def journeys_from_leg( self, origin: Leg, destination: Union[Station, str], via: List[Union[Station, str]] = [], min_change_time: int = 0, max_changes: int = -1, products: Dict[str, bool] = {}, ) -> List[Journey]: """ Returns possible journeys from a leg to a destination Possible journeys between two destinations are calculated by HaFAS and returned. It's also possible to add multiple via stations. :param origin: FPTF `Leg` object from where to search :param destination: FPTF `Station` object or ID of destination/ending station :param via: (optional) List of via stations. The route is calculated via all of these stations in the order of the list. The stations have to be a FPTF `Station` object or the ID of the station. The default is no via stations. :param min_change_time: (optional) Minimum transfer/change time at each station. Default is the default that HaFAS specifies internal. :param max_changes: (optional) Maximum number of changes. Default is unlimited. :param products: (optional) Dict of product name(s) and whether it should be enabled or not. Modifies the default products specified in the profile. :return: List of FPTF `Journey` objects """ if not isinstance(destination, Station): destination = Station(destination) for via_station in via: if not isinstance(via_station, Station): via[via.index(via_station)] = Station(via_station) body = self.profile.format_search_from_leg_request( origin, destination, via, min_change_time, max_changes, products) res = self.profile.request(body) return self.profile.parse_journeys_request(res)
def parse_lid_to_station(self: ProfileInterface, lid: str, name: str = "", latitude: float = 0, longitude: float = 0) -> Station: """ Parses the LID given by HaFAS to a station object :param lid: Location identifier (given by HaFAS) :param name: Station name (optional, if not given, LID is used) :param latitude: Latitude of the station (optional, if not given, LID is used) :param longitude: Longitude of the station (optional, if not given, LID is used) :return: Parsed LID as station object """ parsedLid = self.parse_lid(lid) if latitude == 0 and longitude == 0 and parsedLid['X'] and parsedLid[ 'Y']: latitude = float(float(parsedLid['Y']) / 1000000) longitude = float(float(parsedLid['X']) / 1000000) return Station(id=parsedLid['L'], lid=lid, name=name or parsedLid['O'], latitude=latitude, longitude=longitude)
def test_db_departures_parsing(): directory = os.path.dirname(os.path.realpath(__file__)) raw_hafas_json_file = open(directory + "/departures_raw.json", "r") hafas_response = PyTestHafasResponse(raw_hafas_json_file.read()) raw_hafas_json_file.close() correct_station_board_legs = [ StationBoardLeg( id='1|200921|0|80|5082020', name='IC 2055', direction='Stralsund Hbf', station=Station( id='8098160', lid= 'A=1@O=Berlin Hbf (tief)@X=13369549@Y=52525589@U=80@L=8098160@', name='Berlin Hbf (tief)', latitude=52.525589, longitude=13.369549), date_time=DBProfile().timezone.localize( datetime.datetime(2020, 8, 5, 18, 16)), cancelled=False, delay=datetime.timedelta(seconds=0), platform='6') ] assert DBProfile().parse_station_board_request( hafas_response, "d") == correct_station_board_legs
def test_db_locations_parsing(): directory = os.path.dirname(os.path.realpath(__file__)) raw_hafas_json_file = open(directory + "/locations_raw.json", "r") hafas_response = PyTestHafasResponse(raw_hafas_json_file.read()) raw_hafas_json_file.close() correct_locations = [ Station(id='008000207', name='Köln Hbf', latitude=50.942823, longitude=6.959197), Station(id="008096022", name='KÖLN', latitude=50.941312, longitude=6.967206) ] assert DBProfile().parse_location_request( hafas_response) == correct_locations
def arrivals( self, station: Union[Station, str], date: datetime.datetime, max_trips: int = -1, duration: int = -1, products: Dict[str, bool] = {}, direction: Optional[Union[Station, str]] = None) -> List[StationBoardLeg]: """ Returns arriving trips at the specified station To get detailed information on the trip use the `trip` method with the id :param station: FPTF `Station` object or ID of station :param date: Date and Time when to search :param max_trips: (optional) Maximum number of trips to be returned. Default is "whatever HaFAS wants" :param duration: (optional) Minutes after `date` in which is search is made. Default is "whatever HaFAS wants" :param products: (optional) Dict of product name(s) and whether it should be enabled or not. Modifies the default products specified in the profile. :param direction: (optional) Direction (end) station of the vehicle. Default is any direction station is allowed :return: List of FPTF `StationBoardLeg` objects with arriving trips """ if not isinstance(station, Station): station = Station(id=station) if not isinstance(direction, Station) and direction is not None: direction = Station(id=direction) date = self.profile.transform_datetime_parameter_timezone(date) body = self.profile.format_station_board_request( station, StationBoardRequestType.ARRIVAL, date, max_trips, duration, products, direction) res = self.profile.request(body) return self.profile.parse_station_board_request(res, "a")
def test_vsn_departures_parsing(): directory = os.path.dirname(os.path.realpath(__file__)) raw_hafas_json_file = open(directory + "/departures_raw.json", "r") hafas_response = PyTestHafasResponse(raw_hafas_json_file.read()) raw_hafas_json_file.close() correct_station_board_legs = [ StationBoardLeg(id='1|265947|0|80|1082020', name='IC 2315', direction='Frankfurt(Main) Hbf', station=Station(id='8000050', name='Bremen Hbf', latitude=53.083478, longitude=8.813833), date_time=VSNProfile().timezone.localize( datetime.datetime(2020, 8, 1, 17, 44)), cancelled=False, delay=datetime.timedelta(seconds=3480), platform='8') ] assert VSNProfile().parse_station_board_request( hafas_response, "d") == correct_station_board_legs
def test_db_trips_parsing(): directory = os.path.dirname(os.path.realpath(__file__)) raw_hafas_json_file = open(directory + "/trip_raw.json", "r") hafas_response = PyTestHafasResponse(raw_hafas_json_file.read()) raw_hafas_json_file.close() correct_trip = Leg( id='1|227083|0|80|5082020', origin=Station( id='8002753', lid='A=1@O=Hennef(Sieg)@X=7284588@Y=50773331@U=80@L=8002753@', name='Hennef(Sieg)', latitude=50.773331, longitude=7.284588), destination=Station( id='8000084', lid='A=1@O=Düren@X=6482454@Y=50809513@U=80@L=8000084@', name='Düren', latitude=50.809513, longitude=6.482454 ), departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 2)), arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 17)), mode=Mode.TRAIN, name='S 19', cancelled=False, distance=None, departure_delay=None, departure_platform='2', arrival_delay=None, arrival_platform='5', stopovers=[ Stopover( stop=Station( id='8002753', lid='A=1@O=Hennef(Sieg)@X=7284588@Y=50773331@U=80@L=8002753@', name='Hennef(Sieg)', latitude=50.773331, longitude=7.284588 ), cancelled=False, arrival=None, arrival_delay=None, arrival_platform=None, departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 2)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8005556', lid='A=1@O=Siegburg/Bonn@X=7203029@Y=50793916@U=80@L=8005556@', name='Siegburg/Bonn', latitude=50.793916, longitude=7.203029 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 6)), arrival_delay=None, arrival_platform='1', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 7)), departure_delay=None, departure_platform='1' ), Stopover( stop=Station( id='8000135', lid='A=1@O=Troisdorf@X=7150892@Y=50813926@U=80@L=8000135@', name='Troisdorf', latitude=50.813926, longitude=7.150892 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 12)), arrival_delay=None, arrival_platform='1', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 13)), departure_delay=None, departure_platform='1' ), Stopover( stop=Station( id='8005629', lid='A=1@O=Spich@X=7114917@Y=50826727@U=80@L=8005629@', name='Spich', latitude=50.826727, longitude=7.114917 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 15)), arrival_delay=None, arrival_platform='1', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 16)), departure_delay=None, departure_platform='1' ), Stopover( stop=Station( id='8004873', lid='A=1@O=Porz-Wahn@X=7079266@Y=50858135@U=80@L=8004873@', name='Porz-Wahn', latitude=50.858135, longitude=7.079266 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 19)), arrival_delay=None, arrival_platform='1', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 19)), departure_delay=None, departure_platform='1' ), Stopover( stop=Station( id='8003330', lid='A=1@O=Köln/Bonn Flughafen@X=7119304@Y=50878900@U=80@L=8003330@', name='Köln/Bonn Flughafen', latitude=50.8789, longitude=7.119304 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 23)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 24)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8003358', lid='A=1@O=Köln Frankfurter Straße@X=7051264@Y=50915217@U=80@L=8003358@', name='Köln Frankfurter Straße', latitude=50.915217, longitude=7.051264 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 29)), arrival_delay=None, arrival_platform='1', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 29)), departure_delay=None, departure_platform='1' ), Stopover( stop=Station( id='8003320', lid='A=1@O=Köln Trimbornstr@X=6996736@Y=50935856@U=80@L=8003320@', name='Köln Trimbornstr', latitude=50.935856, longitude=6.996736), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 34)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 34)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8083368', lid='A=1@O=Köln Messe/Deutz Gl. 9-10@X=6974640@Y=50941303@U=80@L=8083368@', name='Köln Messe/Deutz Gl. 9-10', latitude=50.941303, longitude=6.97464), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 36)), arrival_delay=None, arrival_platform='10', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 37)), departure_delay=None, departure_platform='10' ), Stopover( stop=Station( id='8000207', lid='A=1@O=Köln Hbf@X=6958730@Y=50943029@U=80@L=8000207@', name='Köln Hbf', latitude=50.943029, longitude=6.95873 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 39)), arrival_delay=None, arrival_platform='11 B-C', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 40)), departure_delay=None, departure_platform='11 B-C' ), Stopover( stop=Station( id='8003392', lid='A=1@O=Köln Hansaring@X=6952563@Y=50949133@U=80@L=8003392@', name='Köln Hansaring', latitude=50.949133, longitude=6.952563 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 42)), arrival_delay=None, arrival_platform='1', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 42)), departure_delay=None, departure_platform='1' ), Stopover( stop=Station( id='8000208', lid='A=1@O=Köln-Ehrenfeld@X=6917280@Y=50951533@U=80@L=8000208@', name='Köln-Ehrenfeld', latitude=50.951533, longitude=6.91728), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 45)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 46)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8003375', lid='A=1@O=Köln-Müngersdorf Technologiepark@X=6888200@Y=50948396@U=80@L=8003375@', name='Köln-Müngersdorf Technologiepark', latitude=50.948396, longitude=6.8882 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 48)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 49)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8003732', lid='A=1@O=Lövenich@X=6834436@Y=50942930@U=80@L=8003732@', name='Lövenich', latitude=50.94293, longitude=6.834436 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 51)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 52)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8003383', lid='A=1@O=Köln-Weiden West@X=6815136@Y=50940899@U=80@L=8003383@', name='Köln-Weiden West', latitude=50.940899, longitude=6.815136 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 53)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 54)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8002389', lid='A=1@O=Frechen-Königsdorf@X=6777849@Y=50936503@U=80@L=8002389@', name='Frechen-Königsdorf', latitude=50.936503, longitude=6.777849 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 56)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 12, 57)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8000178', lid='A=1@O=Horrem@X=6713495@Y=50916250@U=80@L=8000178@', name='Horrem', latitude=50.91625, longitude=6.713495 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 0)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 1)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8005575', lid='A=1@O=Sindorf@X=6681107@Y=50903711@U=80@L=8005575@', name='Sindorf', latitude=50.903711, longitude=6.681107 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 3)), arrival_delay=None, arrival_platform='1', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 3)), departure_delay=None, departure_platform='1' ), Stopover( stop=Station( id='8001264', lid='A=1@O=Buir@X=6574513@Y=50862405@U=80@L=8001264@', name='Buir', latitude=50.862405, longitude=6.574513 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 9)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 10)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8003990', lid='A=1@O=Merzenich@X=6518051@Y=50840031@U=80@L=8003990@', name='Merzenich', latitude=50.840031, longitude=6.518051 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 13)), arrival_delay=None, arrival_platform='2', departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 13)), departure_delay=None, departure_platform='2' ), Stopover( stop=Station( id='8000084', lid='A=1@O=Düren@X=6482454@Y=50809513@U=80@L=8000084@', name='Düren', latitude=50.809513, longitude=6.482454 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 5, 13, 17)), arrival_delay=None, arrival_platform='5', departure=None, departure_delay=None, departure_platform=None ) ] ) assert DBProfile().parse_trip_request(hafas_response) == correct_trip
def test_db_journey_parsing(): directory = os.path.dirname(os.path.realpath(__file__)) raw_hafas_json_file = open(directory + "/journey_raw.json", "r") hafas_response = PyTestHafasResponse(raw_hafas_json_file.read()) raw_hafas_json_file.close() correct_journey = Journey( id='¶HKI¶T$A=1@O=Siegburg/Bonn@L=8005556@a=128@$A=1@O=Troisdorf@L=8000135@a=128@$202008081507$202008081512$S 19$$1$$$', date=datetime.date(2020, 8, 8), duration=datetime.timedelta(seconds=300), legs=[Leg( id='1|227361|0|80|8082020', origin=Station( id='8005556', lid='A=1@O=Siegburg/Bonn@X=7203029@Y=50793916@U=80@L=8005556@', name='Siegburg/Bonn', latitude=50.793916, longitude=7.203029), destination=Station( id='8000135', lid='A=1@O=Troisdorf@X=7150892@Y=50813926@U=80@L=8000135@', name='Troisdorf', latitude=50.813926, longitude=7.150892), departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 8, 15, 7)), arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 8, 15, 12)), mode=Mode.TRAIN, name='S 19', cancelled=False, distance=None, departure_delay=datetime.timedelta(seconds=240), departure_platform='1', arrival_delay=datetime.timedelta(seconds=240), arrival_platform='1', stopovers=[Stopover( stop=Station( id='8005556', lid='A=1@O=Siegburg/Bonn@X=7203029@Y=50793916@U=80@L=8005556@', name='Siegburg/Bonn', latitude=50.793916, longitude=7.203029 ), cancelled=False, arrival=None, arrival_delay=None, arrival_platform=None, departure=DBProfile().timezone.localize(datetime.datetime(2020, 8, 8, 15, 7)), departure_delay=datetime.timedelta(seconds=240), departure_platform='1' ), Stopover( stop=Station( id='8000135', lid='A=1@O=Troisdorf@X=7150892@Y=50813926@U=80@L=8000135@', name='Troisdorf', latitude=50.813926, longitude=7.150892 ), cancelled=False, arrival=DBProfile().timezone.localize(datetime.datetime(2020, 8, 8, 15, 12)), arrival_delay=datetime.timedelta(seconds=240), arrival_platform='1', departure=None, departure_delay=None, departure_platform=None ) ], )] ) assert DBProfile().parse_journey_request(hafas_response) == correct_journey
def test_vsn_journeys_parsing(): directory = os.path.dirname(os.path.realpath(__file__)) raw_hafas_json_file = open(directory + "/journeys_raw.json", "r") hafas_response = PyTestHafasResponse(raw_hafas_json_file.read()) raw_hafas_json_file.close() correct_journeys = [ Journey( id= '¶HKI¶T$A=1@O=Göttingen@L=8000128@a=128@$A=1@O=Lenglern@L=8003644@a=128@$202008090710$202008090719$ RB85$$1$$$', date=datetime.date(2020, 8, 9), duration=datetime.timedelta(seconds=540), legs=[ Leg(id='1|147532|0|80|9082020', origin=Station(id='8000128', name='Göttingen', latitude=51.536812, longitude=9.926069), destination=Station(id='8003644', name='Lenglern', latitude=51.588428, longitude=9.871199), departure=VSNProfile().timezone.localize( datetime.datetime(2020, 8, 9, 7, 10)), arrival=VSNProfile().timezone.localize( datetime.datetime(2020, 8, 9, 7, 19)), mode=Mode.TRAIN, name='RB85', cancelled=False, distance=None, departure_delay=datetime.timedelta(seconds=0), departure_platform='4', arrival_delay=datetime.timedelta(seconds=60), arrival_platform='1', stopovers=[ Stopover(stop=Station(id='8000128', name='Göttingen', latitude=51.536812, longitude=9.926069), cancelled=False, arrival=None, arrival_delay=None, arrival_platform=None, departure=VSNProfile().timezone.localize( datetime.datetime(2020, 8, 9, 7, 10)), departure_delay=datetime.timedelta(seconds=0), departure_platform=None), Stopover(stop=Station(id='8003644', name='Lenglern', latitude=51.588428, longitude=9.871199), cancelled=False, arrival=VSNProfile().timezone.localize( datetime.datetime(2020, 8, 9, 7, 19)), arrival_delay=datetime.timedelta(seconds=60), arrival_platform=None, departure=None, departure_delay=None, departure_platform=None) ]) ]) ] assert VSNProfile().parse_journeys_request( hafas_response) == correct_journeys