87 Commits

Author SHA1 Message Date
5690080a6a Version is set to 0.4.0-rc.1
Some checks reported warnings
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.8) (push) Has been cancelled
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.10) (push) Has been cancelled
2023-11-25 14:21:48 +01:00
f7873ac66b Fixed installation methods
Some checks reported warnings
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.8) (push) Has been cancelled
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.10) (push) Has been cancelled
2023-11-25 13:20:00 +01:00
83ae0999ea Documentation prepared and improved
Some checks reported warnings
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.8) (push) Has been cancelled
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.10) (push) Has been cancelled
2023-11-25 13:16:48 +01:00
3656a040f4 Okay, 1.0.0 was an overkill, module is in alpha
Some checks failed
Tests / test (3.10) (push) Failing after 22m55s
Tests / test (3.11) (push) Failing after 22m56s
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.8) (push) Has been cancelled
2023-11-25 12:23:33 +01:00
414f3966da Attempt to temporarily fix #2
Some checks failed
Tests / test (3.10) (push) Failing after 23m0s
Tests / test (3.11) (push) Failing after 22m55s
Tests / test (3.8) (push) Failing after 22m56s
Tests / test (3.9) (push) Failing after 22m54s
2023-11-24 23:52:50 +01:00
efedb2533b WIP: Automatic tests
Some checks failed
Tests / test (3.10) (push) Failing after 18m31s
Tests / test (3.11) (push) Failing after 16m39s
Tests / test (3.8) (push) Failing after 1m15s
Tests / test (3.9) (push) Failing after 14m41s
2023-11-24 13:35:47 +01:00
059c511e05 Removed Client from classes
Some checks failed
Tests / test (3.10) (push) Failing after 5m26s
Tests / test (3.11) (push) Failing after 5m28s
Tests / test (3.8) (push) Failing after 5m25s
Tests / test (3.9) (push) Failing after 5m23s
2023-11-24 12:44:57 +01:00
c4b7197267 Classes restructure
Some checks failed
Tests / test (3.10) (push) Failing after 1m10s
Tests / test (3.11) (push) Failing after 1m7s
Tests / test (3.8) (push) Failing after 1m11s
Tests / test (3.9) (push) Has been cancelled
2023-11-24 12:39:25 +01:00
3a65991257 This commit breaks everything 2023-11-24 12:37:24 +01:00
7b9367c0a7 Changed imports 2023-11-24 12:35:51 +01:00
f31fa65d78 Small refactor and isort+black formatting
Some checks reported warnings
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.8) (push) Has been cancelled
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.10) (push) Has been cancelled
2023-11-24 11:21:02 +01:00
fa4f7b83ec Drop support for Python 3.7 (due to EOL)
Some checks failed
Tests / test (3.10) (push) Failing after 5m30s
Tests / test (3.11) (push) Failing after 5m33s
Tests / test (3.8) (push) Failing after 5m29s
Tests / test (3.9) (push) Failing after 5m29s
2023-11-19 23:47:41 +01:00
b0b874bfc8 env fix
Some checks failed
Tests / test (3.10) (push) Failing after 5m31s
Tests / test (3.11) (push) Failing after 5m34s
Tests / test (3.7) (push) Failing after 39s
Tests / test (3.8) (push) Failing after 5m53s
Tests / test (3.9) (push) Failing after 5m23s
2023-11-19 23:08:09 +01:00
9733557463 Added a few basic tests 2023-11-19 23:05:48 +01:00
9282578788 Structural changes
Some checks failed
Tests / test (3.10) (push) Failing after 1m10s
Tests / test (3.7) (push) Has been cancelled
Tests / test (3.8) (push) Has been cancelled
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.11) (push) Has been cancelled
2023-11-19 22:38:51 +01:00
eb9a043c34 Probably a fix for #2 2023-11-19 12:19:31 +01:00
819bd5ff40 Add '.renovaterc' 2023-04-21 10:07:48 +03:00
c2e1fc54c1 Updated to 0.3.4 2023-01-04 11:55:06 +01:00
29ebb4627d Merge branch 'master' of https://git.profitroll.eu/profitroll/PythonRMV 2023-01-04 10:35:38 +01:00
6b6299cd0a Added one more check for correct response return 2023-01-04 10:35:33 +01:00
Profitroll
e91846edee Fixed empty boards return 2022-11-13 15:04:00 +01:00
Profitroll
9b6b2d6416 Updated meta to 0.3.3 2022-11-13 15:03:40 +01:00
Profitroll
f8b13ccedf Removed unused import 2022-10-12 17:42:42 +02:00
Profitroll
b47bc51365 Just a bit clarified docstring 2022-10-12 17:42:22 +02:00
Profitroll
f39da9b803 Updated meta to 0.3.2 2022-10-12 17:28:21 +02:00
Profitroll
1b863c55f1 Added retrieve_stops argument 2022-10-12 17:28:09 +02:00
Profitroll
80a788933d Improved README 2022-10-12 17:15:12 +02:00
Profitroll
3599a034dc Typing improved 2022-10-12 17:08:49 +02:00
Profitroll
e09e8f29fb Changed test function argument type 2022-10-08 12:27:13 +02:00
Profitroll
d23d9a005d Some errors ignored 2022-10-08 12:26:48 +02:00
9c9489aee1 Started writing wiki 2022-10-07 15:22:52 +02:00
07925d15eb Removed litter 2022-10-07 14:19:27 +02:00
a13027614e Updated meta to 0.3.1 2022-10-07 14:17:56 +02:00
ece22489ad Improved docs 2022-10-07 14:17:24 +02:00
94472ba945 Fixed the case when stations is None 2022-10-07 13:51:37 +02:00
76774fc9cb Changed Development Status to Alpha 2022-10-07 13:48:52 +02:00
551babedb7 Updated readme to 0.3.0 2022-10-07 13:47:25 +02:00
ed44947277 him_search fully implemented 2022-10-07 13:25:33 +02:00
cd973b2000 Small import change 2022-10-07 11:37:38 +02:00
036a3174f8 Methods overhaul 2022-10-07 11:35:02 +02:00
201fcba766 him_search() WIP 2022-10-06 15:04:03 +02:00
b15da7964c Updated meta to 0.3.0 2022-10-06 14:37:38 +02:00
ea828bc966 trip_recon is now checked in To-Do 2022-10-06 14:36:01 +02:00
3461d82b34 Added list support 2022-10-06 14:35:10 +02:00
0d9ea775a6 Fixed small docstring issues 2022-10-06 14:34:54 +02:00
5613bf7e3f trip_recon made 2022-10-06 14:34:28 +02:00
2a83b34631 Small typo fix 2022-10-06 14:34:13 +02:00
7e0d381523 Board now support messages 2022-10-06 13:17:16 +02:00
a5022011ed Removed unused imports and fixed real_time_mode 2022-10-06 13:04:27 +02:00
23527c85f3 Removed unused imports 2022-10-06 13:04:17 +02:00
3f738f453b Integrated journey_detail 2022-10-06 13:04:00 +02:00
1a82665932 Added journey_detail to completed in To-Do 2022-10-06 13:03:44 +02:00
84feae2d2f Silenced some warnings in VSCode 2022-10-06 12:49:48 +02:00
9da83c878e Docstring added 2022-10-06 12:48:30 +02:00
c08deb9ff2 date and time arguments docstring fixed 2022-10-06 12:47:07 +02:00
fe9d345002 Reduced number of total requests 2022-10-06 12:41:08 +02:00
f06c9ca33e Testing script added 2022-10-06 12:34:50 +02:00
4fd566f7c4 Small docstring added 2022-10-06 12:09:30 +02:00
170b472ca4 Test added 2022-10-06 11:36:32 +02:00
d49196ff26 Message improved 2022-10-06 11:36:18 +02:00
ebb21aea8c Journey added 2022-10-06 11:36:08 +02:00
Profitroll
6d447a64c5 Types Stop and StopTrip are now supported by board 2022-10-05 21:32:25 +02:00
eee76fdff9 Updated meta to 0.2.9 2022-10-05 15:10:09 +02:00
781b202b32 README corrected 2022-10-05 15:08:27 +02:00
7e4cde8762 board_arrival and board_departure made 2022-10-05 15:06:36 +02:00
5c013dd38f boardType fixed 2022-10-05 15:06:08 +02:00
3a23c058c3 Initialized him_search() 2022-10-05 14:19:50 +02:00
4136bbcddb Fixed typing 2022-10-05 14:19:39 +02:00
366497d8fb Added stop_by_id() method 2022-10-05 14:19:05 +02:00
651d709e66 rtMode argument now works flawlessly 2022-10-05 13:51:04 +02:00
93240ffcca Small docstring changes 2022-10-05 13:50:44 +02:00
65349e14b2 Board methods WIP 2022-10-05 13:50:26 +02:00
62cd9feb55 Added Exception for not ready methods 2022-10-05 13:08:43 +02:00
08dafb6459 All the methods init 2022-10-05 13:08:27 +02:00
8e9347f526 New methods initialized 2022-10-05 13:03:16 +02:00
04261e9f3c Updated meta to 0.2.8 2022-10-05 13:02:10 +02:00
6809e3ae9c Fixed arguments 2022-10-05 12:18:04 +02:00
fe3e839abb Classes docstring improved 2022-10-05 12:17:51 +02:00
b069b82cc5 Enums docstring improved 2022-10-05 12:16:25 +02:00
70aa206cba Meta updated to 0.2.7 2022-10-05 10:33:06 +02:00
71597ac658 Updated to 0.2.6 skipping some versions 2022-10-04 15:25:25 +02:00
93779b62a6 Setup's README updated 2022-10-04 15:14:21 +02:00
0719eaacbc Small enum fixes 2022-10-04 14:40:27 +02:00
83af5b33da Improved To-Do 2022-10-04 11:21:51 +02:00
9c93275e59 Optimized imports 2022-10-04 11:21:30 +02:00
7d5454a5df Removed unused imports and fixed docstring 2022-10-04 11:15:53 +02:00
013326d32a Added support for two new raw methods 2022-10-04 11:15:34 +02:00
105 changed files with 2420 additions and 1102 deletions

View File

@@ -0,0 +1,36 @@
name: Tests
on:
push:
branches:
- dev
- main
tags-ignore:
- v*
pull_request:
jobs:
test:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
env:
AGENT_TOOLSDIRECTORY: /opt/hostedtoolcache
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions
- name: Test with tox
env:
RMV_TOKEN: ${{ secrets.RMV_TOKEN }}
run: tox

15
.gitignore vendored
View File

@@ -154,12 +154,9 @@ cython_debug/
# Custom
.pypirc
tests
test.*
test_all.py
build.*
cleanup.*
publish.*
publish-release.*
.vscode
.vscode/
.venv_linux/
.venv_windows/
# Module-related
tests/output/

17
.renovaterc Normal file
View File

@@ -0,0 +1,17 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
],
"packageRules": [
{
"matchUpdateTypes": [
"minor",
"patch",
"pin",
"digest"
],
"automerge": true
}
]
}

View File

@@ -1,73 +1,66 @@
# PythonRMV
<h1 align="center">PythonRMV</h1>
<p align="center">
<a href="https://git.end-play.xyz/profitroll/PythonRMV/src/branch/master/LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-blue"></a>
<a href="https://git.end-play.xyz/profitroll/PythonRMV"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
</p>
Small module that makes your journey with RMV REST API somehow easier. Based fully on official RMV API reference and HAFAS documentation.
# Requirements
## Requirements
* RMV API key (Get it [here](https://opendata.rmv.de/site/start.html))
* Python3 (Tested versions are 3.7.9 and 3.9.13)
* Python 3.8+
* git (Only for installation from source)
# Installation
## Installation
If you have everything listed in [requirements](#requirements), then let's begin.
### Variant 1:
1. `python -m pip install pyrmv`
### Variant 1
### Variant 2:
1. `git clone https://git.end-play.xyz/profitroll/PythonRMV.git`
2. `cd PythonRMV`
3. `python setup.py install`
`python -m pip install pyrmv`
# Usage
### Variant 2
`python -m pip install git+https://git.end-play.xyz/profitroll/PythonRMV.git`
## Usage
```py
import pyrmv
# Set API key
access_id = "Something"
# Define a Client with API key
client = pyrmv.Client("AcessId")
# Get origin's and destination's location
origin = pyrmv.stop_by_name(access_id, "Frankfurt Hauptbahnhof", max_number=3)[0]
destination = pyrmv.stop_by_coords(access_id, 50.099613, 8.685449, max_number=3)[0]
origin = client.stop_by_name("Frankfurt Hauptbahnhof", max_number=3)[0]
destination = client.stop_by_coords(50.099613, 8.685449, max_number=3)[0]
# Find a trip by locations got
trip = pyrmv.trip_find(access_id, origin_id=origin.id, dest_id=destination.id)
# Find a trip by locations you got above
trip = client.trip_find(origin_id=origin.id, dest_id=destination.id)
```
# Frequently Asked Questions
## Frequently Asked Questions
- [Why are there raw versions and formatted ones?](#why-are-there-raw-versions-and-formatted-ones)
- [Some methods work slightly different](#some-methods-work-slightly-different)
- [Documentation is not perfectly clear](#documentation-is-not-perfectly-clear)
* [Why are there raw versions and formatted ones?](#why-are-there-raw-versions-and-formatted-ones)
* [Some methods work slightly different](#some-methods-work-slightly-different)
## Why are there raw versions and formatted ones?
### Why are there raw versions and formatted ones?
For the purposes of my projects I don't really need all the stuff RMV gives (even though it's not much).
I only need some specific things. However I do understand that in some cases other users may find
those methods quite useful so I implemented them as well.
## Some methods work slightly different
### Some methods work slightly different
Can be. Not all function arguments written may work perfectly because I simply did not test each and
every request. Some of arguments may be irrelevant in my use-case and the others are used quite rare at all.
Just [make an issue](https://git.end-play.xyz/profitroll/PythonRMV/issues/new) and I'll implement it correct when I'll have some free time.
## Documentation is not perfectly clear
## To-Do
Of course docs cannot be perfect as a python docstring, especially if sometimes I don't
know how things should correctly work. That's why you get HAFAS API docs in addition to your
RMV API key. Just use my functions together with those docs, if you want to build something
really sophisticated. However I'm not sure whether RMV supports that many HAFAS features publicly.
### General
# To-Do
- [ ] arrivalBoard (board_arrival)
- [ ] departureBoard (board_departure)
- [x] himsearch (him_search)
- [ ] journeyDetail (journey_detail)
- [x] location.nearbystops (stop_by_coords)
- [x] location.name (stop_by_name)
- [x] trip (trip_find)
- [ ] recon (trip_recon)
* [ ] Docs in Wiki
* [ ] Tickets

69
pyproject.toml Normal file
View File

@@ -0,0 +1,69 @@
[build-system]
requires = ["setuptools>=52.0"]
build-backend = "setuptools.build_meta"
[project]
name = "pyrmv"
dynamic = ["version", "dependencies", "optional-dependencies"]
authors = [{ name = "Profitroll", email = "profitroll@end-play.xyz" }]
maintainers = [{ name = "Profitroll", email = "profitroll@end-play.xyz" }]
description = "Small module that makes your journey with RMV REST API somehow easier."
readme = "README.md"
requires-python = ">=3.8"
license = { text = "GPL3" }
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Utilities",
]
[project.urls]
Homepage = "https://git.end-play.xyz/profitroll/PythonRMV"
Source = "https://git.end-play.xyz/profitroll/PythonRMV"
Tracker = "https://git.end-play.xyz/profitroll/PythonRMV/issues"
Documentation = "https://git.end-play.xyz/profitroll/PythonRMV/wiki"
[tool.setuptools.dynamic]
version = { attr = "pyrmv.__version__" }
dependencies = { file = "requirements/_.txt" }
[tool.setuptools.dynamic.optional-dependencies]
dev = { file = "requirements/dev.txt" }
[tool.setuptools.packages.find]
where = ["src"]
[tool.black]
target-version = ['py38', 'py39', 'py310', 'py311']
line-length = 94
[tool.isort]
profile = "black"
[tool.pytest.ini_options]
minversion = "6.0"
python_files = ["test_*.py"]
pythonpath = "."
testpaths = ["tests"]
[tool.mypy]
namespace_packages = true
install_types = true
strict = true
show_error_codes = true
[tool.pylint.main]
extension-pkg-whitelist = ["ujson"]
py-version = 3.8
[tool.coverage.run]
source = ["pyrmv"]

View File

@@ -1,34 +0,0 @@
"""
## PythonRMV
Small module that makes your journey with RMV REST API somehow easier. Based fully on official RMV API reference and HAFAS documentation.
## Usage
```py
import pyrmv
# Set API key
access_id = "Something"
# Get origin's and destination's location
origin = pyrmv.stop_by_name(access_id, "Frankfurt Hauptbahnhof", max_number=3)[0]
destination = pyrmv.stop_by_coords(access_id, 50.099613, 8.685449, max_number=3)[0]
# Find a trip by locations got
trip = pyrmv.trip_find(access_id, origin_id=origin.id, dest_id=destination.id)
```
"""
__name__ = "pyrmv"
__version__ = "0.2.3"
__license__ = "MIT License"
__author__ = "Profitroll"
from . import raw
from . import const
from . import enums
from . import errors
from . import utility
from . import classes
from .methods import *

View File

@@ -1,10 +0,0 @@
from isodate import parse_duration
class Gis():
def __init__(self, ref: str, route: dict):
self.ref = ref
self.dist = route["dist"]
self.duration = parse_duration(route["durS"])
self.geo = route["dirGeo"]

View File

@@ -1,2 +0,0 @@
class Journey():
pass

View File

@@ -1,42 +0,0 @@
from pyrmv.classes.Gis import Gis
from pyrmv.classes.Message import Message
from pyrmv.classes.Stop import StopTrip
from isodate import parse_duration
class Leg():
def __init__(self, data: dict):
self.origin = StopTrip(data["Origin"])
self.destination = StopTrip(data["Destination"])
if "GisRef" in data:
self.gis = Gis(data["GisRef"]["ref"], data["GisRoute"])
else:
self.gis = None
self.index = data["idx"]
self.name = data["name"]
self.type = data["type"]
if "direction" in data:
self.direction = data["direction"]
else:
self.direction = None
self.messages = []
if "Messages" in data:
for message in data["Messages"]["Message"]:
self.messages.append(Message(message))
if "number" in data:
self.number = data["number"]
else:
self.number = None
self.duration = parse_duration(data["duration"])
if "dist" in data:
self.distance = data["dist"]
else:
self.distance = None

View File

@@ -1,6 +0,0 @@
from .product import Product
from .rt_mode import RealTimeMode
from .lang import Language
from .location_type import LocationType
from .selection_mode import SelectionMode
from .filter_mode import FilterMode

View File

@@ -1,32 +0,0 @@
from enum import auto
from .auto_name import AutoName
class LocationType(AutoName):
"""Enumeration used to declare types of location filter."""
S = auto()
"Search for station/stops only"
A = auto()
"Search for addresses only"
P = auto()
"Search for POIs only"
AP = auto()
"Search for addresses and POIs"
SA = auto()
"Search for station/stops and addresses"
SE = auto()
"Search for stations/stops and entrypoints"
SP = auto()
"Search for stations/stops and POIs"
ALL = auto()
"Search in all existing location pools"
SPE = auto()
"Search for stations/stops, POIs and entrypoints"

View File

@@ -1,11 +0,0 @@
from enum import auto
from .auto_name import AutoName
class SelectionMode(AutoName):
"""Enumeration used to declare location selection modes."""
SLCT_A = auto()
"Selectable"
SLCT_N = auto()
"Not selectable"

View File

@@ -1,3 +0,0 @@
from .trip_find import trip_find
from .stop_by_coords import stop_by_coords
from .stop_by_name import stop_by_name

View File

@@ -1,65 +0,0 @@
from typing import List, Union
from pyrmv.classes.Stop import Stop
from pyrmv.enums.location_type import LocationType
from pyrmv.enums.lang import Language
from pyrmv.enums.selection_mode import SelectionMode
from pyrmv.raw.stop_by_coords import stop_by_coords as raw_stop_by_coords
from pyrmv.utility.find_exception import find_exception
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
def stop_by_coords(
access_id: str,
coords_lat: Union[str, float],
coords_lon: Union[str, float],
lang: Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR] = Language.EN,
radius: Union[int, float] = 1000,
max_number: int = 10,
stop_type: Literal[LocationType.S, LocationType.P, LocationType.SP, LocationType.SE, LocationType.SPE] = LocationType.S,
selection_mode: Literal[SelectionMode.SLCT_A, SelectionMode.SLCT_N] = None, # type: ignore
) -> List[Stop]:
"""Method returns a list of stops around a given center coordinate.
The returned results are ordered by their distance to the center coordinate.
More detailed request is available as raw.stop_by_coords(), however returns dict instead of List[Stop].
### Args:
* access_id (`str`): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
* coords_lat (`Union[str, float]`): Latitude of centre coordinate.
* coords_lon (`Union[str, float]`): Longitude of centre coordinate.
* lang (`Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR]`, **optional**): The language of response. Defaults to `Language.EN`.
* radius (`Union[int, float]`, **optional**): Search radius in meter around the given coordinate if any. Defaults to `1000`.
* max_number (`int`, **optional**): Maximum number of returned stops. Defaults to `10`.
* stop_type (`Literal[LocationType.S, LocationType.P, LocationType.SP, LocationType.SE, LocationType.SPE]`, **optional**): Type filter for location types. Defaults to `LocationType.S`.
* selection_mode (`Literal[SelectionMode.SLCT_A, SelectionMode.SLCT_N]`, **optional**): Selection mode for locations. `SelectionMode.SLCT_N`: Not selectable, `SelectionMode.SLCT_A`: Selectable. Defaults to `None`.
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
stops = []
stops_raw = raw_stop_by_coords(
accessId=access_id,
originCoordLat=coords_lat,
originCoordLong=coords_lon,
lang=lang.code,
radius=radius,
maxNo=max_number,
stopType=(stop_type.code).upper(),
locationSelectionMode=(selection_mode.code).upper()
)
find_exception(stops_raw)
for stop in stops_raw["stopLocationOrCoordLocation"]:
if "StopLocation" in stop:
stops.append(Stop(stop["StopLocation"]))
elif "CoordLocation" in stop:
stops.append(Stop(stop["CoordLocation"]))
return stops

View File

@@ -1,79 +0,0 @@
from typing import List, Union
from pyrmv.classes.Stop import Stop
from pyrmv.enums.location_type import LocationType
from pyrmv.enums.lang import Language
from pyrmv.enums.selection_mode import SelectionMode
from pyrmv.enums.filter_mode import FilterMode
from pyrmv.raw.stop_by_name import stop_by_name as raw_stop_by_name
from pyrmv.utility.find_exception import find_exception
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
def stop_by_name(
access_id: str,
query: str,
lang: Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR] = Language.EN,
max_number: int = 10,
stop_type: Literal[LocationType.A, LocationType.ALL, LocationType.AP, LocationType.P, LocationType.S, LocationType.SA, LocationType.SP] = LocationType.ALL,
selection_mode: Literal[SelectionMode.SLCT_A, SelectionMode.SLCT_N] = None, # type: ignore
coord_lat: Union[str, float] = None, # type: ignore
coord_lon: Union[str, float] = None, # type: ignore
radius: Union[int, float] = 1000,
refine_id: str = None, # type: ignore
stations: Union[str, list] = None, # type: ignore
filter_mode: Literal[FilterMode.DIST_PERI, FilterMode.EXCL_PERI, FilterMode.SLCT_PERI] = FilterMode.DIST_PERI
) -> List[Stop]:
"""Method can be used to perform a pattern matching of a user input and to retrieve a list
of possible matches in the journey planner database. Possible matches might be stops/stations,
points of interest and addresses.
More detailed request is available as raw.stop_by_name(), however returns dict instead of List[Stop].
### Args:
* access_id (`str`): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
* query (`str`): Search for that token.
* lang (`Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR]`, **optional**): The language of response. Defaults to `Language.EN`.
* max_number (`int`, **optional**): Maximum number of returned stops. In range 1-1000. Defaults to `10`.
* stop_type (`Literal[LocationType.A, LocationType.ALL, LocationType.AP, LocationType.P, LocationType.S, LocationType.SA, LocationType.SP]`, **optional**): Type filter for location types. Defaults to `LocationType.ALL`.
* selection_mode (`Literal[SelectionMode.SLCT_A, SelectionMode.SLCT_N]`, **optional**): Selection mode for locations. `SelectionMode.SLCT_N`: Not selectable, `SelectionMode.SLCT_A`: Selectable. Defaults to `None`.
* coord_lat (`Union[str, float]`, **optional**): Latitude of centre coordinate. Defaults to `None`.
* coord_lon (`Union[str, float]`, **optional**): Longitude of centre coordinate. Defaults to `None`.
* radius (`Union[int, float]`, **optional**): Search radius in meter around the given coordinate if any. Defaults to `1000`.
* refine_id (`str`, **optional**): In case of an refinable location, this value takes the ID of the refinable one of a previous result. Defaults to `None`.
* stations (`Union[str, list]`, **optional**): Filter for stations. Matches if the given value is prefix of any station in the itinerary. As a list or as a string separated by comma. Defaults to `None`.
* filter_mode (`Literal[FilterMode.DIST_PERI, FilterMode.EXCL_PERI, FilterMode.SLCT_PERI]`, **optional**): Filter modes for nearby searches. Defaults to `FilterMode.DIST_PERI`.
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
stops = []
stops_raw = raw_stop_by_name(
accessId=access_id,
inputString=query,
lang=lang.code,
maxNo=max_number,
stopType=(stop_type.code).upper(),
locationSelectionMode=(selection_mode.code).upper(),
coordLat=coord_lat,
coordLong=coord_lon,
radius=radius,
refineId=refine_id,
stations=stations,
filterMode=filter_mode.code
)
find_exception(stops_raw)
for stop in stops_raw["stopLocationOrCoordLocation"]:
if "StopLocation" in stop:
stops.append(Stop(stop["StopLocation"]))
elif "CoordLocation" in stop:
stops.append(Stop(stop["CoordLocation"]))
return stops

View File

@@ -1,200 +0,0 @@
from datetime import datetime
from typing import List, Union
from pyrmv.classes.Trip import Trip
from pyrmv.raw.trip_find import trip_find as raw_trip_find
from pyrmv.enums.rt_mode import RealTimeMode
from pyrmv.enums.lang import Language
from pyrmv.utility.find_exception import find_exception
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
def trip_find(
access_id: str,
lang: Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR] = Language.EN,
origin_id: str = None, # type: ignore
origin_id_ext: str = None, # type: ignore
origin_coord_lat: Union[str, float] = None, # type: ignore
origin_coord_lon: Union[str, float] = None, # type: ignore
origin_coord_name: str = None, # type: ignore
destination_id: str = None, # type: ignore
destination_id_ext: str = None, # type: ignore
destination_coord_lat: Union[str, float] = None, # type: ignore
destination_coord_lon: Union[str, float] = None, # type: ignore
destination_coord_name: str = None, # type: ignore
via: str = None, # type: ignore
via_id: str = None, # type: ignore
via_gis: str = None, # type: ignore
via_wait_time: int = 0,
avoid: str = None, # type: ignore
avoid_id: str = None, # type: ignore
change_time_percent: int = 100,
change_time_min: int = None, # type: ignore
change_time_max: int = None, # type: ignore
change_time_add: int = None, # type: ignore
change_max: int = None, # type: ignore
date: Union[str, datetime] = None, # type: ignore
time: Union[str, datetime] = None, # type: ignore
search_arrival: bool = False,
trips_after_time: int = None, # type: ignore
trips_before_time: int = None, # type: ignore
context: str = None, # type: ignore
passlist: bool = False,
operators: Union[str, list] = None, # type: ignore
lines: Union[str, list] = None, # type: ignore
lineids: Union[str, list] = None, # type: ignore
iv_include: bool = False,
iv_only: bool = False,
bike_carriage: bool = False,
passing_points: bool = False,
real_time_mode: Literal[RealTimeMode.FULL, RealTimeMode.INFOS, RealTimeMode.OFF, RealTimeMode.REALTIME, RealTimeMode.SERVER_DEFAULT] = None, # type: ignore
include_earlier: bool = False,
ict_alternatives: bool = False,
tariff: bool = None, # type: ignore
messages: bool = False,
frequency: bool = True
) -> List[Trip]:
"""The trip service calculates a trip from a specified origin to a specified destination. These might be
stop/station IDs or coordinates based on addresses and points of interest validated by the location service or
coordinates freely defined by the client.
More detailed request is available as raw.trip_find(), however returns dict instead of List[Trip].
### Args:
* access_id (`str`): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
* lang (`Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR]`, **optional**): The language of response. Defaults to `Language.EN`.
* origin_id (`str`, **optional**): Specifies the station/stop ID of the origin for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* origin_id_ext (`str`, **optional**): Deprecated. Please use originId as it supports external IDs. Specifies the external station/stop ID of the origin for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* origin_coord_lat (`Union[str, float]`, **optional**): Latitude of station/stop coordinate of the trip's origin. The coordinate can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* origin_coord_lon (`Union[str, float]`, **optional**): Longitude of station/stop coordinate of the trip's origin. The coordinate can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* origin_coord_name (`str`, **optional**): Name of the trip's origin if coordinate cannot be resolved to an address or poi. Defaults to `None`.
* destination_id (`str`, **optional**): Specifies the station/stop ID of the destination for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* destination_id_ext (`str`, **optional**): Deprecated. Please use destId as it supports external IDs. Specifies the external station/stop ID of the destination for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* destination_coord_lat (`Union[str, float]`, **optional**): Latitude of station/stop coordinate of the trip's destination. The coordinate can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* destination_coord_lon (`Union[str, float]`, **optional**): Longitude of station/stop coordinate of the trip's destination. The coordinate can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* destination_coord_name (`str`, **optional**): Name of the trip's destination if coordinate cannot be resolved to an address or poi. Defaults to `None`.
* via (`str`, **optional**): Complex structure to provide multiple via points separated by semicolon. This structure is build like this: `viaId|waittime|viastatus|products|direct|sleepingCar|couchetteCoach|attributes`. Read more about this in HAFAS ReST Documentation. Defaults to `None`.
* via_id (`str`, **optional**): ID of a station/stop used as a via for the trip. Specifying a via station forces the trip search to look for trips which must pass through this station. Such ID can be retrieved from stop_by_name() or stop_by_coords(). If `via` is used, `via_id` and `via_wait_time ` are having no effect. Defaults to `None`.
* via_gis (`str`, **optional**): Complex structure to provide multiple GIS via locations separated by semicolon. This structure is build like this: `locationId|locationMode|transportMode|placeType|usageType|mode|durationOfStay`. Read more about this in HAFAS ReST Documentation. Defaults to `None`.
* via_wait_time (`int`, **optional**): Defines the waiting time spent at via station in minutes. If `via` is used, `via_id` and `via_wait_time` are having no effect. Defaults to 0.
* avoid (`str`, **optional**): Complex structure to provide multiple points to be avoided separated by semicolon. This structure is build like this: `avoidId|avoidstatus` avoidId: id, extId or altId of the avoid, mandatory avoidstatus: one of NPAVM (do not run through if this is a meta station), NPAVO (do not run through), NCAVM (do not change if this is a meta station), NCAVO (do not change), optional but defaults to NCAVM Example: Just define three avoids by extId: `avoid="801234;801235;801236"`. Defaults to `None`.
* avoid_id (`str`, **optional**): ID of a station/stop to be avoided as transfer stop for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). If `avoid` is used, `avoid_id` has no effect. Defaults to `None`.
* change_time_percent (`int`, **optional**): Configures the walking speed when changing from one leg of the journey to the next one. It extends the time required for changes by a specified percentage. A value of 200 doubles the change time as initially calculated by the system. In the response, change time is presented in full minutes. If the calculation based on changeTime-Percent does not result in a full minute, it is rounded using "round half up" method. Defaults to `100`.
* change_time_min (`int`, **optional**): Minimum change time at stop in minutes. Defaults to `None`.
* change_time_max (`int`, **optional**): Maximum change time at stop in minutes. Defaults to `None`.
* change_time_add (`int`, **optional**): This amount of minutes is added to the change time at each stop. Defaults to `None`.
* change_max (`int`, **optional**): Maximum number of changes. In range 0-11. Defaults to `None`.
* date (`str`, **optional**): Sets the start date for which the departures shall be retrieved. Represented in the format `YYYY-MM-DD`. By default the current server date is used. Defaults to `None`.
* time (`str`, **optional**): Sets the start time for which the departures shall be retrieved. Represented in the format `hh:mm[:ss]` in 24h nomenclature. Seconds will be ignored for requests. By default the current server time is used. Defaults to `None`.
* search_arrival (`bool`, **optional**): If set, the date and time parameters specify the arrival time for the trip search instead of the departure time. Defaults to `False`.
* trips_after_time (`int`, **optional**): Minimum number of trips after the search time. Sum of `trips_after_time` and `trips_before_time` has to be less or equal 6. Read more about this in HAFAS ReST Documentation. In range 1-6. Defaults to `None`.
* trips_before_time (`int`, **optional**): Minimum number of trips before the search time. Sum of `trips_after_time` and `trips_before_time` has to be less or equal 6. Read more about this in HAFAS ReST Documentation. In range 0-6. Defaults to `None`.
* context (`str`, **optional**): Defines the starting point for the scroll back or forth operation. Use the scrB value from a previous result to scroll backwards in time and use the scrF value to scroll forth. Defaults to `None`.
* passlist (`bool`, **optional**): Enables/disables the return of the passlist for each leg of the trip. Defaults to `False`.
* operators (`Union[str, list]`, **optional**): Only trips provided by the given operators are part of the result. If the operator should not be part of the be trip, negate it by putting ! in front of it. Example: Filter for operator A and B: `operators=["A","B"]`. Defaults to `None`.
* lines (`Union[str, list]`, **optional**): Only journeys running the given line are part of the result. If the line should not be part of the be trip, negate it by putting ! in front of it. Defaults to `None`.
* lineids (`Union[str, list]`, **optional**): Only journeys running the given line (identified by its line ID) are part of the result. If the line should not be part of the be trip, negate it by putting ! in front of it. Defaults to `None`.
* iv_include (`bool`, **optional**): Enables/disables search for individual transport routes. Defaults to `False`.
* iv_only (`bool`, **optional**): Enables/disables search for individual transport routes only. Defaults to `False`.
* bike_carriage (`bool`, **optional**): Enables/disables search for trips explicit allowing bike carriage. This will only work in combination with `change_max=0` as those trips are always meant to be direct connections. Defaults to `False`.
* passing_points (`bool`, **optional**): Enables/disables the return of stops having no alighting and boarding in its passlist for each leg of the trip. Needs passlist enabled. Defaults to `False`.
* real_time_mode (`Literal[RealTimeMode.FULL, RealTimeMode.INFOS, RealTimeMode.OFF, RealTimeMode.REALTIME, RealTimeMode.SERVER_DEFAULT]`, **optional**): Set the realtime mode to be used. Read more about this in HAFAS ReST Documentation. Defaults to `None`.
* include_earlier (`bool`, **optional**): Disables search optimization in relation of duration. Defaults to `False`.
* ict_alternatives (`bool`, **optional**): Enables/disables the search for alternatives with individualized change times (ICT). Defaults to `False`.
* tariff (`bool`, **optional**): Enables/disables the output of tariff data. The default is configurable via provisioning. Defaults to `None`.
* messages (`bool`, **optional**): Enables/disables the output of traffic messages. The default is configurable via provisioning. Defaults to `False`.
* frequency (`bool`, **optional**): Enables/disables the calculation of frequency information. Defaults to `True`.
### Returns:
* List[Trip]: List of Trip objects. Empty list if none found.
"""
trips = []
trips_raw = raw_trip_find(
accessId=access_id,
lang=lang.code,
originId=origin_id,
originExtId=origin_id_ext,
originCoordLat=origin_coord_lat,
originCoordLong=origin_coord_lon,
originCoordName=origin_coord_name,
destId=destination_id,
destExtId=destination_id_ext,
destCoordLat=destination_coord_lat,
destCoordLong=destination_coord_lon,
destCoordName=destination_coord_name,
via=via,
viaId=via_id,
viaGis=via_gis,
viaWaitTime=via_wait_time,
avoid=avoid,
avoidId=avoid_id,
changeTimePercent=change_time_percent,
minChangeTime=change_time_min,
maxChangeTime=change_time_max,
addChangeTime=change_time_add,
maxChange=change_max,
date=date,
time=time,
searchForArrival=search_arrival,
numF=trips_after_time,
numB=trips_before_time,
context=context,
passlist=passlist,
operators=operators,
lines=lines,
lineids=lineids,
includeIv=iv_include,
ivOnly=iv_only,
bikeCarriage=bike_carriage,
showPassingPoints=passing_points,
rtMode=(real_time_mode.code).upper(),
includeEarlier=include_earlier,
withICTAlternatives=ict_alternatives,
tariff=tariff,
trafficMessages=messages,
withFreq=frequency
)
find_exception(trips_raw)
for trip in trips_raw["Trip"]:
trips.append(Trip(trip))
return trips

View File

@@ -1,36 +0,0 @@
from requests import get
from typing import List, Union
from xmltodict import parse as xmlparse
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
# 2.26. Journey Detail (journeyDetail)
def journey_detail(accessId: str,
json: bool = True
) -> dict:
if json:
headers = {"Accept": "application/json"}
else:
headers = {"Accept": "application/xml"}
payload = {}
for var, val in locals().items():
if str(var) not in ["json", "headers", "payload"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/journeyDetail", params=payload, headers=headers)
# Exceptions checker moved to normal methods
# and exceptions will no longer raise in raw ones.
# find_exception(output.json())
if json:
return output.json()
else:
return xmlparse(output.content)

View File

@@ -1,38 +0,0 @@
from requests import get
from typing import List, Union
from xmltodict import parse as xmlparse
from pyrmv.utility.find_exception import find_exception
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
# 2.17. Reconstruction (recon)
def trip_recon(accessId: str,
json: bool = True
) -> dict:
if json:
headers = {"Accept": "application/json"}
else:
headers = {"Accept": "application/xml"}
payload = {}
for var, val in locals().items():
if str(var) not in ["json", "headers", "payload"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/recon", params=payload, headers=headers)
# Exceptions checker moved to normal methods
# and exceptions will no longer raise in raw ones.
# find_exception(output.json())
if json:
return output.json()
else:
return xmlparse(output.content)

View File

@@ -1,3 +0,0 @@
requests
xmltodict
isodate

3
requirements/_.txt Normal file
View File

@@ -0,0 +1,3 @@
requests~=2.31.0
xmltodict~=0.13.0
isodate~=0.6.1

12
requirements/dev.txt Normal file
View File

@@ -0,0 +1,12 @@
black==23.11.0
build==1.0.3
isort==5.12.0
mypy==1.7.0
pylint==3.0.2
pytest-asyncio==0.22.0
pytest-cov==4.1.0
pytest==7.4.3
tox==4.11.3
twine==4.0.2
types-aiofiles==23.2.0.0
types-ujson==5.8.0.1

View File

@@ -1,3 +0,0 @@
[metadata]
description_file=README.md
license_files=LICENSE

View File

@@ -1,40 +0,0 @@
from setuptools import setup
setup(
name="pyrmv",
version="0.2.3",
author="Profitroll",
description="Small module that makes your journey with RMV REST API somehow easier.",
long_description="## PythonRMV\n\nSmall module that makes your journey with RMV REST API somehow easier. Based fully on official RMV API reference and HAFAS documentation.\n\n## Usage\n\n```py\nimport pyrmv\n\n# Set API key\naccess_id = \"Something\"\n\n# Get origin's and destination's location\norigin = pyrmv.stop_by_name(access_id, \"Frankfurt Hauptbahnhof\", max_number=3)[0]\ndestination = pyrmv.stop_by_coords(access_id, 50.099613, 8.685449, max_number=3)[0]\n\n## Find a trip by locations got\ntrip = pyrmv.trip_find(access_id, origin_id=origin.id, destination_id=destination.id)\n```\n\n## Frequently Asked Questions\n\n- Why are there raw versions and formatted ones?\n- Some methods work slightly different\n- Documentation is not perfectly clear\n\n### Why are there raw versions and formatted ones?\n\nFor the purposes of my projects I don't really need all the stuff RMV gives (even though it's not much).\nI only need some specific things. However I do understand that in some cases other users may find\nthose methods quite useful so I implemented them as well.\n\n\n### Some methods work slightly different\n\nCan be. Not all function arguments written may work perfectly because I simply did not test each and\nevery request. Some of arguments may be irrelevant in my use-case and the others are used quite rare at all.\nJust [make an issue](https://git.end-play.xyz/profitroll/PythonRMV/issues/new) and I'll implement it correct when I'll have some free time.\n\n### Documentation is not perfectly clear\n\nOf course docs cannot be perfect as a python docstring, especially if sometimes I don't\nknow how things should correctly work. That's why you get HAFAS API docs in addition to your\nRMV API key. Just use my functions together with those docs, if you want to build something\nreally sophisticated. However I'm not sure whether RMV supports that many HAFAS features publicly.\n\n## To-Do\n- [ ] arrivalBoard (board_arrival) \n- [ ] departureBoard (board_departure) \n- [x] himsearch (him_search) \n- [ ] journeyDetail (journey_detail)\n- [x] location.nearbystops (stop_by_coords) \n- [x] location.name (stop_by_name) \n- [x] trip (trip_find) \n- [ ] recon (trip_recon)",
long_description_content_type="text/markdown",
author_email="profitroll@end-play.xyz",
url="https://git.end-play.xyz/profitroll/PythonRMV",
project_urls={
"Bug Tracker": "https://git.end-play.xyz/profitroll/PythonRMV/issues",
"Documentation": "https://git.end-play.xyz/profitroll/PythonRMV/wiki",
"Source Code": "https://git.end-play.xyz/profitroll/PythonRMV.git",
},
packages=[
"pyrmv",
"pyrmv.raw",
"pyrmv.const",
"pyrmv.errors",
"pyrmv.methods",
"pyrmv.utility",
"pyrmv.classes"
],
install_requires=[
"requests",
"xmltodict",
"isodate"
],
classifiers=[
"Development Status :: 2 - Pre-Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Utilities"
]
)

29
src/pyrmv/__init__.py Normal file
View File

@@ -0,0 +1,29 @@
"""
## PythonRMV
Small module that makes your journey with RMV REST API somehow easier. Based fully on official RMV API reference and HAFAS documentation.
## Usage
```py
import pyrmv
# Define a Client with API key
client = pyrmv.Client("AcessId")
# Get origin's and destination's location
origin = client.stop_by_name("Frankfurt Hauptbahnhof", max_number=3)[0]
destination = client.stop_by_coords(50.099613, 8.685449, max_number=3)[0]
# Find a trip by locations got
trip = client.trip_find(origin_id=origin.id, dest_id=destination.id)
```
"""
__name__ = "pyrmv"
__version__ = "0.4.0-rc.1"
__license__ = "MIT License"
__author__ = "Profitroll"
from . import classes, const, enums, errors, raw, utility
from .classes.client import Client

View File

@@ -0,0 +1,8 @@
from .board import BoardArrival, BoardDeparture, LineArrival, LineDeparture
from .gis import Gis
from .journey import Journey
from .leg import Leg
from .message import Channel, Message, Url
from .stop import Stop, StopTrip
from .ticket import Ticket
from .trip import Trip

106
src/pyrmv/classes/board.py Normal file
View File

@@ -0,0 +1,106 @@
from datetime import datetime
from typing import Any, Mapping
from pyrmv.classes.message import Message
from pyrmv.utility import ref_upgrade
class LineArrival:
def __init__(self, data: Mapping[str, Any], client, retrieve_stops: bool = True):
# Upgrade is temporarily used due to RMV API mismatch
# self.journey = client.journey_detail(data["JourneyDetailRef"]["ref"])
self.journey = client.journey_detail(ref_upgrade(data["JourneyDetailRef"]["ref"]))
self.status = data["JourneyStatus"]
self.messages = []
self.name = data["name"]
self.type = data["type"]
self.stop_name = data["stop"]
self.stop_id = data["stopid"]
self.stop_id_ext = data["stopExtId"]
self.stop = client.stop_by_id(self.stop_id) if retrieve_stops else None
self.stop = client.stop_by_id(self.stop_id)
self.time = datetime.strptime(data["time"], "%H:%M:%S")
self.date = datetime.strptime(data["date"], "%Y-%m-%d")
self.reachable = data["reachable"]
self.origin = data["origin"]
self.origin = data["origin"]
if "Messages" in data:
self.messages.extend(Message(message) for message in data["Messages"]["Message"])
if ("rtTime" in data) and ("rtDate" in data):
self.time_real_time = datetime.strptime(data["rtTime"], "%H:%M:%S")
self.date_real_time = datetime.strptime(data["rtDate"], "%Y-%m-%d")
else:
self.time_real_time = None
self.date_real_time = None
def __str__(self) -> str:
return (
f"{self.name} coming from {self.origin} at {self.time.time()} {self.date.date()}"
)
class LineDeparture:
def __init__(self, data: Mapping[str, Any], client, retrieve_stops: bool = True):
# Upgrade is temporarily used due to RMV API mismatch
# self.journey = client.journey_detail(data["JourneyDetailRef"]["ref"])
self.journey = client.journey_detail(ref_upgrade(data["JourneyDetailRef"]["ref"]))
self.status = data["JourneyStatus"]
self.messages = []
self.name = data["name"]
self.type = data["type"]
self.stop_name = data["stop"]
self.stop_id = data["stopid"]
self.stop_id_ext = data["stopExtId"]
self.stop = client.stop_by_id(self.stop_id) if retrieve_stops else None
self.time = datetime.strptime(data["time"], "%H:%M:%S")
self.date = datetime.strptime(data["date"], "%Y-%m-%d")
self.reachable = data["reachable"]
self.direction = data["direction"]
self.direction_flag = data["directionFlag"]
if "Messages" in data:
self.messages.extend(Message(message) for message in data["Messages"]["Message"])
if ("rtTime" in data) and ("rtDate" in data):
self.time_real_time = datetime.strptime(data["rtTime"], "%H:%M:%S")
self.date_real_time = datetime.strptime(data["rtDate"], "%Y-%m-%d")
else:
self.time_real_time = None
self.date_real_time = None
def __str__(self) -> str:
return (
f"{self.name} heading {self.direction} at {self.time.time()} {self.date.date()}"
)
class BoardArrival(list):
def __init__(self, data: Mapping[str, Any], client, retrieve_stops: bool = True):
super().__init__([])
if "Arrival" not in data:
return
for line in data["Arrival"]:
self.append(LineArrival(line, client, retrieve_stops=retrieve_stops))
def __str__(self) -> str:
return "Arrival board\n" + "\n".join([str(line) for line in self])
class BoardDeparture(list):
def __init__(self, data: Mapping[str, Any], client, retrieve_stops: bool = True):
super().__init__([])
if "Departure" not in data:
return
for line in data["Departure"]:
self.append(LineDeparture(line, client, retrieve_stops=retrieve_stops))
def __str__(self) -> str:
return "Departure board\n" + "\n".join([str(line) for line in self])

858
src/pyrmv/classes/client.py Normal file
View File

@@ -0,0 +1,858 @@
from datetime import datetime, timedelta
from typing import List, OrderedDict, Union
from pyrmv.classes import (
BoardArrival,
BoardDeparture,
Journey,
Message,
Stop,
StopTrip,
Trip,
)
from pyrmv.enums import *
from pyrmv.raw import board_arrival as raw_board_arrival
from pyrmv.raw import board_departure as raw_board_departure
from pyrmv.raw import him_search as raw_him_search
from pyrmv.raw import journey_detail as raw_journey_detail
from pyrmv.raw import stop_by_coords as raw_stop_by_coords
from pyrmv.raw import stop_by_name as raw_stop_by_name
from pyrmv.raw import trip_find as raw_trip_find
from pyrmv.raw import trip_recon as raw_trip_recon
from pyrmv.utility import find_exception
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
class Client:
"""The main class in the whole module. Is used to use all non-raw methods.
More detailed docs for each method can be found by using IDE's docstring
highlighting system or in project's wiki ([can be found here](https://git.end-play.xyz/profitroll/PythonRMV/wiki))
### Args:
* access_id (`str`): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
### Methods:
* board_arrival -> BoardArrival
* board_departure -> BoardDeparture
* him_search -> List[Message]
* journey_detail -> Journey
* stop_by_coords -> List[Stop]
* stop_by_id -> Union[Stop, None]
* stop_by_name -> List[Stop]
* trip_find -> List[Trip]
* trip_recon -> List[Trip]
### Examples:
```py
import pyrmv
from datetime import datetime, timedelta
# Create client object with you API key
client = pyrmv.Client("YourAccessId")
# Get arrival and departure boards for station "Frankfurt (Main) Taunusanlage"
board_arrival = client.board_arrival("A=1@O=Frankfurt (Main) Taunusanlage@X=8668765@Y=50113478@U=80@L=3000011@", journeys_max=5)
board_departure = client.board_departure("A=1@O=Frankfurt (Main) Taunusanlage@X=8668765@Y=50113478@U=80@L=3000011@", journeys_max=5)
# Search for HIM messages for S9
messages = client.him_search(date_end=datetime.now()+timedelta(days=10), priority_min=2, train_names=["S9"])
# Get detailed journey of Bus 101
journey = client.journey_detail("2|#VN#1#ST#1664906549#PI#0#ZI#12709#TA#0#DA#61022#1S#3008007#1T#1248#LS#3008043#LT#1323#PU#80#RT#1#CA#1aE#ZE#101#ZB#Bus 101 #PC#6#FR#3008007#FT#1248#TO#3008043#TT#1323#", real_time_mode=pyrmv.enums.RealTimeMode.FULL)
# Look for stops using all possible methods
stop_by_coords client.stop_by_coords(50.131140, 8.733362, radius=300, max_number=3)
stop_by_id = client.stop_by_id("A=1@O=Offenbach (Main)-Zentrum Marktplatz/Frankf. Straße@X=8764456@Y=50105181@U=80@L=3002510@")
stop_by_name = client.stop_by_name("Groß Karben", max_number=3)
# Find a trip and reconstruct it
trip = client.trip_find(origin_coord_lat="50.084659", origin_coord_lon="8.785948", destination_coord_lat=50.1233048, destination_coord_lon=8.6129742, messages=True)[0]
trip_recon = client.trip_recon(trip)[0]
```
"""
def __init__(self, access_id: str) -> None:
self.access_id = access_id
def board_arrival(
self,
id: Union[str, None] = None,
id_ext: Union[str, None] = None,
direction: Union[str, Stop, StopTrip, None] = None,
date: Union[str, datetime, None] = None,
time: Union[str, datetime, None] = None,
duration: Union[int, timedelta] = 60,
journeys_max: int = -1,
operators: Union[str, list, None] = None,
lines: Union[str, list, None] = None,
passlist: bool = False,
board_type: Literal[
BoardArrivalType.ARR,
BoardArrivalType.ARR_EQUIVS,
BoardArrivalType.ARR_MAST,
BoardArrivalType.ARR_STATION,
] = BoardArrivalType.ARR,
retrieve_stops: bool = True,
) -> BoardArrival:
"""Method returns a board with arriving transport.
More detailed request is available as `raw.board_arrival()`, however returns `dict` instead of `Board`.
### Args:
* id (`str`, **optional**): Specifies the station/stop ID. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* id_ext (`str`, **optional**): Deprecated. Please use `id` as it supports external IDs. Specifies the external station/stop ID. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* direction (`Union[str, Stop, StopTrip]`, **optional**): If only vehicles departing or arriving from a certain direction shall be returned, specify the direction by giving the station/stop ID of the last stop on the journey or the Stop object itself. Defaults to `None`.
* date (`Union[str, datetime]`, **optional**): Sets the start date for which the departures shall be retrieved. Represented in the format YYYY-MM-DD or as a datetime object. By default the current server date is used. Defaults to `None`.
* time (`Union[str, datetime]`, **optional**): Sets the start time for which the departures shall be retrieved. Represented in the format hh:mm[:ss] in 24h nomenclature or as a datetime object. Seconds will be ignored for requests. By default the current server time is used. Defaults to `None`.
* duration (`Union[int, timedelta]`, **optional**): Set the interval size in minutes. Can also be provided as a timedelta. Defaults to `60`.
* journeys_max (`int`, **optional**): Maximum number of journeys to be returned. If no value is defined or -1, all departing/arriving services within the duration sized period are returned. Defaults to `-1`.
* operators (`Union[str, list]`, **optional**): Only journeys provided by the given operators are part of the result. To filter multiple operators, separate the codes by comma or provide a list. If the operator should not be part of the be trip, negate it by putting ! in front of it. Example: Filter for operator A and B: `operators=[A,B]`. Defaults to `None`.
* lines (`Union[str, list]`, **optional**): Only journeys running the given line are part of the result. To filter multiple lines, provide a list or separate the codes by comma or provide a list. If the line should not be part of the be trip, negate it by putting ! in front of it. Defaults to `None`.
* passlist (`bool`, **optional**): Include a list of all passed waystops. Defaults to `False`.
* board_type (`Union[BoardArrivalType.ARR, BoardArrivalType.ARR_EQUIVS, BoardArrivalType.ARR_MAST, BoardArrivalType.ARR_STATION]`, optional): Set the station arrival board type to be used. Defaults to `BoardArrivalType.ARR`.
* retrieve_stops (`bool`, **optional**): Whether the stops should be retrieved as a `Stop` objects. Using `False` will drastically increase processing speed and decrease number of requests made (good for low access_key rate limit). Defaults to `True`.
### Returns:
* BoardArrival: Instance of `BoardArrival` object.
"""
if isinstance(direction, (Stop, StopTrip)):
direction = direction.id
board_raw = raw_board_arrival(
accessId=self.access_id,
id=id,
extId=id_ext,
direction=direction, # type: ignore
date=date,
time=time,
duration=duration,
maxJourneys=journeys_max,
operators=operators,
lines=lines,
passlist=passlist,
boardType=board_type.code,
)
find_exception(board_raw)
return BoardArrival(board_raw, self, retrieve_stops=retrieve_stops)
def board_departure(
self,
id: Union[str, None] = None,
id_ext: Union[str, None] = None,
direction: Union[str, Stop, StopTrip, None] = None,
date: Union[str, datetime, None] = None,
time: Union[str, datetime, None] = None,
duration: Union[int, timedelta] = 60,
journeys_max: int = -1,
operators: Union[str, list, None] = None,
lines: Union[str, list, None] = None,
passlist: bool = False,
board_type: Literal[
BoardDepartureType.DEP,
BoardDepartureType.DEP_EQUIVS,
BoardDepartureType.DEP_MAST,
BoardDepartureType.DEP_STATION,
] = BoardDepartureType.DEP,
retrieve_stops: bool = True,
) -> BoardDeparture:
"""Method returns a board with departing transport.
More detailed request is available as `raw.board_departure()`, however returns `dict` instead of `Board`.
### Args:
* id (`str`, **optional**): Specifies the station/stop ID. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* id_ext (`str`, **optional**): Deprecated. Please use `id` as it supports external IDs. Specifies the external station/stop ID. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* direction (`Union[str, Stop, StopTrip]`, **optional**): If only vehicles departing or arriving from a certain direction shall be returned, specify the direction by giving the station/stop ID of the last stop on the journey or the Stop object itself. Defaults to `None`.
* date (`Union[str, datetime]`, **optional**): Sets the start date for which the departures shall be retrieved. Represented in the format YYYY-MM-DD or as a datetime object. By default the current server date is used. Defaults to `None`.
* time (`Union[str, datetime]`, **optional**): Sets the start time for which the departures shall be retrieved. Represented in the format hh:mm[:ss] in 24h nomenclature or as a datetime object. Seconds will be ignored for requests. By default the current server time is used. Defaults to `None`.
* duration (`Union[int, timedelta]`, **optional**): Set the interval size in minutes. Can also be provided as a timedelta. Defaults to `60`.
* journeys_max (`int`, **optional**): Maximum number of journeys to be returned. If no value is defined or -1, all departing/arriving services within the duration sized period are returned. Defaults to `-1`.
* operators (`Union[str, list]`, **optional**): Only journeys provided by the given operators are part of the result. To filter multiple operators, separate the codes by comma or provide a list. If the operator should not be part of the be trip, negate it by putting ! in front of it. Example: Filter for operator A and B: `operators=[A,B]`. Defaults to `None`.
* lines (`Union[str, list]`, **optional**): Only journeys running the given line are part of the result. To filter multiple lines, provide a list or separate the codes by comma or provide a list. If the line should not be part of the be trip, negate it by putting ! in front of it. Defaults to `None`.
* passlist (`bool`, **optional**): Include a list of all passed waystops. Defaults to `False`.
* board_type (`Union[BoardDepartureType.DEP, BoardDepartureType.DEP_EQUIVS, BoardDepartureType.DEP_MAST, BoardDepartureType.DEP_STATION]`, optional): Set the station departure board type to be used. Defaults to `BoardDepartureType.DEP`.
* retrieve_stops (`bool`, **optional**): Whether the stops should be retrieved as a `Stop` objects. Using `False` will drastically increase processing speed and decrease number of requests made (good for low access_key rate limit). Defaults to `True`.
### Returns:
* BoardDeparture: Instance of `BoardDeparture` object.
"""
if isinstance(direction, (Stop, StopTrip)):
direction = direction.id
board_raw = raw_board_departure(
accessId=self.access_id,
id=id,
extId=id_ext,
direction=direction, # type: ignore
date=date,
time=time,
duration=duration,
maxJourneys=journeys_max,
operators=operators,
lines=lines,
passlist=passlist,
boardType=board_type.code,
)
find_exception(board_raw)
return BoardDeparture(board_raw, self, retrieve_stops=retrieve_stops)
def him_search(
self,
date_begin: Union[str, datetime, None] = None,
date_end: Union[str, datetime, None] = None,
time_begin: Union[str, datetime, None] = None,
time_end: Union[str, datetime, None] = None,
weekdays: Union[str, OrderedDict[str, bool], None] = None,
ids: Union[list, None] = None,
operators: Union[list, None] = None,
categories: Union[list, None] = None,
channels: Union[list, None] = None,
companies: Union[list, None] = None,
lines: Union[list, None] = None,
line_ids: Union[list, None] = None,
stations: Union[list, List[Stop], None] = None,
station_from: Union[str, Stop, None] = None,
station_to: Union[str, Stop, None] = None,
both_ways: Union[bool, None] = None,
train_names: Union[list, None] = None,
search_mode: Union[
Literal[SearchMode.MATCH, SearchMode.NOMATCH, SearchMode.TFMATCH], None
] = None,
affected_journey_mode: Union[
Literal[AffectedJourneyMode.ALL, AffectedJourneyMode.OFF], None
] = None,
affected_journey_stop_mode: Union[
Literal[
AffectedJourneyStopMode.ALL,
AffectedJourneyStopMode.IMP,
AffectedJourneyStopMode.OFF,
],
None,
] = None,
priority_min: Union[int, None] = None,
priority_max: Union[int, None] = None,
) -> List[Message]:
"""The him_search method will deliver a list of HIM messages if matched by the given criteria as
well as affected products if any.
More detailed request is available as `raw.him_search()`, however returns `dict` instead of `List[Message]`.
### Args:
* date_begin (`Union[str, datetime]`, optional): Sets the event period start date. Defaults to `None`.
* date_end (`Union[str, datetime]`, optional): Sets the event period end date. Defaults to `None`.
* time_begin (`Union[str, datetime]`, optional): Sets the event period start time. Defaults to `None`.
* time_end (`Union[str, datetime]`, optional): Sets the event period end time. Defaults to `None`.
* weekdays (`Union[str, OrderedDict[str, bool]]`, optional): Bitmask or an OrderedDict for validity of HIM messages based on weekdays. OrderedDict must be formatted as follows: `OrderedDict(Monday=bool, Tuesday=bool, Wednesday=bool, Thursday=bool, Friday=bool, Saturday=bool, Sunday=bool)`. Each character of a bitmask represents a weekday starting on monday. Example: Only find HIM Messages valid from monday to friday: `1111100`. Defaults to `None`.
* ids (`list`, optional): List of HIM message IDs as a list or separated by comma. Defaults to `None`.
* operators (`list`, optional): List of operators as a list or separated by comma. Defaults to `None`.
* categories (`list`, optional): List of train categories as a list or separated by comma. Defaults to `None`.
* channels (`list`, optional): List of channels as a list or separated by comma. Defaults to `None`.
* companies (`list`, optional): List of companies as a list or separated by comma. Defaults to `None`.
* lines (`list`, optional): Only HIM messages for the given line are part of the result. To filter multiple lines, provide them as a list or separate the codes by comma. Defaults to `None`.
* line_ids (`list`, optional): Only HIM messages for the given line (identified by its line ID) are part of the result. To filter multiple lines, provide them as a list or separate the line IDs by comma. Defaults to `None`.
* stations (`Union[list, List[Stop]]`, optional): List of (external) station ids or a list of `Stop` objects to be filtered for as a list or separated by comma. Defaults to `None`.
* station_from (`Union[str, Stop]`, optional): Filter messages by line segment starting at this station given as (external) station id or as a `Stop` object. Defaults to `None`.
* station_to (`Union[str, Stop]`, optional): Filter messages by line segment travelling in direction of this station given as (external) station id or as a `Stop` object. Defaults to `None`.
* both_ways (`bool`, optional): If enabled, messages in both directions - from 'station_from' to 'station_to' as well as from 'station_to' to 'station_from' are returned. Defaults to `None`.
* train_names (`list`, optional): List of train name to be filtered for seperated by comma. Defaults to `None`.
* search_mode (`Literal[SearchMode.MATCH, SearchMode.NOMATCH, SearchMode.TFMATCH]`, optional): HIM search mode. `SearchMode.NOMATCH` iterate over all HIM messages available. `SearchMode.MATCH` iterate over all trips to find HIM messages. `SearchMode.TFMATCH` uses filters defined `metas` parameter. Defaults to `None`.
* affected_journey_mode (`Literal[AffectedJourneyMode.ALL, AffectedJourneyMode.OFF]`, optional): Define how to return affected journeys `AffectedJourneyMode.OFF`: do not return affected journeys. `AffectedJourneyMode.ALL`: return affected journeys. Defaults to `None`.
* affected_journey_stop_mode (`Literal[AffectedJourneyStopMode.ALL, AffectedJourneyStopMode.IMP, AffectedJourneyStopMode.OFF]`, optional): Define how to return stops of affected journeys. `AffectedJourneyStopMode.IMP`: return important stops of affected journeys. `AffectedJourneyStopMode.OFF`: do not return stops of affected journeys. `AffectedJourneyStopMode.ALL`: return all affected stops of affected journeys. Defaults to `None`.
* priority_min (`int`, optional): Filter for HIM messages having at least this priority. Defaults to `None`.
* priority_max (`int`, optional): Filter for HIM messages having this priority as maximum. Defaults to `None`.
### Returns:
* List[Message]: List of `Message` objects. Empty list if none found.
"""
if isinstance(station_from, Stop):
station_from = station_from.ext_id
if isinstance(station_to, Stop):
station_to = station_to.ext_id
if stations != None:
new_stations = []
for stop in stations:
if isinstance(stop, Stop):
new_stations.append(stop.ext_id)
else:
new_stations.append(stop)
stations = new_stations
search_mode = None if search_mode is None else search_mode.code
affected_journey_mode = (
None if affected_journey_mode is None else affected_journey_mode.code
)
affected_journey_stop_mode = (
None if affected_journey_stop_mode is None else affected_journey_stop_mode.code
)
messages = []
messages_raw = raw_him_search(
accessId=self.access_id,
dateB=date_begin,
dateE=date_end,
timeB=time_begin,
timeE=time_end,
weekdays=weekdays,
himIds=ids,
operators=operators,
categories=categories,
channels=channels,
companies=companies,
lines=lines,
lineids=line_ids,
stations=stations,
fromstation=station_from, # type: ignore
tostation=station_to, # type: ignore
bothways=both_ways,
trainnames=train_names,
searchmode=search_mode, # type: ignore
affectedJourneyMode=affected_journey_mode, # type: ignore
affectedJourneyStopMode=affected_journey_stop_mode, # type: ignore
maxprio=priority_max,
minprio=priority_min,
)
find_exception(messages_raw)
if "Message" in messages_raw:
messages.extend(Message(message) for message in messages_raw["Message"])
return messages
def journey_detail(
self,
id: str,
date: Union[str, datetime, None] = None,
real_time_mode: Union[
Literal[
RealTimeMode.FULL,
RealTimeMode.INFOS,
RealTimeMode.OFF,
RealTimeMode.REALTIME,
RealTimeMode.SERVER_DEFAULT,
],
None,
] = None,
from_id: Union[str, None] = None,
from_index: Union[int, None] = None,
to_id: Union[str, None] = None,
to_index: Union[int, None] = None,
) -> Journey:
"""The journey_detail method will deliver information about the complete route of a vehicle. The journey
identifier is part of a trip or `board_departure()` response. It contains a list of all stops/stations of this journey
including all departure and arrival times (with real-time data if available) and additional information like
specific attributes about facilities and other texts.
More detailed request is available as `raw.journey_detail()`, however returns `dict` instead of `Journey`.
### Args:
* id (`str`): Specifies the internal journey id of the journey shall be retrieved. Maximum length 512.
* date (`Union[str, datetime]`, **optional**): Day of operation. Represented in the format `YYYY-MM-DD` or as a datetime object. By default the current server date is used. Defaults to `None`.
* real_time_mode (`Literal[RealTimeMode.FULL, RealTimeMode.INFOS, RealTimeMode.OFF, RealTimeMode.REALTIME, RealTimeMode.SERVER_DEFAULT]`, **optional**): Set the realtime mode to be used. Read more about this in HAFAS ReST Documentation. Defaults to `None`.
* from_id (`str`, **optional**): Specifies the station/stop ID the partial itinerary shall start from. Defaults to `None`.
* from_index (`int`, **optional**): Specifies the station/stop index the partial itinerary shall start from. Defaults to `None`.
* to_id (`str`, **optional**): Specifies the station/stop ID the partial itinerary shall end at. Defaults to `None`.
* to_index (`int`, **optional**): Specifies the station/stop index the partial itinerary shall end at. Defaults to `None`.
### Returns:
* Journey: Instance of `Journey` object.
"""
real_time_mode = None if real_time_mode is None else real_time_mode.code
journey_raw = raw_journey_detail(
accessId=self.access_id,
id=id,
date=date,
rtMode=real_time_mode, # type: ignore
fromId=from_id,
fromIdx=from_index,
toId=to_id,
toIdx=to_index,
)
find_exception(journey_raw)
return Journey(journey_raw)
def stop_by_coords(
self,
coords_lat: Union[str, float],
coords_lon: Union[str, float],
lang: Literal[
Language.DE,
Language.DA,
Language.EN,
Language.ES,
Language.FR,
Language.HU,
Language.IT,
Language.NL,
Language.NO,
Language.PL,
Language.SV,
Language.TR,
] = Language.EN,
radius: Union[int, float] = 1000,
max_number: int = 10,
stop_type: Literal[
LocationType.S,
LocationType.P,
LocationType.SP,
LocationType.SE,
LocationType.SPE,
] = LocationType.S,
selection_mode: Union[
Literal[SelectionMode.SLCT_A, SelectionMode.SLCT_N], None
] = None,
) -> List[Stop]:
"""Method returns a list of stops around a given center coordinate.
The returned results are ordered by their distance to the center coordinate.
More detailed request is available as `raw.stop_by_coords()`, however returns `dict` instead of `List[Stop]`.
### Args:
* coords_lat (`Union[str, float]`): Latitude of centre coordinate.
* coords_lon (`Union[str, float]`): Longitude of centre coordinate.
* lang (`Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR]`, **optional**): The language of response. Defaults to `Language.EN`.
* radius (`Union[int, float]`, **optional**): Search radius in meter around the given coordinate if any. Defaults to `1000`.
* max_number (`int`, **optional**): Maximum number of returned stops. Defaults to `10`.
* stop_type (`Literal[LocationType.S, LocationType.P, LocationType.SP, LocationType.SE, LocationType.SPE]`, **optional**): Type filter for location types. Defaults to `LocationType.S`.
* selection_mode (`Literal[SelectionMode.SLCT_A, SelectionMode.SLCT_N]`, **optional**): Selection mode for locations. `SelectionMode.SLCT_N`: Not selectable, `SelectionMode.SLCT_A`: Selectable. Defaults to `None`.
### Returns:
* List[Stop]: List of `Stop` objects. Empty list if none found.
"""
selection_mode = None if selection_mode is None else selection_mode.code
stops = []
stops_raw = raw_stop_by_coords(
accessId=self.access_id,
originCoordLat=coords_lat,
originCoordLong=coords_lon,
lang=lang.code,
radius=radius,
maxNo=max_number,
stopType=stop_type.code,
locationSelectionMode=selection_mode, # type: ignore
)
find_exception(stops_raw)
if "stopLocationOrCoordLocation" in stops_raw:
for stop in stops_raw["stopLocationOrCoordLocation"]:
if "StopLocation" in stop:
stops.append(Stop(stop["StopLocation"]))
elif "CoordLocation" in stop:
stops.append(Stop(stop["CoordLocation"]))
return stops
def stop_by_id(
self,
query: str,
lang: Literal[
Language.DE,
Language.DA,
Language.EN,
Language.ES,
Language.FR,
Language.HU,
Language.IT,
Language.NL,
Language.NO,
Language.PL,
Language.SV,
Language.TR,
] = Language.EN,
) -> Union[Stop, None]:
"""Method can be used to get Stop object whilst only having id available.
### Args:
* query (`str`): Search for that token.
* lang (`Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR]`, **optional**): The language of response. Defaults to `Language.EN`.
### Returns:
* Union[Stop, None]: Instance of `Stop` object or `None` if not found.
"""
stops_raw = raw_stop_by_name(
accessId=self.access_id, inputString=query, lang=lang.code, maxNo=1
)
find_exception(stops_raw)
if len(stops_raw["stopLocationOrCoordLocation"]) <= 0:
return None
stop = stops_raw["stopLocationOrCoordLocation"][0]
if "StopLocation" in stop:
return Stop(stop["StopLocation"])
elif "CoordLocation" in stop:
return Stop(stop["CoordLocation"])
else:
return None
def stop_by_name(
self,
query: str,
lang: Literal[
Language.DE,
Language.DA,
Language.EN,
Language.ES,
Language.FR,
Language.HU,
Language.IT,
Language.NL,
Language.NO,
Language.PL,
Language.SV,
Language.TR,
] = Language.EN,
max_number: int = 10,
stop_type: Literal[
LocationType.A,
LocationType.ALL,
LocationType.AP,
LocationType.P,
LocationType.S,
LocationType.SA,
LocationType.SP,
] = LocationType.ALL,
selection_mode: Union[
Literal[SelectionMode.SLCT_A, SelectionMode.SLCT_N], None
] = None,
coord_lat: Union[str, float, None] = None,
coord_lon: Union[str, float, None] = None,
radius: Union[int, float] = 1000,
refine_id: Union[str, None] = None,
stations: Union[str, list, None] = None,
filter_mode: Literal[
FilterMode.DIST_PERI, FilterMode.EXCL_PERI, FilterMode.SLCT_PERI
] = FilterMode.DIST_PERI,
) -> List[Stop]:
"""Method can be used to perform a pattern matching of a user input and to retrieve a list
of possible matches in the journey planner database. Possible matches might be stops/stations,
points of interest and addresses.
More detailed request is available as `raw.stop_by_name()`, however returns `dict` instead of `List[Stop]`.
### Args:
* query (`str`): Search for that token.
* lang (`Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR]`, **optional**): The language of response. Defaults to `Language.EN`.
* max_number (`int`, **optional**): Maximum number of returned stops. In range 1-1000. Defaults to `10`.
* stop_type (`Literal[LocationType.A, LocationType.ALL, LocationType.AP, LocationType.P, LocationType.S, LocationType.SA, LocationType.SP]`, **optional**): Type filter for location types. Defaults to `LocationType.ALL`.
* selection_mode (`Literal[SelectionMode.SLCT_A, SelectionMode.SLCT_N]`, **optional**): Selection mode for locations. `SelectionMode.SLCT_N`: Not selectable, `SelectionMode.SLCT_A`: Selectable. Defaults to `None`.
* coord_lat (`Union[str, float]`, **optional**): Latitude of centre coordinate. Defaults to `None`.
* coord_lon (`Union[str, float]`, **optional**): Longitude of centre coordinate. Defaults to `None`.
* radius (`Union[int, float]`, **optional**): Search radius in meter around the given coordinate if any. Defaults to `1000`.
* refine_id (`str`, **optional**): In case of an refinable location, this value takes the ID of the refinable one of a previous result. Defaults to `None`.
* stations (`Union[str, list]`, **optional**): Filter for stations. Matches if the given value is prefix of any station in the itinerary. As a list or as a string separated by comma. Defaults to `None`.
* filter_mode (`Literal[FilterMode.DIST_PERI, FilterMode.EXCL_PERI, FilterMode.SLCT_PERI]`, **optional**): Filter modes for nearby searches. Defaults to `FilterMode.DIST_PERI`.
### Returns:
* List[Stop]: List of `Stop` objects. Empty list if none found.
"""
selection_mode = None if selection_mode is None else selection_mode.code
stops = []
stops_raw = raw_stop_by_name(
accessId=self.access_id,
inputString=query,
lang=lang.code,
maxNo=max_number,
stopType=stop_type.code,
locationSelectionMode=selection_mode, # type: ignore
coordLat=coord_lat,
coordLong=coord_lon,
radius=radius,
refineId=refine_id,
stations=stations,
filterMode=filter_mode.code,
)
find_exception(stops_raw)
if "stopLocationOrCoordLocation" in stops_raw:
for stop in stops_raw["stopLocationOrCoordLocation"]:
if "StopLocation" in stop:
stops.append(Stop(stop["StopLocation"]))
elif "CoordLocation" in stop:
stops.append(Stop(stop["CoordLocation"]))
return stops
def trip_find(
self,
lang: Literal[
Language.DE,
Language.DA,
Language.EN,
Language.ES,
Language.FR,
Language.HU,
Language.IT,
Language.NL,
Language.NO,
Language.PL,
Language.SV,
Language.TR,
] = Language.EN,
origin_id: Union[str, None] = None,
origin_id_ext: Union[str, None] = None,
origin_coord_lat: Union[str, float, None] = None,
origin_coord_lon: Union[str, float, None] = None,
origin_coord_name: Union[str, None] = None,
destination_id: Union[str, None] = None,
destination_id_ext: Union[str, None] = None,
destination_coord_lat: Union[str, float, None] = None,
destination_coord_lon: Union[str, float, None] = None,
destination_coord_name: Union[str, None] = None,
via: Union[str, None] = None,
via_id: Union[str, None] = None,
via_gis: Union[str, None] = None,
via_wait_time: int = 0,
avoid: Union[str, None] = None,
avoid_id: Union[str, None] = None,
change_time_percent: int = 100,
change_time_min: Union[int, None] = None,
change_time_max: Union[int, None] = None,
change_time_add: Union[int, None] = None,
change_max: Union[int, None] = None,
date: Union[str, datetime, None] = None,
time: Union[str, datetime, None] = None,
search_arrival: bool = False,
trips_after_time: Union[int, None] = None,
trips_before_time: Union[int, None] = None,
context: Union[str, None] = None,
passlist: bool = False,
operators: Union[str, list, None] = None,
lines: Union[str, list, None] = None,
lineids: Union[str, list, None] = None,
iv_include: bool = False,
iv_only: bool = False,
bike_carriage: bool = False,
passing_points: bool = False,
real_time_mode: Union[
Literal[
RealTimeMode.FULL,
RealTimeMode.INFOS,
RealTimeMode.OFF,
RealTimeMode.REALTIME,
RealTimeMode.SERVER_DEFAULT,
],
None,
] = None,
include_earlier: bool = False,
ict_alternatives: bool = False,
tariff: Union[bool, None] = None,
messages: bool = False,
frequency: bool = True,
) -> List[Trip]:
"""The trip service calculates a trip from a specified origin to a specified destination. These might be
stop/station IDs or coordinates based on addresses and points of interest validated by the location service or
coordinates freely defined by the client.
More detailed request is available as `raw.trip_find()`, however returns `dict` instead of `List[Trip]`.
### Args:
* lang (`Literal[Language.DE, Language.DA, Language.EN, Language.ES, Language.FR, Language.HU, Language.IT, Language.NL, Language.NO, Language.PL, Language.SV, Language.TR]`, **optional**): The language of response. Defaults to `Language.EN`.
* origin_id (`str`, **optional**): Specifies the station/stop ID of the origin for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* origin_id_ext (`str`, **optional**): Deprecated. Please use originId as it supports external IDs. Specifies the external station/stop ID of the origin for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* origin_coord_lat (`Union[str, float]`, **optional**): Latitude of station/stop coordinate of the trip's origin. The coordinate can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* origin_coord_lon (`Union[str, float]`, **optional**): Longitude of station/stop coordinate of the trip's origin. The coordinate can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* origin_coord_name (`str`, **optional**): Name of the trip's origin if coordinate cannot be resolved to an address or poi. Defaults to `None`.
* destination_id (`str`, **optional**): Specifies the station/stop ID of the destination for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* destination_id_ext (`str`, **optional**): Deprecated. Please use destId as it supports external IDs. Specifies the external station/stop ID of the destination for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* destination_coord_lat (`Union[str, float]`, **optional**): Latitude of station/stop coordinate of the trip's destination. The coordinate can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* destination_coord_lon (`Union[str, float]`, **optional**): Longitude of station/stop coordinate of the trip's destination. The coordinate can be retrieved from stop_by_name() or stop_by_coords(). Defaults to `None`.
* destination_coord_name (`str`, **optional**): Name of the trip's destination if coordinate cannot be resolved to an address or poi. Defaults to `None`.
* via (`str`, **optional**): Complex structure to provide multiple via points separated by semicolon. This structure is build like this: `viaId|waittime|viastatus|products|direct|sleepingCar|couchetteCoach|attributes`. Read more about this in HAFAS ReST Documentation. Defaults to `None`.
* via_id (`str`, **optional**): ID of a station/stop used as a via for the trip. Specifying a via station forces the trip search to look for trips which must pass through this station. Such ID can be retrieved from stop_by_name() or stop_by_coords(). If `via` is used, `via_id` and `via_wait_time ` are having no effect. Defaults to `None`.
* via_gis (`str`, **optional**): Complex structure to provide multiple GIS via locations separated by semicolon. This structure is build like this: `locationId|locationMode|transportMode|placeType|usageType|mode|durationOfStay`. Read more about this in HAFAS ReST Documentation. Defaults to `None`.
* via_wait_time (`int`, **optional**): Defines the waiting time spent at via station in minutes. If `via` is used, `via_id` and `via_wait_time` are having no effect. Defaults to 0.
* avoid (`str`, **optional**): Complex structure to provide multiple points to be avoided separated by semicolon. This structure is build like this: `avoidId|avoidstatus` avoidId: id, extId or altId of the avoid, mandatory avoidstatus: one of NPAVM (do not run through if this is a meta station), NPAVO (do not run through), NCAVM (do not change if this is a meta station), NCAVO (do not change), optional but defaults to NCAVM Example: Just define three avoids by extId: `avoid="801234;801235;801236"`. Defaults to `None`.
* avoid_id (`str`, **optional**): ID of a station/stop to be avoided as transfer stop for the trip. Such ID can be retrieved from stop_by_name() or stop_by_coords(). If `avoid` is used, `avoid_id` has no effect. Defaults to `None`.
* change_time_percent (`int`, **optional**): Configures the walking speed when changing from one leg of the journey to the next one. It extends the time required for changes by a specified percentage. A value of 200 doubles the change time as initially calculated by the system. In the response, change time is presented in full minutes. If the calculation based on changeTime-Percent does not result in a full minute, it is rounded using "round half up" method. Defaults to `100`.
* change_time_min (`int`, **optional**): Minimum change time at stop in minutes. Defaults to `None`.
* change_time_max (`int`, **optional**): Maximum change time at stop in minutes. Defaults to `None`.
* change_time_add (`int`, **optional**): This amount of minutes is added to the change time at each stop. Defaults to `None`.
* change_max (`int`, **optional**): Maximum number of changes. In range 0-11. Defaults to `None`.
* date (`Union[str, datetime]`, **optional**): Sets the start date for which the departures shall be retrieved. Represented in the format `YYYY-MM-DD` or as a datetime object. By default the current server date is used. Defaults to `None`.
* time (`Union[str, datetime]`, **optional**): Sets the start time for which the departures shall be retrieved. Represented in the format `hh:mm[:ss]` in 24h nomenclature or as a datetime object. Seconds will be ignored for requests. By default the current server time is used. Defaults to `None`.
* search_arrival (`bool`, **optional**): If set, the date and time parameters specify the arrival time for the trip search instead of the departure time. Defaults to `False`.
* trips_after_time (`int`, **optional**): Minimum number of trips after the search time. Sum of `trips_after_time` and `trips_before_time` has to be less or equal 6. Read more about this in HAFAS ReST Documentation. In range 1-6. Defaults to `None`.
* trips_before_time (`int`, **optional**): Minimum number of trips before the search time. Sum of `trips_after_time` and `trips_before_time` has to be less or equal 6. Read more about this in HAFAS ReST Documentation. In range 0-6. Defaults to `None`.
* context (`str`, **optional**): Defines the starting point for the scroll back or forth operation. Use the scrB value from a previous result to scroll backwards in time and use the scrF value to scroll forth. Defaults to `None`.
* passlist (`bool`, **optional**): Enables/disables the return of the passlist for each leg of the trip. Defaults to `False`.
* operators (`Union[str, list]`, **optional**): Only trips provided by the given operators are part of the result. If the operator should not be part of the be trip, negate it by putting ! in front of it. Example: Filter for operator A and B: `operators=["A","B"]`. Defaults to `None`.
* lines (`Union[str, list]`, **optional**): Only journeys running the given line are part of the result. If the line should not be part of the be trip, negate it by putting ! in front of it. Defaults to `None`.
* lineids (`Union[str, list]`, **optional**): Only journeys running the given line (identified by its line ID) are part of the result. If the line should not be part of the be trip, negate it by putting ! in front of it. Defaults to `None`.
* iv_include (`bool`, **optional**): Enables/disables search for individual transport routes. Defaults to `False`.
* iv_only (`bool`, **optional**): Enables/disables search for individual transport routes only. Defaults to `False`.
* bike_carriage (`bool`, **optional**): Enables/disables search for trips explicit allowing bike carriage. This will only work in combination with `change_max=0` as those trips are always meant to be direct connections. Defaults to `False`.
* passing_points (`bool`, **optional**): Enables/disables the return of stops having no alighting and boarding in its passlist for each leg of the trip. Needs passlist enabled. Defaults to `False`.
* real_time_mode (`Literal[RealTimeMode.FULL, RealTimeMode.INFOS, RealTimeMode.OFF, RealTimeMode.REALTIME, RealTimeMode.SERVER_DEFAULT]`, **optional**): Set the realtime mode to be used. Read more about this in HAFAS ReST Documentation. Defaults to `None`.
* include_earlier (`bool`, **optional**): Disables search optimization in relation of duration. Defaults to `False`.
* ict_alternatives (`bool`, **optional**): Enables/disables the search for alternatives with individualized change times (ICT). Defaults to `False`.
* tariff (`bool`, **optional**): Enables/disables the output of tariff data. The default is configurable via provisioning. Defaults to `None`.
* messages (`bool`, **optional**): Enables/disables the output of traffic messages. The default is configurable via provisioning. Defaults to `False`.
* frequency (`bool`, **optional**): Enables/disables the calculation of frequency information. Defaults to `True`.
### Returns:
* List[Trip]: List of `Trip` objects. Empty list if none found.
"""
real_time_mode = None if real_time_mode is None else real_time_mode.code
trips = []
trips_raw = raw_trip_find(
accessId=self.access_id,
lang=lang.code,
originId=origin_id,
originExtId=origin_id_ext,
originCoordLat=origin_coord_lat,
originCoordLong=origin_coord_lon,
originCoordName=origin_coord_name,
destId=destination_id,
destExtId=destination_id_ext,
destCoordLat=destination_coord_lat,
destCoordLong=destination_coord_lon,
destCoordName=destination_coord_name,
via=via,
viaId=via_id,
viaGis=via_gis,
viaWaitTime=via_wait_time,
avoid=avoid,
avoidId=avoid_id,
changeTimePercent=change_time_percent,
minChangeTime=change_time_min,
maxChangeTime=change_time_max,
addChangeTime=change_time_add,
maxChange=change_max,
date=date,
time=time,
searchForArrival=search_arrival,
numF=trips_after_time,
numB=trips_before_time,
context=context,
passlist=passlist,
operators=operators,
lines=lines,
lineids=lineids,
includeIv=iv_include,
ivOnly=iv_only,
bikeCarriage=bike_carriage,
showPassingPoints=passing_points,
rtMode=real_time_mode, # type: ignore
includeEarlier=include_earlier,
withICTAlternatives=ict_alternatives,
tariff=tariff,
trafficMessages=messages,
withFreq=frequency,
)
find_exception(trips_raw)
if "Trip" in trips_raw:
trips.extend(Trip(trip) for trip in trips_raw["Trip"])
return trips
def trip_recon(
self,
context: Union[str, Trip],
date: Union[str, datetime, None] = None,
match_real_time: Union[bool, None] = None,
enable_replacements: Union[bool, None] = None,
arrival_dev_lower: Union[int, None] = None,
arrival_dev_upper: Union[int, None] = None,
departure_dev_lower: Union[int, None] = None,
departure_dev_upper: Union[int, None] = None,
passlist: bool = False,
passing_points: bool = False,
real_time_mode: Union[
Literal[
RealTimeMode.FULL,
RealTimeMode.INFOS,
RealTimeMode.OFF,
RealTimeMode.REALTIME,
RealTimeMode.SERVER_DEFAULT,
],
None,
] = None,
tariff: Union[bool, None] = None,
messages: bool = False,
) -> List[Trip]:
"""Reconstructing a trip can be achieved using the reconstruction context provided by any trip result in the
`ctx_recon` attribute of `Trip` object. The result will be a true copy of the original trip search result given
that the underlying data did not change.
More detailed request is available as `raw.trip_recon()`, however returns `dict` instead of `List[Trip]`.
### Args:
* context (`Union[str, Journey]`): Specifies the reconstruction context.
* date (`Union[str, datetime]`, **optional**): Sets the start date for which the departures shall be retrieved. Represented in the format `YYYY-MM-DD` or as a datetime object. This parameter will force the service to reconstruct the trip on that specific date. If the trip is not available on that date, because it does not operate, exception SvcNoResultError will be raised. Defaults to `None`.
* match_real_time (`bool`, **optional**): Whether the realtime type that journeys are based on be considered. Defaults to `None`.
* enable_replacements (`bool`, **optional**): If set to `True` replaces cancelled journeys with their replacement journeys if possible. Defaults to `None`.
* arrival_dev_lower (`int`, **optional**): Lower deviation in minutes within interval `[0, 720]` indicating "how much earlier than original arrival". Defaults to `None`.
* arrival_dev_upper (`int`, **optional**): Upper deviation in minutes within interval `[0, 720]` indicating "how much later than original arrival". Defaults to `None`.
* departure_dev_lower (`int`, **optional**): Lower deviation in minutes within interval `[0, 720]` indicating "how much earlier than original departure". Defaults to `None`.
* departure_dev_upper (`int`, **optional**): Upper deviation in minutes within interval `[0, 720]` indicating "how much later than original departure". Defaults to `None`.
* passlist (`bool`, **optional**): Enables/disables the return of the passlist for each leg of the trip. Defaults to `None`.
* passing_points (`bool`, **optional**): Enables/disables the return of stops having no alighting and boarding in its passlist for each leg of the trip. Needs passlist parameter enabled. Defaults to `False`.
* real_time_mode (`Literal[RealTimeMode.FULL, RealTimeMode.INFOS, RealTimeMode.OFF, RealTimeMode.REALTIME, RealTimeMode.SERVER_DEFAULT]`, **optional**): Set the realtime mode to be used. Read more about this in HAFAS ReST Documentation. Defaults to `None`.
* tariff (`bool`, **optional**): Enables/disables the output of tariff data. The default is configurable via provisioning. Defaults to `None`.
* messages (`bool`, **optional**): Enables/disables the output of traffic messages. The default is configurable via provisioning. Defaults to `False`.
### Returns:
* List[Trip]: List of `Trip` objects. Empty list if none found.
"""
real_time_mode = None if real_time_mode is None else real_time_mode.code
if isinstance(context, Trip):
context = context.ctx_recon
trips = []
trips_raw = raw_trip_recon(
accessId=self.access_id,
ctx=context, # type: ignore
date=date,
matchRtType=match_real_time,
enableReplacements=enable_replacements,
arrL=arrival_dev_lower,
arrU=arrival_dev_upper,
depL=departure_dev_lower,
depU=departure_dev_upper,
passlist=passlist,
showPassingPoints=passing_points,
rtMode=real_time_mode, # type: ignore
tariff=tariff,
trafficMessages=messages,
)
find_exception(trips_raw)
if "Trip" in trips_raw:
trips.extend(Trip(trip) for trip in trips_raw["Trip"])
return trips

13
src/pyrmv/classes/gis.py Normal file
View File

@@ -0,0 +1,13 @@
from typing import Any, Mapping
from isodate import parse_duration
class Gis:
"""Gis object."""
def __init__(self, ref: str, route: Mapping[str, Any]):
self.ref = ref
self.dist = route["dist"]
self.duration = parse_duration(route["durS"])
self.geo = route["dirGeo"]

View File

@@ -0,0 +1,27 @@
from typing import Any, Mapping
from pyrmv.classes.message import Message
from pyrmv.classes.stop import Stop
from pyrmv.utility import ref_upgrade
class Journey:
"""Journey object."""
def __init__(self, data: Mapping[str, Any]):
self.stops = []
# Upgrade is temporarily used due to RMV API mismatch
# self.ref = data["ref"]
self.ref = ref_upgrade(data["ref"])
self.direction = data["Directions"]["Direction"][0]["value"]
self.direction_flag = data["Directions"]["Direction"][0]["flag"]
self.stops.extend(Stop(stop) for stop in data["Stops"]["Stop"])
self.messages = []
if "Messages" in data:
self.messages.extend(Message(message) for message in data["Messages"]["Message"])
def __str__(self) -> str:
return f"Journey with total of {len(self.stops)} stops and {len(self.messages)} messages heading {self.direction} ({self.direction_flag})"

29
src/pyrmv/classes/leg.py Normal file
View File

@@ -0,0 +1,29 @@
from typing import Any, Mapping
from isodate import parse_duration
from pyrmv.classes.gis import Gis
from pyrmv.classes.message import Message
from pyrmv.classes.stop import StopTrip
class Leg:
"""Trip leg object."""
def __init__(self, data: Mapping[str, Any]):
self.origin = StopTrip(data["Origin"])
self.destination = StopTrip(data["Destination"])
self.gis = (
None if "GisRef" not in data else Gis(data["GisRef"]["ref"], data["GisRoute"])
)
self.messages = []
self.index = data["idx"]
self.name = data["name"]
self.type = data["type"]
self.direction = data.get("direction")
self.number = data.get("number")
self.duration = parse_duration(data["duration"])
self.distance = data.get("dist")
if "Messages" in data:
self.messages.extend(Message(message) for message in data["Messages"]["Message"])

View File

@@ -1,23 +1,29 @@
from pyrmv.classes.Stop import Stop
from datetime import datetime
from typing import Any, Mapping
from isodate import parse_duration
class Url():
from pyrmv.classes.stop import Stop
def __init__(self, data: dict) -> None:
class Url:
"""Traffic message channel url object."""
def __init__(self, data: Mapping[str, Any]) -> None:
self.name = data["name"]
self.url = data["url"]
def __str__(self) -> str:
return f"{self.name}: {self.url}"
class Channel():
def __init__(self, data: dict) -> None:
class Channel:
"""Traffic message channel object."""
def __init__(self, data: Mapping[str, Any]) -> None:
self.name = data["name"]
url = []
for link in url:
url.append(Url(link))
url.extend(Url(link) for link in url)
self.url = url
self.time_start = datetime.strptime(data["validFromTime"], "%H:%M:%S")
self.date_start = datetime.strptime(data["validFromDate"], "%Y-%m-%d")
@@ -28,21 +34,17 @@ class Channel():
return f"{self.name}: from {self.time_start} {self.date_start} until {self.time_end} {self.date_end}"
class Message():
def __init__(self, data: dict) -> None:
class Message:
"""Traffic message object."""
def __init__(self, data: Mapping[str, Any]) -> None:
self.affected_stops = []
for stop in data["affectedStops"]["StopLocation"]:
self.affected_stops.append(Stop(stop))
self.valid_from_stop = Stop(data["validFromStop"])
self.valid_to_stop = Stop(data["validToStop"])
self.valid_from_stop = (
None if "validFromStop" not in data else Stop(data["validFromStop"])
)
self.valid_to_stop = None if "validToStop" not in data else Stop(data["validToStop"])
self.channels = []
for channel in data["channel"]:
self.channels.append(Channel(channel))
self.channels.extend(Channel(channel) for channel in data["channel"])
self.id = data["id"]
self.active = data["act"]
self.head = data["head"]
@@ -50,7 +52,7 @@ class Message():
self.text = data["text"]
self.company = data["company"]
self.category = data["category"]
self.priority = data["priority"]
self.priority = None if "priority" not in data else data["priority"]
self.products = data["products"]
self.icon = data["icon"]
self.time_start = datetime.strptime(data["sTime"], "%H:%M:%S")
@@ -63,11 +65,12 @@ class Message():
self.date_modified = datetime.strptime(data["modDate"], "%Y-%m-%d")
self.daily_start = datetime.strptime(data["dailyStartingAt"], "%H:%M:%S")
self.daily_duration = parse_duration(data["dailyDuration"])
self.base_type = data["baseType"] if "baseType" in data else None
if "baseType" in data:
self.base_type = data["baseType"]
else:
self.base_type = None
if "affectedStops" in data:
self.affected_stops.extend(
Stop(stop) for stop in data["affectedStops"]["StopLocation"]
)
def __str__(self) -> str:
return f"{self.base_type} message with priority {self.products} valid from {self.time_start.time()} {self.date_start.date()} until {self.time_end.time()} {self.date_end.date()}: {self.head} - {self.lead}"
return f"{self.base_type} message with priority {self.products} valid from {self.time_start.time()} {self.date_start.date()} until {self.time_end.time()} {self.date_end.date()}: {self.head} - {self.lead}"

View File

@@ -1,30 +1,32 @@
from datetime import datetime
class Stop():
def __init__(self, data: dict):
class Stop:
"""Stop object."""
def __init__(self, data: dict):
self.name = data["name"]
self.id = data["id"]
if "extId" in data:
self.ext_id = data["extId"]
else:
self.ext_id = None
self.ext_id = data.get("extId")
self.description = data.get("description")
self.lon = data["lon"]
self.lat = data["lat"]
self.route_index = data.get("routeIdx")
self.track_arrival = data.get("arrTrack")
self.track_departure = data.get("depTrack")
def __str__(self) -> str:
return f"Stop {self.name} at {self.lon}, {self.lat}"
class StopTrip(Stop):
"""Trip stop object. It's like a Stop object, but with a date and time."""
def __init__(self, data: dict):
self.type = data["type"]
self.date = datetime.strptime(data["date"], "%Y-%m-%d")
self.time = datetime.strptime(data["time"], "%H:%M:%S")
super().__init__(data)
def __str__(self) -> str:
return f"Stop {self.name} at {self.lon}, {self.lat} at {self.time.time()} {self.date.date()}"
return f"Stop {self.name} at {self.lon}, {self.lat} at {self.time.time()} {self.date.date()}"

View File

@@ -1,4 +1,4 @@
class Ticket():
class Ticket:
"""
{
"externalContent": {
@@ -44,9 +44,9 @@ class Ticket():
"FreigabeId": "20730",
"Freigabe":"2645, 3670, 5001, 5002, 5003, 5004, 5005, 5006, 5011, 5013, 5015, 5021, 5022, 5023, 5031, 5041, 5042, 5046, 5059, 5100, 5233, 6239, 6626, 6636, 6637, 6639, 6648, 6649, 6650, 6655, 6660, 6664, 6691",
"FreigabeOverview": "Bad Homburg v.d.Höhe;Bad Soden a.Ts.;Eschborn;Friedrichsdorf;Glashütten"
}
}
}
"""
def __init__(self) -> None:
pass
pass

View File

@@ -1,36 +1,28 @@
from pyrmv.classes.Leg import Leg
from pyrmv.classes.Stop import StopTrip
from isodate import parse_duration
class Trip():
from pyrmv.classes.leg import Leg
from pyrmv.classes.stop import StopTrip
class Trip:
"""Trip object."""
def __init__(self, data: dict):
self.raw_data = data
self.origin = StopTrip(data["Origin"])
self.destination = StopTrip(data["Destination"])
self.legs = []
for leg in data["LegList"]["Leg"]:
self.legs.append(Leg(leg))
self.legs.extend(Leg(leg) for leg in data["LegList"]["Leg"])
self.calculation = data["calculation"]
self.index = data["idx"]
self.id = data["tripId"]
self.ctx_recon = data["ctxRecon"]
self.duration = parse_duration(data["duration"])
if "rtDuration" in data:
self.real_time_duration = parse_duration(data["rtDuration"])
else:
self.real_time_duration = None
self.real_time_duration = (
None if "rtDuration" not in data else parse_duration(data["rtDuration"])
)
self.checksum = data["checksum"]
if "transferCount" in data:
self.transfer_count = data["transferCount"]
else:
self.transfer_count = 0
self.transfer_count = data.get("transferCount", 0)
def __str__(self) -> str:
return f"Trip from {self.origin.name} to {self.destination.name} lasting {self.duration} ({self.real_time_duration}) with {len(self.legs)} legs and {self.transfer_count} transfers"
return f"Trip from {self.origin.name} to {self.destination.name} lasting {self.duration} ({self.real_time_duration}) with {len(self.legs)} legs and {self.transfer_count} transfers"

View File

@@ -0,0 +1 @@
from .product import PRODUCTS

View File

@@ -17,4 +17,4 @@ PRODUCTS: Dict[str, int] = {
"ferry": 256,
"taxi": 512,
"bahn": 1024,
}
}

View File

@@ -0,0 +1,10 @@
from .aff_journey_mode import AffectedJourneyMode
from .aff_journey_stop_mode import AffectedJourneyStopMode
from .board_type import BoardArrivalType, BoardDepartureType
from .filter_mode import FilterMode
from .lang import Language
from .location_type import LocationType
from .product import Product
from .rt_mode import RealTimeMode
from .search_mode import SearchMode
from .selection_mode import SelectionMode

View File

@@ -0,0 +1,13 @@
from enum import auto
from .auto_name import AutoName
class AffectedJourneyMode(AutoName):
"""Enumeration used to declare types of HIM search modes."""
ALL = auto()
"Return affected journeys."
OFF = auto()
"Do not return affected journeys."

View File

@@ -0,0 +1,16 @@
from enum import auto
from .auto_name import AutoName
class AffectedJourneyStopMode(AutoName):
"""Enumeration used to declare types of affected journey stops return modes."""
ALL = auto()
"Return all affected stops of affected journeys."
IMP = auto()
"Return important stops of affected journeys."
OFF = auto()
"Do not return stops of affected journeys."

View File

@@ -2,7 +2,9 @@
# https://github.com/pyrogram/pyrogram/blob/master/pyrogram/enums/auto_name.py
from enum import Enum
from pyrmv.const.product import PRODUCTS
from pyrmv.const import PRODUCTS
class AutoName(Enum):
def __init__(self, code) -> None:
@@ -14,6 +16,7 @@ class AutoName(Enum):
def __repr__(self):
return f"pyrmv.enums.{self}"
class AutoNameProduct(AutoName):
def __init__(self, code) -> None:
self.code = PRODUCTS[code]
self.code = PRODUCTS[code]

View File

@@ -0,0 +1,47 @@
from enum import auto
from .auto_name import AutoName
class BoardArrivalType(AutoName):
"""Enumeration used to declare types of arrival board.
* ARR - Arrival board as configured in HAFAS
* ARR_EQUIVS - Arrival board with all journeys at any masts and equivalent stops
* ARR_MAST - Arrival board at mast
* ARR_STATION - Arrival board with all journeys at any masts of the requested station
"""
ARR = auto()
"Arrival board as configured in HAFAS"
ARR_EQUIVS = auto()
"Arrival board with all journeys at any masts and equivalent stops"
ARR_MAST = auto()
"Arrival board at mast"
ARR_STATION = auto()
"Arrival board with all journeys at any masts of the requested station"
class BoardDepartureType(AutoName):
"""Enumeration used to declare types of departure board.
* DEP - Departure board as configured in HAFAS
* DEP_EQUIVS - Departure board with all journeys at any masts and equivalent stops
* DEP_MAST - Departure board at mast
* DEP_STATION - Departure board with all journeys at any masts of the requested station
"""
DEP = auto()
"Departure board as configured in HAFAS"
DEP_EQUIVS = auto()
"Departure board with all journeys at any masts and equivalent stops"
DEP_MAST = auto()
"Departure board at mast"
DEP_STATION = auto()
"Departure board with all journeys at any masts of the requested station"

View File

@@ -1,8 +1,15 @@
from enum import auto
from .auto_name import AutoName
class FilterMode(AutoName):
"""Enumeration used to declare filters for nearby searches."""
"""Enumeration used to declare filters for nearby searches.
* DIST_PERI - Accentuate matches. Matches in the radius are first
* EXCL_PERI - Returns matches inside the radius only
* SLCT_PERI - Matches in the radius are excluded. Returns matches outside the radius only
"""
DIST_PERI = auto()
"Accentuate matches. Matches in the radius are first."
@@ -11,4 +18,4 @@ class FilterMode(AutoName):
"Returns matches inside the radius only."
SLCT_PERI = auto()
"Matches in the radius are excluded. Returns matches outside the radius only."
"Matches in the radius are excluded. Returns matches outside the radius only."

View File

@@ -1,24 +1,44 @@
from enum import auto
from .auto_name import AutoName
class Language(AutoName):
"""Enumeration used to declare locales as ISO-3166 codes (but only available in HAFAS ones)."""
DE = auto()
"German"
AR = auto()
"Arabic"
CA = auto()
"Catalan, Valencian"
DA = auto()
"Danish"
DE = auto()
"German"
EL = auto()
"Greek"
EN = auto()
"English"
ES = auto()
"Spanish"
FI = auto()
"Finnish"
FR = auto()
"French"
HI = auto()
"Hindi"
HR = auto()
"Croatian"
HU = auto()
"Hungarian"
@@ -34,8 +54,26 @@ class Language(AutoName):
PL = auto()
"Polish"
RU = auto()
"Russian"
SK = auto()
"Slovak"
SL = auto()
"Slovenian"
SV = auto()
"Swedish"
TL = auto()
"Tagalog"
TR = auto()
"Turkish"
"Turkish"
UR = auto()
"Urdu"
ZH = auto()
"Chinese"

View File

@@ -0,0 +1,49 @@
from enum import auto
from .auto_name import AutoName
class LocationType(AutoName):
"""Enumeration used to declare types of location filter.
* S - Search for station/stops only
* A - Search for addresses only
* P - Search for POIs only
* AP - Search for addresses and POIs
* SA - Search for station/stops and addresses
* SE - Search for stations/stops and entrypoints
* SP - Search for stations/stops and POIs
* ALL - Search in all existing location pools
* SPE - Search for stations/stops, POIs and entrypoints
Note that not all location types may be available for a certain methods.
Make sure that selected type is supported by method by looking up
its acceptable types in argument description.
"""
S = auto()
"Search for station/stops only"
A = auto()
"Search for addresses only"
P = auto()
"Search for POIs only"
AP = auto()
"Search for addresses and POIs"
SA = auto()
"Search for station/stops and addresses"
SE = auto()
"Search for stations/stops and entrypoints"
SP = auto()
"Search for stations/stops and POIs"
ALL = auto()
"Search in all existing location pools"
SPE = auto()
"Search for stations/stops, POIs and entrypoints"

View File

@@ -1,6 +1,8 @@
from enum import auto
from .auto_name import AutoNameProduct
class Product(AutoNameProduct):
"""Enumeration used to declare types of transport."""
@@ -11,7 +13,7 @@ class Product(AutoNameProduct):
"InterCity (commonly abbreviated IC on timetables and tickets) is the classification applied to certain long-distance passenger train services in Europe. Such trains (in contrast to regional, local, or commuter trains) generally call at major stations only."
EC = auto()
"EuroCity, abbreviated as EC, is a cross-border train category within the European inter-city rail network. In contrast to trains allocated to the lower-level \"IC\" (InterCity) category, EC trains are international services that meet 20 criteria covering comfort, speed, food service, and cleanliness."
'EuroCity, abbreviated as EC, is a cross-border train category within the European inter-city rail network. In contrast to trains allocated to the lower-level "IC" (InterCity) category, EC trains are international services that meet 20 criteria covering comfort, speed, food service, and cleanliness.'
R = auto()
"Regional rail, also known as local trains and stopping trains, are passenger rail services that operate between towns and cities. These trains operate with more stops over shorter distances than inter-city rail, but fewer stops and faster service than commuter rail."
@@ -44,4 +46,4 @@ class Product(AutoNameProduct):
"A taxi, also known as a taxicab or simply a cab, is a type of vehicle for hire with a driver, used by a single passenger or small group of passengers, often for a non-shared ride."
BAHN = auto()
"Rail transport (also known as train transport) is a means of transport that transfers passengers and goods on wheeled vehicles running on rails, which are located on tracks. In contrast to road transport, where the vehicles run on a prepared flat surface, rail vehicles (rolling stock) are directionally guided by the tracks on which they run."
"Rail transport (also known as train transport) is a means of transport that transfers passengers and goods on wheeled vehicles running on rails, which are located on tracks. In contrast to road transport, where the vehicles run on a prepared flat surface, rail vehicles (rolling stock) are directionally guided by the tracks on which they run."

View File

@@ -1,6 +1,8 @@
from enum import auto
from .auto_name import AutoName
class RealTimeMode(AutoName):
"""Enumeration used to declare types of real-time traffic."""
@@ -17,4 +19,4 @@ class RealTimeMode(AutoName):
"Search on real-time data: Connections are computed on the basis of real-time data, using planned schedule only whenever no real-time data is available. All connections computed are feasible with respect to the currently known real-time situation. Additional trains (supplied via real-time feed) will be found if these are part of a fast, comfortable, or direct connection (or economic connection, if economic search is activated)."
SERVER_DEFAULT = auto()
"One of the other real-times modes used by default for RMV."
"One of the other real-times modes used by default for RMV."

View File

@@ -0,0 +1,16 @@
from enum import auto
from .auto_name import AutoName
class SearchMode(AutoName):
"""Enumeration used to declare types of HIM search modes."""
MATCH = auto()
"Iterate over all trips to find HIM messages."
NOMATCH = auto()
"Iterate over all HIM messages available."
TFMATCH = auto()
"Uses filters defined `metas` parameter."

View File

@@ -0,0 +1,17 @@
from enum import auto
from .auto_name import AutoName
class SelectionMode(AutoName):
"""Enumeration used to declare location selection modes.
* SLCT_A - Selectable
* SLCT_N - Not selectable
"""
SLCT_A = auto()
"Selectable"
SLCT_N = auto()
"Not selectable"

View File

@@ -0,0 +1,7 @@
from .api_errors import *
from .int_errors import *
from .not_ready import *
from .ps_errors import *
from .sot_errors import *
from .svc_errors import *
from .unknown_error import *

View File

@@ -2,32 +2,38 @@ class ApiAuthError(Exception):
"""
Access denied for accessId provided.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class ApiQuotaError(Exception):
"""
Quota exceeded for accessId provided.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class ApiTooManyRequests(Exception):
"""
Too many requests.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class ApiParamError(Exception):
"""Exception raised for errors in the input arguments.
@@ -42,14 +48,16 @@ class ApiParamError(Exception):
super().__init__(self.errorText)
def __str__(self):
return f'{self.errorCode} -> {self.errorText}'
return f"{self.errorCode} -> {self.errorText}"
class ApiFormatError(Exception):
"""
Response format not supported.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
return self.__doc__

View File

@@ -2,28 +2,33 @@ class IntError(Exception):
"""
Internal RMV server error.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class IntGatewayError(Exception):
"""
Communication error with RMV backend systems.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class IntTimeoutError(Exception):
"""
Timeout during service processing.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
return self.__doc__

View File

@@ -0,0 +1,10 @@
class NotReadyYetError(Exception):
"""
This method is not finished yet.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__

View File

@@ -6,8 +6,9 @@ class PsIncorrectParamError(Exception):
forward/backward from the end/beginning of the
connection.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
return self.__doc__

View File

@@ -2,48 +2,57 @@ class SotAlreadyArrivedError(Exception):
"""
Trip already arrived.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SotNotStartedError(Exception):
"""
Trip not started.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SotCancelledError(Exception):
"""
Trip cancelled.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SotAllTrainsFilteredError(Exception):
"""
All trips filtered.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SotStayOnTripError(Exception):
"""
No change. Stay on trip.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
return self.__doc__

View File

@@ -12,134 +12,160 @@ class SvcParamError(Exception):
super().__init__(self.errorText)
def __str__(self):
return f'{self.errorCode} -> {self.errorText}'
return f"{self.errorCode} -> {self.errorText}"
class SvcLocationError(Exception):
"""
Location missing or invalid.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcLocationArrivalError(Exception):
"""
Arrival location missing or invalid.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcLocationDepartureError(Exception):
"""
Departure location missing or invalid.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcLocationViaError(Exception):
"""
Unknown change stop.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcLocationEqualError(Exception):
"""
Origin/destination or vias are equal.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcLocationNearError(Exception):
"""
Origin and destination are too close.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcDatetimeError(Exception):
"""
Date/time are missing or invalid.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcDatetimePeriodError(Exception):
"""
Date/time are not in timetable or allowed period.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcProductError(Exception):
"""
Product field missing or invalid.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcContextError(Exception):
"""
Context is invalid.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcNoResultError(Exception):
"""
No result found.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcSearchError(Exception):
"""
Unsuccessful search.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
class SvcNoMatchError(Exception):
"""
No match found.
"""
def __init__(self):
super().__init__(self.__doc__)
def __str__(self):
return self.__doc__
return self.__doc__

View File

@@ -12,4 +12,4 @@ class UnknownError(Exception):
super().__init__(self.errorText)
def __str__(self):
return f'{self.errorCode} -> {self.errorText}'
return f"{self.errorCode} -> {self.errorText}"

View File

@@ -5,4 +5,4 @@ from .journey_detail import journey_detail
from .stop_by_coords import stop_by_coords
from .stop_by_name import stop_by_name
from .trip_find import trip_find
from .trip_recon import trip_recon
from .trip_recon import trip_recon

View File

@@ -1,6 +1,7 @@
from datetime import datetime, timedelta
from typing import Union
from requests import get
from datetime import datetime
from typing import List, Union
from xmltodict import parse as xmlparse
try:
@@ -8,32 +9,34 @@ try:
except ImportError:
from typing_extensions import Literal
# 2.25. Arrival Board (arrivalBoard)
def board_arrival(accessId: str,
json: bool = True,
id: str = None, # type: ignore
extId: str = None, # type: ignore
direction: str = None, # type: ignore
date: Union[str, datetime] = None, # type: ignore
time: Union[str, datetime] = None, # type: ignore
duration: int = 60,
maxJourneys: int = -1,
products: int = None, # type: ignore
operators: Union[str, list] = None, # type: ignore
lines: Union[str, list] = None, # type: ignore
filterEquiv: bool = True,
attributes: Union[str, list] = None, # type: ignore
platforms: Union[str, list] = None, # type: ignore
passlist: bool = False,
boardType: Literal["ARR", "ARR_EQUIVS", "ARR_MAST", "ARR_STATION"] = "ARR"
) -> dict:
def board_arrival(
accessId: str,
json: bool = True,
id: Union[str, None] = None,
extId: Union[str, None] = None,
direction: Union[str, None] = None,
date: Union[str, datetime, None] = None,
time: Union[str, datetime, None] = None,
duration: Union[int, timedelta] = 60,
maxJourneys: int = -1,
products: Union[int, None] = None,
operators: Union[str, list, None] = None,
lines: Union[str, list, None] = None,
filterEquiv: bool = True,
attributes: Union[str, list, None] = None,
platforms: Union[str, list, None] = None,
passlist: bool = False,
boardType: Literal["ARR", "ARR_EQUIVS", "ARR_MAST", "ARR_STATION"] = "ARR",
) -> dict:
"""The arrival board can be retrieved by a call to the arrivalBoard service. This method will return the next
arrivals from a given point in time within a duration covered time span. The default duration size is 60 minutes.
arrivals from a given point in time within a duration covered time span. The default duration size is 60 minutes.
Note: The result list always contains all arrivals running the the last minute found even if the requested
maximum was overrun.
maximum was overrun.
Read more about this in section 2.25. "Arrival Board (arrivalBoard)" of HAFAS ReST Documentation.
Read more about this in section 2.25. "Arrival Board (arrivalBoard)" of HAFAS ReST Documentation.
### Args:
* accessId (str): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
@@ -56,14 +59,10 @@ def board_arrival(accessId: str,
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
if json:
headers = {"Accept": "application/json"}
else:
headers = {"Accept": "application/xml"}
"""
payload = {}
headers = {"Accept": "application/json"} if json else {"Accept": "application/xml"}
for var, val in locals().items():
if str(var) == "date":
@@ -74,24 +73,19 @@ def board_arrival(accessId: str,
payload[str(var)] = val
elif str(var) == "time":
if val != None:
if isinstance(val, datetime):
payload[str(var)] = val.strftime("%H:%M")
else:
payload[str(var)] = val
payload[str(var)] = (
val.strftime("%H:%M") if isinstance(val, datetime) else val
)
elif str(var) == "duration":
if val != None:
payload[str(var)] = val.minutes if isinstance(val, timedelta) else val
elif str(var) == "boardType":
if val != None:
payload["type"] = val
payload["type"] = val.upper()
elif str(var) not in ["json", "headers", "payload"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/arrivalBoard", params=payload, headers=headers)
# Exceptions checker moved to normal methods
# and exceptions will no longer raise in raw ones.
# find_exception(output.json())
if json:
return output.json()
else:
return xmlparse(output.content)
return output.json() if json else xmlparse(output.content)

View File

@@ -1,6 +1,7 @@
from datetime import datetime
from datetime import datetime, timedelta
from typing import Union
from requests import get
from typing import List, Union
from xmltodict import parse as xmlparse
try:
@@ -8,33 +9,35 @@ try:
except ImportError:
from typing_extensions import Literal
# 2.24. Departure Board (departureBoard)
def board_departure(accessId: str,
json: bool = True,
id: str = None, # type: ignore
extId: str = None, # type: ignore
direction: str = None, # type: ignore
date: Union[str, datetime] = None, # type: ignore
time: Union[str, datetime] = None, # type: ignore
duration: int = 60,
maxJourneys: int = -1,
products: int = None, # type: ignore
operators: Union[str, list] = None, # type: ignore
lines: Union[str, list] = None, # type: ignore
filterEquiv: bool = True,
attributes: Union[str, list] = None, # type: ignore
platforms: Union[str, list] = None, # type: ignore
passlist: bool = False,
boardType: Literal["DEP", "DEP_EQUIVS", "DEP_MAST", "DEP_STATION"] = "DEP"
) -> dict:
def board_departure(
accessId: str,
json: bool = True,
id: Union[str, None] = None,
extId: Union[str, None] = None,
direction: Union[str, None] = None,
date: Union[str, datetime, None] = None,
time: Union[str, datetime, None] = None,
duration: Union[int, timedelta] = 60,
maxJourneys: int = -1,
products: Union[int, None] = None,
operators: Union[str, list, None] = None,
lines: Union[str, list, None] = None,
filterEquiv: bool = True,
attributes: Union[str, list, None] = None,
platforms: Union[str, list, None] = None,
passlist: bool = False,
boardType: Literal["DEP", "DEP_EQUIVS", "DEP_MAST", "DEP_STATION"] = "DEP",
) -> dict:
"""The separture board can be retrieved by a call to the departureBoard service. This method will return the
next departures (or less if not existing) from a given point in time within a duration covered time span. The
default duration size is 60 minutes.
default duration size is 60 minutes.
Note: The result list always contains all departures running the the last minute found even if the requested
maximum was overrun.
maximum was overrun.
Read more about this in section 2.24. "Departure Board (departureBoard)" of HAFAS ReST Documentation.
Read more about this in section 2.24. "Departure Board (departureBoard)" of HAFAS ReST Documentation.
### Args:
* accessId (str): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
@@ -57,14 +60,10 @@ def board_departure(accessId: str,
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
if json:
headers = {"Accept": "application/json"}
else:
headers = {"Accept": "application/xml"}
"""
payload = {}
headers = {"Accept": "application/json"} if json else {"Accept": "application/xml"}
for var, val in locals().items():
if str(var) == "date":
@@ -75,24 +74,19 @@ def board_departure(accessId: str,
payload[str(var)] = val
elif str(var) == "time":
if val != None:
if isinstance(val, datetime):
payload[str(var)] = val.strftime("%H:%M")
else:
payload[str(var)] = val
payload[str(var)] = (
val.strftime("%H:%M") if isinstance(val, datetime) else val
)
elif str(var) == "duration":
if val != None:
payload[str(var)] = val.minutes if isinstance(val, timedelta) else val
elif str(var) == "boardType":
if val != None:
payload["type"] = val
payload["type"] = val.upper()
elif str(var) not in ["json", "headers", "payload"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/departureBoard", params=payload, headers=headers)
# Exceptions checker moved to normal methods
# and exceptions will no longer raise in raw ones.
# find_exception(output.json())
if json:
return output.json()
else:
return xmlparse(output.content)
return output.json() if json else xmlparse(output.content)

View File

@@ -1,55 +1,58 @@
from requests import get
from typing import Dict, OrderedDict, Union
from xmltodict import parse as xmlparse
from datetime import datetime
from typing import OrderedDict, Union
from pyrmv.utility.weekdays_bitmask import weekdays_bitmask
from requests import get
from xmltodict import parse as xmlparse
from pyrmv.utility import weekdays_bitmask
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
# 2.37. HIM Search (himsearch)
def him_search(accessId: str,
json: bool = True,
dateB: Union[str, datetime] = None, # type: ignore
dateE: Union[str, datetime] = None, # type: ignore
timeB: Union[str, datetime] = None, # type: ignore
timeE: Union[str, datetime] = None, # type: ignore
weekdays: Union[str, OrderedDict[str, bool]] = None, # type: ignore
himIds: Union[str, list] = None, # type: ignore
hierarchicalView: bool = False,
operators: Union[str, list] = None, # type: ignore
categories: Union[str, list] = None, # type: ignore
channels: Union[str, list] = None, # type: ignore
companies: Union[str, list] = None, # type: ignore
lines: Union[str, list] = None, # type: ignore
lineids: Union[str, list] = None, # type: ignore
stations: Union[str, list] = None, # type: ignore
fromstation: str = None, # type: ignore
tostation: str = None, # type: ignore
bothways: bool = None, # type: ignore
trainnames: Union[str, list] = None, # type: ignore
metas: Union[str, list] = None, # type: ignore
himcategory: str = None, # type: ignore
himtags: Union[str, list] = None, # type: ignore
regions: Union[str, list] = None, # type: ignore
himtext: Union[str, list] = None, # type: ignore
himtexttags: Union[str, list] = None, # type: ignore
additionalfields: Union[str, list, dict] = None, # type: ignore
poly: bool = False,
searchmode: Literal["MATCH", "NOMATCH", "TFMATCH"] = None, # type: ignore
affectedJourneyMode: Literal["ALL", "OFF"] = None, # type: ignore
affectedJourneyStopMode: Literal["ALL", "IMP", "OFF"] = None, # type: ignore
orderBy: Union[str, list] = None, # type: ignore
minprio: Union[str, int] = None, # type: ignore
maxprio: Union[str, int] = None # type: ignore
) -> dict:
def him_search(
accessId: str,
json: bool = True,
dateB: Union[str, datetime, None] = None,
dateE: Union[str, datetime, None] = None,
timeB: Union[str, datetime, None] = None,
timeE: Union[str, datetime, None] = None,
weekdays: Union[str, OrderedDict[str, bool], None] = None,
himIds: Union[str, list, None] = None,
hierarchicalView: bool = False,
operators: Union[str, list, None] = None,
categories: Union[str, list, None] = None,
channels: Union[str, list, None] = None,
companies: Union[str, list, None] = None,
lines: Union[str, list, None] = None,
lineids: Union[str, list, None] = None,
stations: Union[str, list, None] = None,
fromstation: Union[str, None] = None,
tostation: Union[str, None] = None,
bothways: Union[bool, None] = None,
trainnames: Union[str, list, None] = None,
metas: Union[str, list, None] = None,
himcategory: Union[str, None] = None,
himtags: Union[str, list, None] = None,
regions: Union[str, list, None] = None,
himtext: Union[str, list, None] = None,
himtexttags: Union[str, list, None] = None,
additionalfields: Union[str, list, dict, None] = None,
poly: bool = False,
searchmode: Union[Literal["MATCH", "NOMATCH", "TFMATCH"], None] = None,
affectedJourneyMode: Union[Literal["ALL", "OFF"], None] = None,
affectedJourneyStopMode: Union[Literal["ALL", "IMP", "OFF"], None] = None,
orderBy: Union[str, list, None] = None,
minprio: Union[str, int, None] = None,
maxprio: Union[str, int, None] = None,
) -> dict:
"""The himSearch will return a list of HIM messages if matched by the given criteria as well as affected
products if any.
Read more about this in section 2.37. "HIM Search (himsearch)" of HAFAS ReST Documentation.
Read more about this in section 2.37. "HIM Search (himsearch)" of HAFAS ReST Documentation.
### Args:
* accessId (str): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
@@ -89,45 +92,42 @@ def him_search(accessId: str,
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
if json:
headers = {"Accept": "application/json"}
else:
headers = {"Accept": "application/xml"}
"""
payload = {}
headers = {"Accept": "application/json"} if json else {"Accept": "application/xml"}
for var, val in locals().items():
if str(var) in ["dateB", "dateE"]:
if str(var) in {"dateB", "dateE"}:
if val != None:
if isinstance(val, datetime):
payload[str(var)] = val.strftime("%Y-%m-%d")
else:
payload[str(var)] = val
elif str(var) in ["timeB", "timeE"]:
elif str(var) in {"timeB", "timeE"}:
if val != None:
if isinstance(val, datetime):
payload[str(var)] = val.strftime("%H:%M")
else:
payload[str(var)] = val
payload[str(var)] = (
val.strftime("%H:%M") if isinstance(val, datetime) else val
)
elif str(var) == "weekdays":
if val != None:
if isinstance(val, OrderedDict):
payload[str(var)] = weekdays_bitmask(val)
else:
payload[str(var)] = val
elif str(var) == "searchmode":
if val != None:
payload["searchmode"] = val.upper()
elif str(var) == "affectedJourneyMode":
if val != None:
payload["affectedJourneyMode"] = val.upper()
elif str(var) == "affectedJourneyStopMode":
if val != None:
payload["affectedJourneyStopMode"] = val.upper()
elif str(var) not in ["json", "headers", "payload"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/himsearch", params=payload, headers=headers)
# Exceptions checker moved to normal methods
# and exceptions will no longer raise in raw ones.
# find_exception(output.json())
if json:
return output.json()
else:
return xmlparse(output.content)
return output.json() if json else xmlparse(output.content)

View File

@@ -0,0 +1,68 @@
from datetime import datetime
from typing import Union
from requests import get
from xmltodict import parse as xmlparse
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
# 2.26. Journey Detail (journeyDetail)
def journey_detail(
accessId: str,
id: str,
json: bool = True,
date: Union[str, datetime, None] = None,
poly: bool = False,
polyEnc: Literal["DLT", "GPA", "N"] = "N",
showPassingPoints: bool = False,
rtMode: Union[Literal["FULL", "INFOS", "OFF", "REALTIME", "SERVER_DEFAULT"], None] = None,
fromId: Union[str, None] = None,
fromIdx: Union[int, None] = None,
toId: Union[str, None] = None,
toIdx: Union[int, None] = None,
baim: bool = False,
) -> dict:
"""The journey_detail method will deliver information about the complete route of a vehicle. The journey
identifier is part of a trip or departureBoard response. It contains a list of all stops/stations of this journey
including all departure and arrival times (with real-time data if available) and additional information like
specific attributes about facilities and other texts.
Read more about this in section 2.26. "Journey Detail (journeyDetail)" of HAFAS ReST Documentation.
### Args:
* accessId (str): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
* id (str): Specifies the internal journey id of the journey shall be retrieved. Maximum length 512.
* json (bool, optional): Whether response should be retrieved as JSON. XML is returned if False. Defaults to True.
* date (Union[str, datetime], optional): Day of operation. Represented in the format `YYYY-MM-DD`. By default the current server date is used. Defaults to None.
* poly (bool, optional): Enables/disables the calculation of the polyline for each leg of the trip except any GIS route. Defaults to False.
* polyEnc (Literal["DLT", "GPA", "N"], optional): Defines encoding of the returned polyline. Possible values are "N" (no encoding / compression), "DLT" (delta to the previous coordinate), "GPA" (Google encoded polyline format). Defaults to "N".
* showPassingPoints (bool, optional): Enables/disables the return of stops having no alighting and no boarding in its passlist for each leg of the trip. Defaults to False.
* rtMode (Literal["FULL", "INFOS", "OFF", "REALTIME", "SERVER_DEFAULT"], optional): Set the realtime mode to be used. Read more about this in HAFAS ReST Documentation. Defaults to None.
* fromId (str, optional): Specifies the station/stop ID the partial itinerary shall start from. Defaults to None.
* fromIdx (str, optional): Specifies the station/stop index the partial itinerary shall start from. Defaults to None.
* toId (str, optional): Specifies the station/stop ID the partial itinerary shall end at. Defaults to None.
* toIdx (str, optional): Specifies the station/stop index the partial itinerary shall end at. Defaults to None.
* baim (bool, optional): Enables/disables BAIM search and response. Defaults to False.
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
payload = {}
headers = {"Accept": "application/json"} if json else {"Accept": "application/xml"}
for var, val in locals().items():
if str(var) == "rtMode":
if val != None:
payload["rtMode"] = val.upper()
elif str(var) not in ["json", "headers", "payload"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/journeyDetail", params=payload, headers=headers)
return output.json() if json else xmlparse(output.content)

View File

@@ -1,5 +1,6 @@
from typing import Union
from requests import get
from typing import List, Union
from xmltodict import parse as xmlparse
try:
@@ -7,25 +8,29 @@ try:
except ImportError:
from typing_extensions import Literal
# 2.4. Location Search by Coordinate (location.nearbystops)
def stop_by_coords(accessId: str,
originCoordLat: Union[str, float],
originCoordLong: Union[str, float],
lang: Literal["de", "da", "en", "es", "fr", "hu", "it", "nl", "no", "pl", "sv", "tr"] = "en",
json: bool = True,
radius: Union[int, float] = 1000,
maxNo: int = 10,
stopType: Literal["S", "P", "SP", "SE", "SPE"] = "S",
locationSelectionMode: Literal["SLCT_N", "SLCT_A"] = None, # type: ignore
products: int = None, # type: ignore
meta: str = None, # type: ignore
sattributes: Union[str, list] = None, # type: ignore
sinfotexts: Union[str, list] = None # type: ignore
) -> dict:
"""The location.nearbystops service returns a list of stops around a given center coordinate (within a
radius of 1000m). The returned results are ordered by their distance to the center coordinate.
Read more about this in section 2.4. "Location Search by Coordinate (location.nearbystops)" of HAFAS ReST Documentation.
# 2.4. Location Search by Coordinate (location.nearbystops)
def stop_by_coords(
accessId: str,
originCoordLat: Union[str, float],
originCoordLong: Union[str, float],
lang: Literal[
"de", "da", "en", "es", "fr", "hu", "it", "nl", "no", "pl", "sv", "tr"
] = "en",
json: bool = True,
radius: Union[int, float] = 1000,
maxNo: int = 10,
stopType: Literal["S", "P", "SP", "SE", "SPE"] = "S",
locationSelectionMode: Union[Literal["SLCT_N", "SLCT_A"], None] = None,
products: Union[int, None] = None,
meta: Union[str, None] = None,
sattributes: Union[str, list, None] = None,
sinfotexts: Union[str, list, None] = None,
) -> dict:
"""The location.nearbystops service returns a list of stops around a given center coordinate (within a
radius of 1000m). The returned results are ordered by their distance to the center coordinate.
Read more about this in section 2.4. "Location Search by Coordinate (location.nearbystops)" of HAFAS ReST Documentation.
### Args:
* accessId (str): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
@@ -44,27 +49,24 @@ def stop_by_coords(accessId: str,
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
if json:
headers = {"Accept": "application/json"}
else:
headers = {"Accept": "application/xml"}
"""
payload = {}
headers = {"Accept": "application/json"} if json else {"Accept": "application/xml"}
for var, val in locals().items():
if str(var) not in ["json", "headers", "payload", "raw_response"]:
if str(var) == "stopType":
if val != None:
payload["type"] = val.upper()
elif str(var) == "locationSelectionMode":
if val != None:
payload["locationSelectionMode"] = val.upper()
elif str(var) not in ["json", "headers", "payload", "raw_response"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/location.nearbystops", params=payload, headers=headers)
output = get(
"https://www.rmv.de/hapi/location.nearbystops", params=payload, headers=headers
)
# Exceptions checker moved to normal methods
# and exceptions will no longer raise in raw ones.
# find_exception(output.json())
if json:
return output.json()
else:
return xmlparse(output.content)
return output.json() if json else xmlparse(output.content)

View File

@@ -1,5 +1,6 @@
from typing import Union
from requests import get
from typing import List, Union
from xmltodict import parse as xmlparse
try:
@@ -7,33 +8,37 @@ try:
except ImportError:
from typing_extensions import Literal
# 2.3. Location Search by Name (location.name)
def stop_by_name(accessId: str,
inputString: str,
lang: Literal["de", "da", "en", "es", "fr", "hu", "it", "nl", "no", "pl", "sv", "tr"] = "en",
json: bool = True,
maxNo: int = 10,
stopType: Literal["A", "ALL", "AP", "P", "S", "SA", "SP"] = "ALL",
locationSelectionMode: Literal["SLCT_N", "SLCT_A"] = None, # type: ignore
products: int = None, # type: ignore
coordLat: Union[str, float] = None, # type: ignore
coordLong: Union[str, float] = None, # type: ignore
radius: Union[int, float] = 1000,
refineId: str = None, # type: ignore
meta: str = None, # type: ignore
stations: Union[str, list] = None, # type: ignore
sattributes: Union[str, list] = None, # type: ignore
filterMode: Literal["DIST_PERI", "EXCL_PERI", "SLCT_PERI"] = "DIST_PERI"
) -> dict:
def stop_by_name(
accessId: str,
inputString: str,
lang: Literal[
"de", "da", "en", "es", "fr", "hu", "it", "nl", "no", "pl", "sv", "tr"
] = "en",
json: bool = True,
maxNo: int = 10,
stopType: Literal["A", "ALL", "AP", "P", "S", "SA", "SP"] = "ALL",
locationSelectionMode: Union[Literal["SLCT_N", "SLCT_A"], None] = None,
products: Union[int, None] = None,
coordLat: Union[str, float, None] = None,
coordLong: Union[str, float, None] = None,
radius: Union[int, float] = 1000,
refineId: Union[str, None] = None,
meta: Union[str, None] = None,
stations: Union[str, list, None] = None,
sattributes: Union[str, list, None] = None,
filterMode: Literal["DIST_PERI", "EXCL_PERI", "SLCT_PERI"] = "DIST_PERI",
) -> dict:
"""The location.name service can be used to perform a pattern matching of a user input and to retrieve a list
of possible matches in the journey planner database. Possible matches might be stops/stations, points of
interest and addresses.
interest and addresses.
The result is a list of possible matches (locations) where the user might pick one entry to perform a trip
request with this location as origin or destination or to ask for a departure board or arrival board of this
location (stops/stations only).
location (stops/stations only).
Read more about this in section 2.3. "Location Search by Name (location.name)" of HAFAS ReST Documentation.
Read more about this in section 2.3. "Location Search by Name (location.name)" of HAFAS ReST Documentation.
### Args:
* accessId (str): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
@@ -55,30 +60,25 @@ def stop_by_name(accessId: str,
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
if json:
headers = {"Accept": "application/json"}
else:
headers = {"Accept": "application/xml"}
"""
payload = {}
headers = {"Accept": "application/json"} if json else {"Accept": "application/xml"}
for var, val in locals().items():
if str(var) == "inputString":
if val != None:
payload["input"] = val
elif str(var) not in ["json", "headers", "payload", "raw_response"]:
elif str(var) == "stopType":
if val != None:
payload["type"] = val.upper()
elif str(var) == "filterMode":
if val != None:
payload["filterMode"] = val.upper()
elif str(var) not in ["json", "headers", "payload", "raw_response", "stopType"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/location.name", params=payload, headers=headers)
# Exceptions checker moved to normal methods
# and exceptions will no longer raise in raw ones.
# find_exception(output.json())
if json:
return output.json()
else:
return xmlparse(output.content)
return output.json() if json else xmlparse(output.content)

View File

@@ -1,135 +1,111 @@
from datetime import datetime
from requests import get
from typing import List, Union
from xmltodict import parse as xmlparse
from pyrmv.classes.Trip import Trip
from pyrmv.utility.find_exception import find_exception
from requests import get
from xmltodict import parse as xmlparse
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
# 2.12. Trip Search (trip)
def trip_find(accessId: str,
lang: Literal["de", "da", "en", "es", "fr", "hu", "it", "nl", "no", "pl", "sv", "tr"] = "en",
json: bool = True,
originId: str = None, # type: ignore
originExtId: str = None, # type: ignore
originCoordLat: Union[str, float] = None, # type: ignore
originCoordLong: Union[str, float] = None, # type: ignore
originCoordName: str = None, # type: ignore
destId: str = None, # type: ignore
destExtId: str = None, # type: ignore
destCoordLat: Union[str, float] = None, # type: ignore
destCoordLong: Union[str, float] = None, # type: ignore
destCoordName: str = None, # type: ignore
via: str = None, # type: ignore
viaId: str = None, # type: ignore
viaWaitTime: int = 0,
avoid: str = None, # type: ignore
avoidId: str = None, # type: ignore
viaGis: str = None, # type: ignore
changeTimePercent: int = 100,
minChangeTime: int = None, # type: ignore
maxChangeTime: int = None, # type: ignore
addChangeTime: int = None, # type: ignore
maxChange: int = None, # type: ignore
date: Union[str, datetime] = None, # type: ignore
time: Union[str, datetime] = None, # type: ignore
searchForArrival: bool = False,
numF: int = None, # type: ignore
numB: int = None, # type: ignore
context: str = None, # type: ignore
poly: bool = False,
polyEnc: Literal["DLT", "GPA", "N"] = "N",
passlist: bool = False,
products: int = None, # type: ignore
operators: Union[str, list] = None, # type: ignore
attributes: Union[str, list] = None, # type: ignore
sattributes: Union[str, list] = None, # type: ignore
fattributes: Union[str, list] = None, # type: ignore
lines: Union[str, list] = None, # type: ignore
lineids: Union[str, list] = None, # type: ignore
avoidPaths: List[Literal["SW", "EA", "ES", "RA", "CB"]] = None, # type: ignore
originWalk: Union[str, list] = None, # type: ignore
originBike: Union[str, list] = None, # type: ignore
originCar: Union[str, list] = None, # type: ignore
originTaxi: Union[str, list] = None, # type: ignore
originPark: Union[str, list] = None, # type: ignore
originMeta: Union[str, list] = None, # type: ignore
destWalk: Union[str, list] = None, # type: ignore
destBike: Union[str, list] = None, # type: ignore
destCar: Union[str, list] = None, # type: ignore
destTaxi: Union[str, list] = None, # type: ignore
destPark: Union[str, list] = None, # type: ignore
destMeta: Union[str, list] = None, # type: ignore
totalWalk: Union[str, list] = None, # type: ignore
totalBike: Union[str, list] = None, # type: ignore
totalCar: Union[str, list] = None, # type: ignore
totalTaxi: Union[str, list] = None, # type: ignore
totalMeta: Union[str, list] = None, # type: ignore
gisProducts: str = None, # type: ignore
includeIv: bool = False,
ivOnly: bool = False,
mobilityProfile: str = None, # type: ignore
bikeCarriage: bool = False,
bikeCarriageType: Literal["SINGLEBIKES", "SMALLGROUPS", "LARGEGROUPS"] = None, # type: ignore
sleepingCar: bool = False,
couchetteCoach: bool = False,
showPassingPoints: bool = False,
baim: bool = False,
eco: bool = False,
ecoCmp: bool = False,
ecoParams: str = None, # type: ignore
rtMode: Literal["FULL", "INFOS", "OFF", "REALTIME", "SERVER_DEFAULT"] = None, # type: ignore
unsharp: bool = False,
trainFilter: str = None, # type: ignore
economic: bool = False,
groupFilter: str = None, # type: ignore
blockingList: str = None, # type: ignore
blockedEdges: str = None, # type: ignore
trainComposition: bool = False,
includeEarlier: bool = False,
withICTAlternatives: bool = False,
tariff: bool = None, # type: ignore
trafficMessages: bool = False,
travellerProfileData: str = None, # type: ignore
withFreq: bool = True
) -> dict:
def trip_find(
accessId: str,
lang: Literal[
"de", "da", "en", "es", "fr", "hu", "it", "nl", "no", "pl", "sv", "tr"
] = "en",
json: bool = True,
originId: Union[str, None] = None,
originExtId: Union[str, None] = None,
originCoordLat: Union[str, float, None] = None,
originCoordLong: Union[str, float, None] = None,
originCoordName: Union[str, None] = None,
destId: Union[str, None] = None,
destExtId: Union[str, None] = None,
destCoordLat: Union[str, float, None] = None,
destCoordLong: Union[str, float, None] = None,
destCoordName: Union[str, None] = None,
via: Union[str, None] = None,
viaId: Union[str, None] = None,
viaWaitTime: int = 0,
avoid: Union[str, None] = None,
avoidId: Union[str, None] = None,
viaGis: Union[str, None] = None,
changeTimePercent: int = 100,
minChangeTime: Union[int, None] = None,
maxChangeTime: Union[int, None] = None,
addChangeTime: Union[int, None] = None,
maxChange: Union[int, None] = None,
date: Union[str, datetime, None] = None,
time: Union[str, datetime, None] = None,
searchForArrival: bool = False,
numF: Union[int, None] = None,
numB: Union[int, None] = None,
context: Union[str, None] = None,
poly: bool = False,
polyEnc: Literal["DLT", "GPA", "N"] = "N",
passlist: bool = False,
products: Union[int, None] = None,
operators: Union[str, list, None] = None,
attributes: Union[str, list, None] = None,
sattributes: Union[str, list, None] = None,
fattributes: Union[str, list, None] = None,
lines: Union[str, list, None] = None,
lineids: Union[str, list, None] = None,
avoidPaths: Union[List[Literal["SW", "EA", "ES", "RA", "CB"]], None] = None,
originWalk: Union[str, list, None] = None,
originBike: Union[str, list, None] = None,
originCar: Union[str, list, None] = None,
originTaxi: Union[str, list, None] = None,
originPark: Union[str, list, None] = None,
originMeta: Union[str, list, None] = None,
destWalk: Union[str, list, None] = None,
destBike: Union[str, list, None] = None,
destCar: Union[str, list, None] = None,
destTaxi: Union[str, list, None] = None,
destPark: Union[str, list, None] = None,
destMeta: Union[str, list, None] = None,
totalWalk: Union[str, list, None] = None,
totalBike: Union[str, list, None] = None,
totalCar: Union[str, list, None] = None,
totalTaxi: Union[str, list, None] = None,
totalMeta: Union[str, list, None] = None,
gisProducts: Union[str, None] = None,
includeIv: bool = False,
ivOnly: bool = False,
mobilityProfile: Union[str, None] = None,
bikeCarriage: bool = False,
bikeCarriageType: Union[
Literal["SINGLEBIKES", "SMALLGROUPS", "LARGEGROUPS"], None
] = None,
sleepingCar: bool = False,
couchetteCoach: bool = False,
showPassingPoints: bool = False,
baim: bool = False,
eco: bool = False,
ecoCmp: bool = False,
ecoParams: Union[str, None] = None,
rtMode: Union[Literal["FULL", "INFOS", "OFF", "REALTIME", "SERVER_DEFAULT"], None] = None,
unsharp: bool = False,
trainFilter: Union[str, None] = None,
economic: bool = False,
groupFilter: Union[str, None] = None,
blockingList: Union[str, None] = None,
blockedEdges: Union[str, None] = None,
trainComposition: bool = False,
includeEarlier: bool = False,
withICTAlternatives: bool = False,
tariff: Union[bool, None] = None,
trafficMessages: bool = False,
travellerProfileData: Union[str, None] = None,
withFreq: bool = True,
) -> dict:
"""The trip service calculates a trip from a specified origin to a specified destination. These might be
stop/station IDs or coordinates based on addresses and points of interest validated by the location service or
coordinates freely defined by the client.
Read more about this in section 2.12. "Trip Search (trip)" of HAFAS ReST Documentation.
Read more about this in section 2.12. "Trip Search (trip)" of HAFAS ReST Documentation.
### Args:
* accessId (str): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
@@ -156,8 +132,8 @@ def trip_find(accessId: str,
* maxChangeTime (int, optional): Maximum change time at stop in minutes. Defaults to None.
* addChangeTime (int, optional): This amount of minutes is added to the change time at each stop. Defaults to None.
* maxChange (int, optional): Maximum number of changes. In range 0-11. Defaults to None.
* date (str, optional): Sets the start date for which the departures shall be retrieved. Represented in the format `YYYY-MM-DD`. By default the current server date is used. Defaults to None.
* time (str, optional): Sets the start time for which the departures shall be retrieved. Represented in the format `hh:mm[:ss]` in 24h nomenclature. Seconds will be ignored for requests. By default the current server time is used. Defaults to None.
* date (Union[str, datetime], optional): Sets the start date for which the departures shall be retrieved. Represented in the format `YYYY-MM-DD`. By default the current server date is used. Defaults to None.
* time (Union[str, datetime], optional): Sets the start time for which the departures shall be retrieved. Represented in the format `hh:mm[:ss]` in 24h nomenclature. Seconds will be ignored for requests. By default the current server time is used. Defaults to None.
* searchForArrival (bool, optional): If set, the date and time parameters specify the arrival time for the trip search instead of the departure time. Defaults to False.
* numF (int, optional): Minimum number of trips after the search time. Sum of numF and numB has to be less or equal 6. Read more about this in HAFAS ReST Documentation. In range 1-6. Defaults to None.
* numB (int, optional): Minimum number of trips before the search time. Sum of numF and numB has to be less or equal 6. Read more about this in HAFAS ReST Documentation. In range 0-6. Defaults to None.
@@ -220,14 +196,10 @@ def trip_find(accessId: str,
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
if json:
headers = {"Accept": "application/json"}
else:
headers = {"Accept": "application/xml"}
"""
payload = {}
headers = {"Accept": "application/json"} if json else {"Accept": "application/xml"}
for var, val in locals().items():
if str(var) == "date":
@@ -238,21 +210,16 @@ def trip_find(accessId: str,
payload[str(var)] = val
elif str(var) == "time":
if val != None:
if isinstance(val, datetime):
payload[str(var)] = val.strftime("%H:%M")
else:
payload[str(var)] = val
payload[str(var)] = (
val.strftime("%H:%M") if isinstance(val, datetime) else val
)
elif str(var) == "rtMode":
if val != None:
payload["rtMode"] = val.upper()
elif str(var) not in ["json", "headers", "payload"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/trip", params=payload, headers=headers)
# Exceptions checker moved to normal methods
# and exceptions will no longer raise in raw ones.
# find_exception(output.json())
if json:
return output.json()
else:
return xmlparse(output.content)
return output.json() if json else xmlparse(output.content)

103
src/pyrmv/raw/trip_recon.py Normal file
View File

@@ -0,0 +1,103 @@
from datetime import datetime
from typing import Union
from requests import get
from xmltodict import parse as xmlparse
try:
from typing import Literal
except ImportError:
from typing_extensions import Literal
def trip_recon(
accessId: str,
ctx: str,
json: bool = True,
poly: bool = False,
polyEnc: Literal["DLT", "GPA", "N"] = "N",
date: Union[str, datetime, None] = None,
useCombinedComparison: Union[bool, None] = None,
acceptGaps: Union[bool, None] = None,
allowDummySections: Union[bool, None] = None,
flagAllNonReachable: Union[bool, None] = None,
matchCatStrict: Union[bool, None] = None,
matchIdNonBlank: Union[bool, None] = None,
matchIdStrict: Union[bool, None] = None,
matchNumStrict: Union[bool, None] = None,
matchRtType: Union[bool, None] = None,
enableRtFullSearch: Union[bool, None] = None,
enableReplacements: Union[bool, None] = None,
arrL: Union[int, None] = None,
arrU: Union[int, None] = None,
depL: Union[int, None] = None,
depU: Union[int, None] = None,
passlist: bool = False,
showPassingPoints: bool = False,
rtMode: Union[Literal["FULL", "INFOS", "OFF", "REALTIME", "SERVER_DEFAULT"], None] = None,
eco: bool = False,
ecoCmp: bool = False,
ecoParams: Union[str, None] = None,
tariff: Union[bool, None] = None,
trafficMessages: Union[bool, None] = None,
travellerProfileData: Union[str, None] = None,
) -> dict:
"""Reconstructing a trip can be achieved using the reconstruction context provided by any trip result in the
ctxRecon attribute of Trip element. The result will be a true copy of the original trip search result given
that the underlying data did not change.
Read more about this in section 2.17. "Reconstruction (recon)" of HAFAS ReST Documentation.
### Args:
* accessId (str): Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
* ctx (str): Specifies the reconstruction context.
* json (bool, optional): Whether response should be retrieved as JSON. XML is returned if False. Defaults to True.
* poly (bool, optional): Enables/disables the calculation of the polyline for each leg of the trip except any GIS route. Defaults to False.
* polyEnc (Literal["DLT", "GPA", "N"], optional): Defines encoding of the returned polyline. Possible values are "N" (no encoding / compression), "DLT" (delta to the previous coordinate), "GPA" (Google encoded polyline format). Defaults to "N".
* date (Union[str, datetime], optional): Sets the start date for which the departures shall be retrieved. Represented in the format `YYYY-MM-DD`. This parameter will force the ser-vice to reconstruct the trip on that specific date. If the trip is not available on that date, because it does not operate, the error code SVC_NO_RESULT will be returned. Defaults to None.
* useCombinedComparison (bool, optional): Compare based on combined output name - `False`: Compare parameters (category, line, train number) individually. Defaults to None.
* acceptGaps (bool, optional): Accept an incomplete description of the connection (with gaps) i.e. missing walks/transfers. Defaults to None.
* allowDummySections (bool, optional): Allow a partial reconstruction that will not lead to a reconstruction failure if sections are not reconstructable. Instead, for theses inconstructable sections, dummy sections will be created in the result. Defaults to None.
* flagAllNonReachable (bool, optional): Should all non-reachable journeys be flagged (`True`), or only the first one encountered? Defaults to None.
* matchCatStrict (bool, optional): Should the category (Gattung) match exactly? Only applicable if `useCombinedComparison` is `False`. Defaults to None.
* matchIdNonBlank (bool, optional): Should the train identifier (Zugbezeichner) without whitespace match? Defaults to None.
* matchIdStrict (bool, optional): Should the train identifier (Zugbezeichner) match exactly? Defaults to None.
* matchNumStrict (bool, optional): Should the train number (Zugnummer) match exactly? Only applicable if `useCombinedComparison` is `False`. Defaults to None.
* matchRtType (bool, optional): Should the realtime type that journeys are based on (e.g. SOLL, IST, additional, deviation, …) be considered? Defaults to None.
* enableRtFullSearch (bool, optional): By default, the reconstruction request makes one attempt for each journey within the scheduled data. However, the scheduled data may not necessarily reflect basic realtime properties of the journeys therein. In such a case, one may enable a two-step approach which we call "full search", i.e. search for matching journeys in the scheduled data in a first step. If this fails, then search for matching journeys in the realtime data. Defaults to None.
* enableReplacements (bool, optional): If set to true replaces cancelled journeys with their replacement journeys if possible. Defaults to None.
* arrL (int, optional): Lower deviation in minutes within interval [0, 720] indicating "how much earlier than original arrival". Defaults to None.
* arrU (int, optional): Upper deviation in minutes within interval [0, 720] indicating "how much later than original arrival". Defaults to None.
* depL (int, optional): Lower deviation in minutes within interval [0, 720] indicating "how much earlier than original departure". Defaults to None.
* depU (int, optional): Upper deviation in minutes within interval [0, 720] indicating "how much later than original departure". Defaults to None.
* passlist (bool, optional): Enables/disables the return of the passlist for each leg of the trip. Defaults to False.
* showPassingPoints (bool, optional): Enables/disables the return of stops having no alighting and boarding in its passlist for each leg of the trip. Needs passlist parameter enabled. Defaults to False.
* rtMode (Literal["FULL", "INFOS", "OFF", "REALTIME", "SERVER_DEFAULT"], optional): Set the realtime mode to be used. Read more about this in HAFAS ReST Documentation. Defaults to None.
* eco (bool, optional): Enables/disables eco value calculation. Defaults to False.
* ecoCmp (bool, optional): Enables/disables eco comparison. Defaults to False.
* ecoParams (str, optional): Provide additional eco parameters. Values vary. Defaults to None.
* tariff (bool, optional): Enables/disables the output of tariff data. The default is configurable via provisioning. Defaults to None.
* trafficMessages (bool, optional): Enables/disables the output of traffic messages. The default is configurable via provisioning. Defaults to None.
* travellerProfileData (str, optional): Traveller profile data. Structure depends on set up. Defaults to None.
### Returns:
* dict: Output from RMV. Dict will contain "errorCode" and "errorText" if exception occurs.
"""
payload = {}
headers = {"Accept": "application/json"} if json else {"Accept": "application/xml"}
for var, val in locals().items():
if str(var) == "date":
if val != None:
if isinstance(val, datetime):
payload[str(var)] = val.strftime("%Y-%m-%d")
else:
payload[str(var)] = val
elif str(var) not in ["json", "headers", "payload"]:
if val != None:
payload[str(var)] = val
output = get("https://www.rmv.de/hapi/recon", params=payload, headers=headers)
return output.json() if json else xmlparse(output.content)

View File

@@ -0,0 +1,3 @@
from .find_exception import find_exception
from .journey_ref_converter import ref_upgrade
from .weekdays_bitmask import weekdays_bitmask

View File

@@ -1,22 +1,46 @@
from pyrmv.errors.api_errors import ApiAuthError, ApiFormatError, ApiParamError, ApiQuotaError, ApiTooManyRequests
from pyrmv.errors.int_errors import IntError, IntGatewayError, IntTimeoutError
from pyrmv.errors.ps_errors import PsIncorrectParamError
from pyrmv.errors.sot_errors import SotAllTrainsFilteredError, SotAlreadyArrivedError, SotCancelledError, SotNotStartedError, SotStayOnTripError
from pyrmv.errors.svc_errors import SvcContextError, SvcDatetimeError, SvcDatetimePeriodError, SvcLocationArrivalError, SvcLocationDepartureError, SvcLocationEqualError, SvcLocationError, SvcLocationNearError, SvcLocationViaError, SvcNoMatchError, SvcNoResultError, SvcProductError, SvcSearchError
from pyrmv.errors.unknown_error import UnknownError
from pyrmv.errors import (
ApiAuthError,
ApiFormatError,
ApiParamError,
ApiQuotaError,
ApiTooManyRequests,
IntError,
IntGatewayError,
IntTimeoutError,
PsIncorrectParamError,
SotAllTrainsFilteredError,
SotAlreadyArrivedError,
SotCancelledError,
SotNotStartedError,
SotStayOnTripError,
SvcContextError,
SvcDatetimeError,
SvcDatetimePeriodError,
SvcLocationArrivalError,
SvcLocationDepartureError,
SvcLocationEqualError,
SvcLocationError,
SvcLocationNearError,
SvcLocationViaError,
SvcNoMatchError,
SvcNoResultError,
SvcProductError,
SvcSearchError,
UnknownError,
)
def find_exception(data: dict):
"""Scan returned dict for errorCode from RMV.
Raises different exceptions if errorCode is not None.
Raises different exceptions if errorCode is not None.
### Args:
* data (dict): Response from RMV as a dict.
### Raises:
* Any: Formatted as "errorCode -> errorText" if ApiParamError and UnknownError or as a single massage for others.
"""
"""
if "errorCode" in data:
if data["errorCode"] == "API_AUTH":
raise ApiAuthError()
@@ -25,7 +49,7 @@ def find_exception(data: dict):
elif data["errorCode"] == "API_TOO_MANY_REQUESTS":
raise ApiTooManyRequests()
elif data["errorCode"] == "API_PARAM":
raise ApiParamError(errorCode=data["errorCode"], errorText=data["errorText"])
@@ -99,4 +123,4 @@ def find_exception(data: dict):
raise PsIncorrectParamError()
else:
raise UnknownError(errorCode=data["errorCode"], errorText=data["errorText"])
raise UnknownError(errorCode=data["errorCode"], errorText=data["errorText"])

View File

@@ -0,0 +1,26 @@
def ref_upgrade(ref: str) -> str:
"""This function converts older journey refs to the newer ones.
### WARNING
This function will be deprecated as soon as RMV updates their API
### Args:
* ref (`str`): Old ref like this one: `2|#VN#1#ST#1700765441#PI#0#ZI#160749#TA#0#DA#241123#1S#3004646#1T#2228#LS#3006907#LT#2354#PU#80#RT#1#CA#S30#ZE#S1#ZB# S1#PC#3#FR#3004646#FT#2228#TO#3006907#TT#2354#`
### Raises:
* `KeyError`: Some required keys are not found in the ref provided
### Returns:
* `str`: Ref of the new type
"""
items = "|".join(ref.split("|")[1:]).strip("#").split("#")
result = {items[i]: items[i + 1] for i in range(0, len(items), 2)}
for required in ["VN", "ZI", "TA", "PU"]:
if required not in result:
raise KeyError(
f"Required key {required} in the old journey ref is not found during conversion to the newer journey ref"
)
return "|".join([result["VN"], result["ZI"], result["TA"], result["PU"]])

View File

@@ -9,13 +9,10 @@ def weekdays_bitmask(data: OrderedDict[str, bool]) -> str:
### Returns:
* str: _description_
"""
output = ""
"""
if len(data) != 7:
raise ValueError("OrderedDict must be formatted as follows: OrderedDict(Monday=bool, Tuesday=bool, Wednesday=bool, Thursday=bool, Friday=bool, Saturday=bool, Sunday=bool)")
for day in data:
if data[day]:
output += "1"
else:
output += "0"
return output
raise ValueError(
"OrderedDict must be formatted as follows: OrderedDict(Monday=bool, Tuesday=bool, Wednesday=bool, Thursday=bool, Friday=bool, Saturday=bool, Sunday=bool)"
)
return "".join("1" if data[day] else "0" for day in data)

36
tests/conftest.py Normal file
View File

@@ -0,0 +1,36 @@
from os import environ
from typing import List
import pytest
from pyrmv import Client
@pytest.fixture()
def api_token() -> str:
return environ.get("RMV_TOKEN")
@pytest.fixture()
def api_client(api_token: str) -> Client:
return Client(api_token)
@pytest.fixture()
def sample_stop_id() -> str:
return "A=1@O=Frankfurt (Main) Taunusanlage@X=8668765@Y=50113478@U=80@L=3000011@"
@pytest.fixture()
def sample_journey_id() -> str:
return "1|12709|0|80"
@pytest.fixture()
def sample_origin() -> List[str]:
return ["50.084659", "8.785948"]
@pytest.fixture()
def sample_destination() -> List[float]:
return [50.1233048, 8.6129742]

82
tests/test_client.py Normal file
View File

@@ -0,0 +1,82 @@
from datetime import datetime, timedelta
from typing import List
import pytest
from pyrmv import Client, enums
from pyrmv.classes import Journey, Message, Stop, Trip
from pyrmv.classes.board import BoardArrival, BoardDeparture
def test_board_arrival(api_client: Client, sample_stop_id: str):
assert isinstance(
api_client.board_arrival(id=sample_stop_id, journeys_max=3), BoardArrival
)
def test_board_departure(api_client: Client, sample_stop_id: str):
assert isinstance(
api_client.board_departure(id=sample_stop_id, journeys_max=3), BoardDeparture
)
def test_him_search(api_client: Client):
assert isinstance(
api_client.him_search(date_end=datetime.now() + timedelta(days=10))[0], Message
)
def test_journey_detail(api_client: Client, sample_journey_id: str):
assert (
api_client.journey_detail(
sample_journey_id,
real_time_mode=enums.RealTimeMode.FULL,
),
Journey,
)
def test_stop_by_coords(api_client: Client, sample_origin: List[str]):
assert isinstance(
api_client.stop_by_coords(sample_origin[0], sample_origin[1], max_number=3)[0], Stop
)
def test_stop_by_id(api_client: Client, sample_stop_id: str):
assert isinstance(api_client.stop_by_id(sample_stop_id), Stop)
def test_trip_find(
api_client: Client, sample_origin: List[str], sample_destination: List[float]
):
assert isinstance(
api_client.trip_find(
origin_coord_lat=sample_origin[0],
origin_coord_lon=sample_origin[1],
destination_coord_lat=sample_destination[0],
destination_coord_lon=sample_destination[1],
messages=True,
)[0],
Trip,
)
def test_trip_recon(
api_client: Client, sample_origin: List[str], sample_destination: List[float]
):
assert isinstance(
api_client.trip_recon(
api_client.trip_find(
origin_coord_lat=sample_origin[0],
origin_coord_lon=sample_origin[1],
destination_coord_lat=sample_destination[0],
destination_coord_lon=sample_destination[1],
messages=True,
)[0],
)[0],
Trip,
)
def test_stop_by_name(api_client: Client):
assert isinstance(api_client.stop_by_name("Hauptwache", max_number=1)[0], Stop)

7
tests/test_raw.py Normal file
View File

@@ -0,0 +1,7 @@
import pytest
from pyrmv.raw import stop_by_name
def test_stop_by_name(api_token: str):
assert isinstance(stop_by_name(api_token, "Hauptwache", maxNo=1), dict)

23
tox.ini Normal file
View File

@@ -0,0 +1,23 @@
[tox]
minversion = 3.8.0
envlist = py38, py39, py310, py311
isolated_build = true
[gh-actions]
python =
3.8: py38
3.9: py39
3.10: py310
3.11: py311
[testenv]
setenv =
PYTHONPATH = {toxinidir}
passenv =
RMV_TOKEN
deps =
-r{toxinidir}/requirements/_.txt
-r{toxinidir}/requirements/dev.txt
commands =
pytest --basetemp={envtmpdir} --cov=pyrmv --cov-report term-missing

39
wiki/Home.md Normal file
View File

@@ -0,0 +1,39 @@
# PythonRMV
Welcome to the project's Wiki.
This module aims to provide eased access to RMV's OpenData API endpoints and enable some home-projects to show the data about public transit state at the moment. As for now, async is not supported and is not necessarily planned in the future, so bigger projects should consider this before using this module in the first place.
## Basic concepts behind
So the module `pyrmv` has two options to choose from when it comes to the usage:
1. Using higher-level methods of the class [pyrmv.Client](https://git.end-play.xyz/profitroll/PythonRMV/wiki/Client). These methods provide pythonic objects, can throw exceptions and are overall pretty neat.
2. Using raw functions from [pyrmv.raw](https://git.end-play.xyz/profitroll/PythonRMV/wiki/Raw-Functions). These functions are basically a small interface for HTTP requests that happen in the background and have little to no processing behind the scenes.
Your preferred variant depends on the use case, but usually higher-level methods of the Client should be the match.
## Objects
This module does **not** use the [FPTF](https://github.com/public-transport/friendly-public-transport-format) because it aims to give full access to the API RMV provides, thus objects Client gives you will contain a bit more information.
These objects are implemented in pyrmv:
* [BoardArrival](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.BoardArrival)
* [BoardDeparture](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.BoardDeparture)
* [LineArrival](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.LineArrival)
* [LineDeparture](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.LineDeparture)
* [Gis](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Gis)
* [Journey](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Journey)
* [Leg](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Leg)
* [Channel](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Channel)
* [Message](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Message)
* [Url](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Url)
* [Stop](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Stop)
* [StopTrip](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.StopTrip)
* [Trip](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Trip)
* ~~[Ticket](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Ticket)~~ (WIP)
## Note for bigger projects
As you may already know, bigger projects like [Öffi](https://gitlab.com/oeffi/oeffi) and [DB Navigator](https://play.google.com/store/apps/details?id=de.hafas.android.db) use NVV's API instead of RMV's for navigation and public transit querying. Reasons behind this are clear as day and from perspective of pyrmv it's highly recommended you also choose that way, because RMV loves to change or break their API in unexpected places and does not cooperate with developers well enough when they do so.

1
wiki/Raw-Functions.md Normal file
View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

21
wiki/_Sidebar.md Normal file
View File

@@ -0,0 +1,21 @@
# [Home](https://git.end-play.xyz/profitroll/PythonRMV/wiki)
## Classes
* [Client](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client)
## Methods
* [board_arrival](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client.board_arrival)
* [board_departure](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client.board_departure)
* [him_search](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client.him_search)
* [journey_detail](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client.journey_detail)
* [stop_by_coords](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client.stop_by_coords)
* [stop_by_id](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client.stop_by_id)
* [stop_by_name](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client.stop_by_name)
* [trip_find](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client.trip_find)
* [trip_recon](https://git.end-play.xyz/profitroll/PythonRMV/wiki/classes.Client.trip_recon)
## Raw functions
* [List of raw functions](https://git.end-play.xyz/profitroll/PythonRMV/wiki/Raw-Functions)

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

1
wiki/classes/Channel.md Normal file
View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1,31 @@
# Client
You are now viewing the main class of the module, all available higher-level methods can be found here.
This page is about the Client class, which exposes high-level methods for an easy access to the API.
```py
from pyrmv import Client
client = Client("SampleAPIKey")
print(client.stop_by_id("A=1@O=Offenbach (Main)-Zentrum Marktplatz\/Frankf. Straße@X=8764456@Y=50105181@U=80@L=3002510@"))
```
## Details
### Parameters
* access_key (`str`) Access ID for identifying the requesting client. Get your key on [RMV website](https://opendata.rmv.de/site/start.html).
### Methods
* [board_arrival](https://git.end-play.xyz/profitroll/PythonRMV/wiki/board_arrival) -> `BoardArrival`
* [board_departure](https://git.end-play.xyz/profitroll/PythonRMV/wiki/board_departure) -> `BoardDeparture`
* [him_search](https://git.end-play.xyz/profitroll/PythonRMV/wiki/him_search) -> `List[Message]`
* [journey_detail](https://git.end-play.xyz/profitroll/PythonRMV/wiki/journey_detail) -> `Journey`
* [stop_by_coords](https://git.end-play.xyz/profitroll/PythonRMV/wiki/stop_by_coords) -> `List[Stop]`
* [stop_by_id](https://git.end-play.xyz/profitroll/PythonRMV/wiki/stop_by_id) -> `Union[Stop, None]`
* [stop_by_name](https://git.end-play.xyz/profitroll/PythonRMV/wiki/stop_by_name) -> `List[Stop]`
* [trip_find](https://git.end-play.xyz/profitroll/PythonRMV/wiki/trip_find) -> `List[Trip]`
* [trip_recon](https://git.end-play.xyz/profitroll/PythonRMV/wiki/trip_recon) -> `List[Trip]`

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

1
wiki/classes/Gis.md Normal file
View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

1
wiki/classes/Journey.md Normal file
View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

1
wiki/classes/Leg.md Normal file
View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

1
wiki/classes/Message.md Normal file
View File

@@ -0,0 +1 @@
Docs are not available yet. Please, use the linting in your IDE until the documentation is there.

Some files were not shown because too many files have changed in this diff Show More