From a936795afa243d2f06e9710ca94d1b2c17b35a95 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Wed, 13 Nov 2024 20:05:01 +0100 Subject: [PATCH 01/20] add penality bike parking --- source/jormungandr/jormungandr/instance.py | 4 + .../jormungandr/interfaces/v1/Journeys.py | 5 + .../interfaces/v1/journey_common.py | 24 ++- .../interfaces/v1/serializer/status.py | 2 + source/jormungandr/jormungandr/park_modes.py | 75 +++++++ .../jormungandr/scenarios/distributed.py | 10 + .../jormungandr/street_network/__init__.py | 1 + .../jormungandr/street_network/bike.py | 198 ++++++++++++++++++ .../navitiacommon/default_values.py | 6 + .../navitiacommon/models/__init__.py | 8 + source/tyr/tyr/fields.py | 2 + source/tyr/tyr/resources.py | 18 ++ 12 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 source/jormungandr/jormungandr/park_modes.py create mode 100644 source/jormungandr/jormungandr/street_network/bike.py diff --git a/source/jormungandr/jormungandr/instance.py b/source/jormungandr/jormungandr/instance.py index 4f418570b7..b47ab6b227 100644 --- a/source/jormungandr/jormungandr/instance.py +++ b/source/jormungandr/jormungandr/instance.py @@ -820,6 +820,10 @@ def additional_parameters(self): additional_time_after_first_section_taxi = _make_property_getter('additional_time_after_first_section_taxi') additional_time_before_last_section_taxi = _make_property_getter('additional_time_before_last_section_taxi') + additional_time_after_first_section_bike = _make_property_getter('additional_time_after_first_section_bike') + additional_time_before_last_section_bike = _make_property_getter('additional_time_before_last_section_bike') + + max_walking_direct_path_duration = _make_property_getter('max_walking_direct_path_duration') max_bike_direct_path_duration = _make_property_getter('max_bike_direct_path_duration') max_bss_direct_path_duration = _make_property_getter('max_bss_direct_path_duration') diff --git a/source/jormungandr/jormungandr/interfaces/v1/Journeys.py b/source/jormungandr/jormungandr/interfaces/v1/Journeys.py index c1ad3f657f..85971f66c5 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/Journeys.py +++ b/source/jormungandr/jormungandr/interfaces/v1/Journeys.py @@ -826,6 +826,11 @@ def _set_specific_params(mod): if args.get('additional_time_before_last_section_taxi') is None: args['additional_time_before_last_section_taxi'] = mod.additional_time_before_last_section_taxi + if args.get('additional_time_after_first_section_bike') is None: + args['additional_time_after_first_section_bike'] = mod.additional_time_after_first_section_bike + if args.get('additional_time_before_last_section_bike') is None: + args['additional_time_before_last_section_bike'] = mod.additional_time_before_last_section_bike + if args.get('_stop_points_nearby_duration') is None: args['_stop_points_nearby_duration'] = mod.stop_points_nearby_duration diff --git a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py index e5f9bd866b..8406991c7f 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py +++ b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py @@ -30,7 +30,7 @@ # www.navitia.io from __future__ import absolute_import, print_function, unicode_literals, division -from jormungandr import i_manager, fallback_modes, partner_services, app +from jormungandr import i_manager, fallback_modes, partner_services, app, park_modes from jormungandr.interfaces.v1.ResourceUri import ResourceUri from datetime import datetime from jormungandr.resources_utils import ResourceUtc @@ -239,6 +239,14 @@ def __init__(self, output_type_serializer): action="append", help='Same as first_section_mode but for the last section.', ) + + parser_get.add_argument( + "park_mode[]", + type=OptionValue(park_modes.all_park_modes), + dest="origin_mode", + action="append", + help='Force the park mode if the first section is by bike\n' + ) # for retrocompatibility purpose, we duplicate (without []): parser_get.add_argument( "first_section_mode", @@ -506,6 +514,20 @@ def __init__(self, output_type_serializer): type=int, help="the additional time added to the taxi section, right before riding the taxi but after hopping off the public transit", ) + + + parser_get.add_argument( + "additional_time_after_first_section_bike", + type=int, + help="the additional time added to the bike section, right after riding the bike but before hopping on the public transit", + ) + + parser_get.add_argument( + "additional_time_before_last_section_bike", + type=int, + help="the additional time added to the bike section, right before riding the bike but after hopping off the public transit", + ) + parser_get.add_argument( "_pt_planner", type=OptionValue(['kraken', 'loki']), diff --git a/source/jormungandr/jormungandr/interfaces/v1/serializer/status.py b/source/jormungandr/jormungandr/interfaces/v1/serializer/status.py index cc7bcc410c..5695a5a4a7 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/serializer/status.py +++ b/source/jormungandr/jormungandr/interfaces/v1/serializer/status.py @@ -74,6 +74,8 @@ class ParametersSerializer(serpy.Serializer): max_extra_second_pass = Field(schema_type=int) additional_time_after_first_section_taxi = Field(schema_type=int) additional_time_before_last_section_taxi = Field(schema_type=int) + additional_time_after_first_section_bike = Field(schema_type=int) + additional_time_before_last_section_bike = Field(schema_type=int) max_walking_direct_path_duration = Field(schema_type=int) max_bike_direct_path_duration = Field(schema_type=int) max_bss_direct_path_duration = Field(schema_type=int) diff --git a/source/jormungandr/jormungandr/park_modes.py b/source/jormungandr/jormungandr/park_modes.py new file mode 100644 index 0000000000..1f33c9810f --- /dev/null +++ b/source/jormungandr/jormungandr/park_modes.py @@ -0,0 +1,75 @@ +# Copyright (c) 2001-2024, Hove and/or its affiliates. All rights reserved. +# +# This file is part of Navitia, +# the software to build cool stuff with public transport. +# +# Hope you'll enjoy and contribute to this project, +# powered by Hove (www.hove.com). +# Help us simplify mobility and open public transport: +# a non ending quest to the responsive locomotion way of traveling! +# +# LICENCE: This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# Stay tuned using +# twitter @navitia +# channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org +# https://groups.google.com/d/forum/navitia +# www.navitia.io +# +# + + +from enum import Enum +from navitiacommon import response_pb2 + + + +class ParkModes(Enum): + none = response_pb2.None + without_park = response_pb2.WithoutPark + with_park = response_pb2.WithPark + + + @classmethod + def modes_str(cls): + + return {e.name for e in cls} + + + @classmethod + def modes_enum(cls): + return set(cls) + + + @classmethod + def get_allowed_combinations_enums(cls): + def _combi(first_sections_modes, last_section_modes): + from itertools import product + + # cartesian product between two iterables + return set(product(first_sections_modes, last_section_modes)) + + return _combi(cls.modes_enum(), cls.modes_enum()) + + + @classmethod + def get_allowed_combinations_str(cls): + # python 2/3 portability + import six + allowed_combinations_enum = cls.get_allowed_combinations_enums() + # transform all enum to str + return set(six.moves.map(lambda modes: (modes[0].name, modes[1].name), allowed_combinations_enum)) + + +all_park_modes = ParkModes.modes_str() diff --git a/source/jormungandr/jormungandr/scenarios/distributed.py b/source/jormungandr/jormungandr/scenarios/distributed.py index addabb3469..602aaf5b69 100644 --- a/source/jormungandr/jormungandr/scenarios/distributed.py +++ b/source/jormungandr/jormungandr/scenarios/distributed.py @@ -589,6 +589,16 @@ def graphical_isochrones(self, request, instance): 'additional_time_before_last_section_taxi' ] = instance.additional_time_after_first_section_taxi + if request.get('additional_time_after_first_section_bike') is None: + request[ + 'additional_time_after_first_section_bike' + ] = instance.additional_time_after_first_section_bike + + if request.get('additional_time_before_last_section_bike') is None: + request[ + 'additional_time_before_last_section_bike' + ] = instance.additional_time_before_last_section_bike + krakens_call = set({(request["origin_mode"][0], request["destination_mode"][0], "indifferent")}) pt_object_origin = None pt_object_destination = None diff --git a/source/jormungandr/jormungandr/street_network/__init__.py b/source/jormungandr/jormungandr/street_network/__init__.py index c348c6d8a2..20e732b5fb 100644 --- a/source/jormungandr/jormungandr/street_network/__init__.py +++ b/source/jormungandr/jormungandr/street_network/__init__.py @@ -41,3 +41,4 @@ from jormungandr.street_network.car_with_park import CarWithPark from jormungandr.street_network.handimap import Handimap from jormungandr.street_network.andyamo import Andyamo +from jormungandr.street_network.bike import Bike diff --git a/source/jormungandr/jormungandr/street_network/bike.py b/source/jormungandr/jormungandr/street_network/bike.py new file mode 100644 index 0000000000..425f8fcdd4 --- /dev/null +++ b/source/jormungandr/jormungandr/street_network/bike.py @@ -0,0 +1,198 @@ +# Copyright (c) 2001-2024, Hove and/or its affiliates. All rights reserved. +# +# This file is part of Navitia, +# the software to build cool stuff with public transport. +# +# Hope you'll enjoy and contribute to this project, +# powered by Hove (www.hove.com). +# Help us simplify mobility and open public transport: +# a non ending quest to the responsive locomotion way of traveling! +# +# LICENCE: This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# Stay tuned using +# twitter @navitia +# channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org +# https://groups.google.com/d/forum/navitia +# www.navitia.io +from __future__ import absolute_import, print_function, unicode_literals, division + +import six +import logging +import copy +from jormungandr.street_network.street_network import AbstractStreetNetworkService, StreetNetworkPathType +from jormungandr import utils, park_modes as pm +from jormungandr.utils import SectionSorter +from functools import cmp_to_key + + +from navitiacommon import response_pb2 + + +class Bike(AbstractStreetNetworkService): + def __init__(self, instance, service_url, modes=None, id=None, timeout=10, api_key=None, **kwargs): + self.instance = instance + self.modes = modes or [pm.ParkModes.with_park] + assert list(self.modes) == [pm.ParkModes.with_park], ( + 'Class: ' + str(self.__class__) + ' can only be used with ParkModes.with_park mode. ' + ) + self.sn_system_id = id or 'bike' + config = kwargs.get('street_network', {}) + if 'service_url' not in config['args']: + config['args'].update({'service_url': None}) + if 'instance' not in config['args']: + config['args'].update({'instance': instance}) + + config['args'].update({'modes': self.modes}) + self.street_network = utils.create_object(config) + + def status(self): + return { + 'id': six.text_type(self.sn_system_id), + 'class': self.__class__.__name__, + 'modes': self.modes, + 'backend_class': self.street_network.__class__.__name__, + } + + + + def _direct_path(self, instance, mode, pt_object_origin, pt_object_destination, fallback_extremity, request, direct_path_type, request_id): + copy_request = copy.deepcopy(request) + response = self.street_network.direct_path( + instance, mode, pt_object_origin, pt_object_destination, fallback_extremity, copy_request, direct_path_type, request_id + ) + + if not response: + return response + + + def _add_additional_section_in_fallback( + self, response, pt_object_origin, pt_object_destination, request, direct_path_type + ): + logger = logging.getLogger(__name__) + logger.info("Creating additional section for direct path") + + for journey in response.journeys: + # Depending of the fallback type(beginning/ending fallback), the additional section's + # place can be the origin/destination of the pt_journey + # + if direct_path_type == StreetNetworkPathType.BEGINNING_FALLBACK: + self._add_additional_section_after_first_section_bike( + journey, pt_object_destination, request["additional_time_after_last_section_bike"] + ) + else: + self._add_additional_section_before_last_section_bike( + journey, pt_object_origin, request["additional_time_after_last_section_bike"] + ) + + + def _add_additional_section_after_first_section_bike(self, journey, pt_object, additional_time): + logging.getLogger(__name__).info("Creating additional section_after_first_section_bike") + + additional_section = self._create_additional_section( + pt_object, additional_time, journey.sections[-1].end_date_time, "section_1" + ) + + # We have to complete the destination of the first section ourselves + # Because Jormun does not do it afterwards + journey.sections[-1].destination.CopyFrom(pt_object) + + self._update_journey(journey, additional_section) + + def _add_additional_section_before_last_section_bike(self, journey, pt_object, additional_time): + logging.getLogger(__name__).info("Creating additional section_after_first_section_bike") + + additional_section = self._create_additional_section( + pt_object, additional_time, journey.sections[-1].end_date_time, "section_1" + ) + + # We have to complete the destination of the first section ourselves + # Because Jormun does not do it afterwards + journey.sections[-1].destination.CopyFrom(pt_object) + + for s in journey.sections: + s.end_date_time += additional_time + s.begin_date_time += additional_time + + self._update_journey(journey, additional_section) + + def _create_additional_section(self, pt_object, additional_time, begin_date_time, section_id): + additional_section = response_pb2.Section() + + additional_section.id = section_id + additional_section.origin.CopyFrom(pt_object) + additional_section.destination.CopyFrom(pt_object) + additional_section.duration = additional_time + additional_section.type = response_pb2.WAITING + additional_section.begin_date_time = begin_date_time + additional_section.end_date_time = additional_section.begin_date_time + additional_section.duration + + return additional_section + + def _update_journey(self, journey, additional_section): + journey.duration += additional_section.duration + journey.durations.total += additional_section.duration + journey.arrival_date_time += additional_section.duration + + journey.sections.extend([additional_section]) + journey.sections.sort(key=cmp_to_key(SectionSorter())) + + journey.nb_sections += 1 + + def _get_street_network_routing_matrix( + self, instance, origins, destinations, street_network_mode, max_duration, request, request_id, **kwargs + ): + + copy_request = copy.deepcopy(request) + response = self.street_network.get_street_network_routing_matrix( + instance, + origins, + destinations, + street_network_mode, + max_duration, + copy_request, + request_id, + **kwargs + ) + + if response and len(response.rows): + self._add_additional_time_in_routing_matrix( + response.rows[0].routing_response, origins, destinations, copy_request + ) + + return response + + + def _add_additional_time_in_routing_matrix(self, response, origins, destinations, request): + addtional_matrix_time = ( + request["additional_time_after_first_section_bike"] + if len(origins) == 1 + else request["additional_time_before_last_section_bike"] + ) + + for r in response: + r.duration += addtional_matrix_time + + def make_path_key(self, mode, orig_uri, dest_uri, streetnetwork_path_type, period_extremity): + """ + :param orig_uri, dest_uri, mode: matters obviously + :param streetnetwork_path_type: whether it's a fallback at + the beginning, the end of journey or a direct path without PT also matters especially for car (to know if we + park before or after) + :param period_extremity: is a PeriodExtremity (a datetime and its meaning on the + fallback period) + Nota: period_extremity is not taken into consideration so far because we assume that a + direct path from A to B remains the same even the departure time are different (no realtime) + """ + return self.street_network.make_path_key(mode, orig_uri, dest_uri, streetnetwork_path_type, None) diff --git a/source/navitiacommon/navitiacommon/default_values.py b/source/navitiacommon/navitiacommon/default_values.py index 9b86a338d2..2fb4602e93 100644 --- a/source/navitiacommon/navitiacommon/default_values.py +++ b/source/navitiacommon/navitiacommon/default_values.py @@ -151,6 +151,12 @@ # Additionnal time in second before the taxi section when used as last section mode additional_time_before_last_section_taxi = 5 * 60 +# Additionnal time in second after the bike section when used as first section mode +additional_time_after_first_section_bike = 5 * 60 + +# Additionnal time in second before the bike section when used as last section mode +additional_time_before_last_section_bike = 5 * 60 + max_walking_direct_path_duration = 24 * 60 * 60 max_bike_direct_path_duration = 24 * 60 * 60 diff --git a/source/navitiacommon/navitiacommon/models/__init__.py b/source/navitiacommon/navitiacommon/models/__init__.py index cb1bda3f7e..9e129f7a9d 100644 --- a/source/navitiacommon/navitiacommon/models/__init__.py +++ b/source/navitiacommon/navitiacommon/models/__init__.py @@ -516,6 +516,14 @@ class Instance(db.Model): # type: ignore db.Integer, default=default_values.additional_time_before_last_section_taxi, nullable=False ) + additional_time_after_first_section_bike = db.Column( + db.Integer, default=default_values.additional_time_after_first_section_bike, nullable=False + ) + + additional_time_before_last_section_bike = db.Column( + db.Integer, default=default_values.additional_time_before_last_section_bike, nullable=False + ) + max_walking_direct_path_duration = db.Column( db.Integer, default=default_values.max_walking_direct_path_duration, nullable=False ) diff --git a/source/tyr/tyr/fields.py b/source/tyr/tyr/fields.py index c2438b4157..92e3c8e428 100644 --- a/source/tyr/tyr/fields.py +++ b/source/tyr/tyr/fields.py @@ -198,6 +198,8 @@ def format(self, value): 'autocomplete_backend': fields.Raw, 'additional_time_after_first_section_taxi': fields.Raw, 'additional_time_before_last_section_taxi': fields.Raw, + 'additional_time_after_first_section_bike': fields.Raw, + 'additional_time_before_last_section_bike': fields.Raw, 'max_additional_connections': fields.Raw, 'successive_physical_mode_to_limit_id': fields.Raw, 'car_park_provider': fields.Raw, diff --git a/source/tyr/tyr/resources.py b/source/tyr/tyr/resources.py index e0e6881e9b..ac6ce606a3 100644 --- a/source/tyr/tyr/resources.py +++ b/source/tyr/tyr/resources.py @@ -711,6 +711,22 @@ def put(self, version=0, id=None, name=None): default=instance.additional_time_before_last_section_taxi, ) + parser.add_argument( + 'additional_time_before_first_section_bike', + type=int, + help='additional time after the bike section when used as first section mode', + location=('json', 'values'), + default=instance.additional_time_before_first_section_bike + ) + + parser.add_argument( + 'additional_time_before_last_section_bike', + type=int, + help='additional time before the bike section when used as first section mode', + location=('json', 'values'), + default=instance.additional_time_before_first_section_bike + ) + parser.add_argument( 'max_additional_connections', type=int, @@ -1050,6 +1066,8 @@ def map_args_to_instance(attr_name): 'autocomplete_backend', 'additional_time_after_first_section_taxi', 'additional_time_before_last_section_taxi', + 'additional_time_after_first_section_bike', + 'additional_time_after_last_section_bike', 'max_additional_connections', 'car_park_provider', 'street_network_car', From aa31fba64bdcbd73093df0b0ade51fa631f068f4 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Thu, 28 Nov 2024 08:06:21 +0100 Subject: [PATCH 02/20] change way of doing things --- .../jormungandr/default_settings.py | 4 +- source/jormungandr/jormungandr/instance.py | 6 +- .../jormungandr/interfaces/v1/Journeys.py | 28 +-- .../interfaces/v1/journey_common.py | 24 ++- .../interfaces/v1/serializer/status.py | 3 +- source/jormungandr/jormungandr/park_modes.py | 11 +- .../jormungandr/scenarios/distributed.py | 15 +- .../scenarios/helper_classes/helper_utils.py | 108 +++++++++- .../helper_classes/streetnetwork_path.py | 1 - .../jormungandr/scenarios/journey_filter.py | 6 + .../jormungandr/scenarios/new_default.py | 3 + .../jormungandr/street_network/__init__.py | 1 - .../jormungandr/street_network/bike.py | 198 ------------------ .../streetnetwork_backend_manager.py | 6 +- .../jormungandr/street_network/taxi.py | 2 - source/jormungandr/requirements.txt | 2 +- .../navitiacommon/default_values.py | 6 +- .../navitiacommon/models/__init__.py | 8 +- source/routing/raptor_api.cpp | 2 + source/tyr/tyr/fields.py | 3 +- source/tyr/tyr/resources.py | 13 +- 21 files changed, 179 insertions(+), 271 deletions(-) delete mode 100644 source/jormungandr/jormungandr/street_network/bike.py diff --git a/source/jormungandr/jormungandr/default_settings.py b/source/jormungandr/jormungandr/default_settings.py index f6c773a581..eefc590a56 100644 --- a/source/jormungandr/jormungandr/default_settings.py +++ b/source/jormungandr/jormungandr/default_settings.py @@ -12,7 +12,7 @@ } # 1000ms # path of the configuration file for each instances -INSTANCES_DIR = os.getenv('JORMUNGANDR_INSTANCES_DIR', '/etc/jormungandr.d') +INSTANCES_DIR = os.getenv('JORMUNGANDR_INSTANCES_DIR', './jormung_conf') INSTANCES_TIMEOUT = float(os.getenv('JORMUNGANDR_INSTANCES_TIMEOUT_S', 10)) @@ -32,7 +32,7 @@ 'JORMUNGANDR_SQLALCHEMY_DATABASE_URI', 'postgresql://navitia:navitia@localhost/jormungandr' ) -DISABLE_DATABASE = boolean(os.getenv('JORMUNGANDR_DISABLE_DATABASE', False)) +DISABLE_DATABASE = boolean(os.getenv('JORMUNGANDR_DISABLE_DATABASE', True)) # Active the asynchronous ridesharing mode ASYNCHRONOUS_RIDESHARING = boolean(os.getenv('JORMUNGANDR_ASYNCHRONOUS_RIDESHARING', False)) diff --git a/source/jormungandr/jormungandr/instance.py b/source/jormungandr/jormungandr/instance.py index b47ab6b227..4d80c1bcb2 100644 --- a/source/jormungandr/jormungandr/instance.py +++ b/source/jormungandr/jormungandr/instance.py @@ -820,9 +820,7 @@ def additional_parameters(self): additional_time_after_first_section_taxi = _make_property_getter('additional_time_after_first_section_taxi') additional_time_before_last_section_taxi = _make_property_getter('additional_time_before_last_section_taxi') - additional_time_after_first_section_bike = _make_property_getter('additional_time_after_first_section_bike') - additional_time_before_last_section_bike = _make_property_getter('additional_time_before_last_section_bike') - + on_street_bike_parking_duration = _make_property_getter('on_street_bike_parking_duration') max_walking_direct_path_duration = _make_property_getter('max_walking_direct_path_duration') max_bike_direct_path_duration = _make_property_getter('max_bike_direct_path_duration') @@ -1041,6 +1039,7 @@ def _get_street_network(self, mode, request): :param request: This parameter in required only for file configuration. :return: street_network backend connector for the mode """ + if app.config[str('DISABLE_DATABASE')]: return self._streetnetwork_backend_manager.get_street_network_legacy(self, mode, request) else: @@ -1061,6 +1060,7 @@ def get_street_network(self, mode, request): if mode != fallback_modes.FallbackModes.car.name: return self._get_street_network(mode, request) + walking_service = self._get_street_network(fallback_modes.FallbackModes.walking.name, request) car_service = self._get_street_network(fallback_modes.FallbackModes.car.name, request) return street_network.CarWithPark( diff --git a/source/jormungandr/jormungandr/interfaces/v1/Journeys.py b/source/jormungandr/jormungandr/interfaces/v1/Journeys.py index 85971f66c5..7d00a71f10 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/Journeys.py +++ b/source/jormungandr/jormungandr/interfaces/v1/Journeys.py @@ -75,7 +75,6 @@ from copy import deepcopy from jormungandr.travelers_profile import TravelerProfile from navitiacommon.constants import ENUM_LANGUAGE -import urllib.parse import base64 @@ -143,6 +142,9 @@ def wrapper(*args, **kwargs): args['from'] = journey['from']['id'] args['rel'] = 'journeys' journey['links'] = [create_external_link('v1.journeys', **args)] + + + elif allowed_ids and 'public_transport' in (s['type'] for s in journey['sections']): # exactly one first_section_mode if any(s['type'].startswith('bss') for s in journey['sections'][:2]): @@ -436,15 +438,15 @@ def wrapper(*args, **kwargs): for j in response.get('journeys', []): if 'sections' not in j: continue - logging.debug( - 'for journey changing origin: {old_o} to {new_o}' - ', destination to {old_d} to {new_d}'.format( - old_o=j.get('sections', [{}])[0].get('from').get('id'), - new_o=(g.origin_detail or {}).get('id'), - old_d=j.get('sections', [{}])[-1].get('to').get('id'), - new_d=(g.destination_detail or {}).get('id'), - ) - ) + # logging.debug( + # 'for journey changing origin: {old_o} to {new_o}' + # ', destination to {old_d} to {new_d}'.format( + # old_o=j.get('sections', [{}])[0].get('from').get('id'), + # new_o=(g.origin_detail or {}).get('id'), + # old_d=j.get('sections', [{}])[-1].get('to').get('id'), + # new_d=(g.destination_detail or {}).get('id'), + # ) + # ) if g.origin_detail: self.clean_global_origin_destination_detail(g.origin_detail) j['sections'][0]['from'] = g.origin_detail @@ -826,10 +828,8 @@ def _set_specific_params(mod): if args.get('additional_time_before_last_section_taxi') is None: args['additional_time_before_last_section_taxi'] = mod.additional_time_before_last_section_taxi - if args.get('additional_time_after_first_section_bike') is None: - args['additional_time_after_first_section_bike'] = mod.additional_time_after_first_section_bike - if args.get('additional_time_before_last_section_bike') is None: - args['additional_time_before_last_section_bike'] = mod.additional_time_before_last_section_bike + if args.get("on_street_bike_parking_duration") is None: + args["on_street_bike_parking_duration"] = mod.on_street_bike_parking_duration if args.get('_stop_points_nearby_duration') is None: args['_stop_points_nearby_duration'] = mod.stop_points_nearby_duration diff --git a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py index 8406991c7f..5fc98b881d 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py +++ b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py @@ -30,7 +30,7 @@ # www.navitia.io from __future__ import absolute_import, print_function, unicode_literals, division -from jormungandr import i_manager, fallback_modes, partner_services, app, park_modes +from jormungandr import i_manager, fallback_modes, park_modes, partner_services, app from jormungandr.interfaces.v1.ResourceUri import ResourceUri from datetime import datetime from jormungandr.resources_utils import ResourceUtc @@ -232,6 +232,17 @@ def __init__(self, output_type_serializer): 'first_section_mode[]=bike&last_section_mode[]=walking&' 'last_section_mode[]=bss&last_section_mode[]=bike`', ) + + parser_get.add_argument( + "park_mode[]", + type=OptionValue(park_modes.all_park_modes), + dest="park_mode", + action="append", + help='If you want to use park modes in your journey. ' + 'Note: the park_modes[] concern only the bike objects. ' + ) + + parser_get.add_argument( "last_section_mode[]", type=OptionValue(fallback_modes.all_fallback_modes), @@ -515,17 +526,10 @@ def __init__(self, output_type_serializer): help="the additional time added to the taxi section, right before riding the taxi but after hopping off the public transit", ) - - parser_get.add_argument( - "additional_time_after_first_section_bike", - type=int, - help="the additional time added to the bike section, right after riding the bike but before hopping on the public transit", - ) - parser_get.add_argument( - "additional_time_before_last_section_bike", + "on_street_bike_parking_duration", type=int, - help="the additional time added to the bike section, right before riding the bike but after hopping off the public transit", + help="the additional time added to the bike section before and after parking the bike", ) parser_get.add_argument( diff --git a/source/jormungandr/jormungandr/interfaces/v1/serializer/status.py b/source/jormungandr/jormungandr/interfaces/v1/serializer/status.py index 5695a5a4a7..f9151b0913 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/serializer/status.py +++ b/source/jormungandr/jormungandr/interfaces/v1/serializer/status.py @@ -74,8 +74,7 @@ class ParametersSerializer(serpy.Serializer): max_extra_second_pass = Field(schema_type=int) additional_time_after_first_section_taxi = Field(schema_type=int) additional_time_before_last_section_taxi = Field(schema_type=int) - additional_time_after_first_section_bike = Field(schema_type=int) - additional_time_before_last_section_bike = Field(schema_type=int) + on_street_bike_parking_duration = Field(schema_type=int) max_walking_direct_path_duration = Field(schema_type=int) max_bike_direct_path_duration = Field(schema_type=int) max_bss_direct_path_duration = Field(schema_type=int) diff --git a/source/jormungandr/jormungandr/park_modes.py b/source/jormungandr/jormungandr/park_modes.py index 1f33c9810f..216fc99982 100644 --- a/source/jormungandr/jormungandr/park_modes.py +++ b/source/jormungandr/jormungandr/park_modes.py @@ -34,11 +34,10 @@ from navitiacommon import response_pb2 - -class ParkModes(Enum): - none = response_pb2.None - without_park = response_pb2.WithoutPark - with_park = response_pb2.WithPark +class ParkMode(Enum): + none = response_pb2.NONE + on_street = response_pb2.OnStreet + park_and_ride = response_pb2.ParkAndRide @classmethod @@ -72,4 +71,4 @@ def get_allowed_combinations_str(cls): return set(six.moves.map(lambda modes: (modes[0].name, modes[1].name), allowed_combinations_enum)) -all_park_modes = ParkModes.modes_str() +all_park_modes = ParkMode.modes_str() diff --git a/source/jormungandr/jormungandr/scenarios/distributed.py b/source/jormungandr/jormungandr/scenarios/distributed.py index 602aaf5b69..05fa63d988 100644 --- a/source/jormungandr/jormungandr/scenarios/distributed.py +++ b/source/jormungandr/jormungandr/scenarios/distributed.py @@ -343,6 +343,7 @@ def finalise_journeys(self, future_manager, request, responses, context, instanc for response in responses: pt_journey_fare_pool.async_compute_fare(response, request_id) + wait_and_complete_pt_journey( requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, @@ -356,6 +357,8 @@ def finalise_journeys(self, future_manager, request, responses, context, instanc journeys=journeys_to_complete, request_id="{}_complete_pt_journey".format(request_id), ) + + if request['_loki_compute_pt_journey_fare'] is True and request['_pt_planner'] == "loki": wait_and_complete_pt_journey_fare( pt_elements=journeys_to_complete, pt_journey_fare_pool=pt_journey_fare_pool @@ -589,15 +592,11 @@ def graphical_isochrones(self, request, instance): 'additional_time_before_last_section_taxi' ] = instance.additional_time_after_first_section_taxi - if request.get('additional_time_after_first_section_bike') is None: - request[ - 'additional_time_after_first_section_bike' - ] = instance.additional_time_after_first_section_bike - - if request.get('additional_time_before_last_section_bike') is None: + if request.get('on_street_bike_parking_duration') is None: request[ - 'additional_time_before_last_section_bike' - ] = instance.additional_time_before_last_section_bike + 'on_street_bike_parking_duration' + ] = instance.on_street_bike_parking_duration + krakens_call = set({(request["origin_mode"][0], request["destination_mode"][0], "indifferent")}) pt_object_origin = None diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py index 773e5558d9..16fb5ef829 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py @@ -192,6 +192,31 @@ def _make_ending_car_park_sections( car_park_to_sp_section.duration = car_park_crowfly_duration +def _extend_with_bike_park(begin_date_time, duration): + bike_park_section = response_pb2.Section() + bike_park_section.id = "Section_1" + bike_park_section.duration = duration + bike_park_section.type = response_pb2.PARK + bike_park_section.begin_date_time = begin_date_time + bike_park_section.end_date_time = bike_park_section.begin_date_time + duration + return bike_park_section + + +def _extend_with_bike_park_street_network(origin, begin_date_time, destination): + bike_park_to_sp_section = response_pb2.Section() + bike_park_to_sp_section.id = "Section_2" + bike_park_to_sp_section.origin.CopyFrom(origin) + bike_park_to_sp_section.destination.CopyFrom(destination) + bike_park_to_sp_section.type = response_pb2.STREET_NETWORK + bike_park_to_sp_section.street_network.mode = response_pb2.Walking + bike_park_to_sp_section.begin_date_time = begin_date_time + # bike_park_to_sp_section.end_date_time = begin_date_time + duration + return bike_park_to_sp_section + + + + + def _extend_with_car_park( fallback_dp, pt_journey, fallback_type, walking_speed, car_park, car_park_duration, car_park_crowfly_duration ): @@ -390,6 +415,55 @@ def add_poi_access_point_in_sections(fallback_type, via_poi_access, sections): poi_access.is_exit = True poi_access.is_entrance = True +def _update_journey(journey, park_section, street_mode_section, to_replace, new_fallbacks): + journey.duration += park_section.duration + street_mode_section.duration + journey.durations.total += park_section.duration + street_mode_section.duration + journey.arrival_date_time += park_section.duration + street_mode_section.duration + journey.sections.remove(to_replace) + journey.sections.extend([street_mode_section, park_section]) + journey.sections.extend(new_fallbacks) + journey.nb_sections += 1 + +def _update_fallback_with_bike_mode(journey, fallback_dp, fallback_period_extremity, fallback_type, via_pt_access, via_poi_access,**kwargs): + """ + Replace journey's fallback sections with the given fallback_dp. + + Note: the replacement is done in place of the journey + """ + aligned_fallback = _align_fallback_direct_path_datetime(fallback_dp, fallback_period_extremity) + fallback_sections = aligned_fallback.journeys[0].sections + + # update the 'id' which isn't set + _rename_fallback_sections_ids(fallback_sections) + + # We have to create the link between the fallback and the pt part manually here + if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK and kwargs["origin_mode"] == ["bike"]: + for s in journey.sections: + s.begin_date_time += kwargs["additional_time"] + s.end_date_time += kwargs["additional_time"] + park_section = _extend_with_bike_park(fallback_sections[-1].end_date_time, kwargs["additional_time"]) + street_mode_section = _extend_with_bike_park_street_network(fallback_sections[-1].destination, park_section.end_date_time, journey.sections[0].destination) + _update_journey(journey, park_section, street_mode_section, journey.sections[0], fallback_sections) + + elif fallback_type == StreetNetworkPathType.ENDING_FALLBACK and kwargs["destination_mode"] == ["bike"]: + street_mode_section = _extend_with_bike_park_street_network(fallback_sections[0].destination, fallback_sections[0].begin_date_time, journey.sections[-1].destination) + park_section = _extend_with_bike_park(street_mode_section.begin_date_time, kwargs["additional_time"]) + fallback_sections[0].begin_date_time += kwargs["additional_time"] + _update_journey(journey, park_section, street_mode_section, journey.sections[-1], fallback_sections) + + + add_poi_access_point_in_sections(fallback_type, via_poi_access, fallback_sections) + + if isinstance(via_pt_access, type_pb2.PtObject) and via_pt_access.embedded_type == type_pb2.ACCESS_POINT: + if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK: + journey.sections[-1].vias.add().CopyFrom(via_pt_access.access_point) + else: + journey.sections[0].vias.add().CopyFrom(via_pt_access.access_point) + journey.sections.sort(key=cmp_to_key(SectionSorter())) + + + + def _update_fallback_sections( journey, fallback_dp, fallback_period_extremity, fallback_type, via_pt_access, via_poi_access @@ -638,14 +712,28 @@ def _build_fallback( fallback_dp_copy, fallback_type, requested_obj, via_poi_access, language ) - _update_fallback_sections( - pt_journey, - fallback_dp_copy, - fallback_period_extremity, - fallback_type, - via_pt_access, - via_poi_access, - ) + if request["park_mode"] == ["on_street"] and (request["origin_mode"] == ["bike"] or request["destination_mode"] == ["bike"]): + _update_fallback_with_bike_mode( + pt_journey, + fallback_dp_copy, + fallback_period_extremity, + fallback_type, + via_pt_access, + via_poi_access, + park_mode = request["park_mode"], + origin_mode = request["origin_mode"], + destination_mode = request["destination_mode"], + additional_time = request["on_street_bike_parking_duration"] + ) + else: + _update_fallback_sections( + pt_journey, + fallback_dp_copy, + fallback_period_extremity, + fallback_type, + via_pt_access, + via_poi_access, + ) # update distances and durations by mode if it's a proper computed streetnetwork fallback if fallback_dp_copy and fallback_dp_copy.journeys: @@ -693,9 +781,13 @@ def get_max_fallback_duration(request, mode, dp_future, direct_path_timeout): :return: max_fallback_duration """ # 30 minutes by default + print("request", request) max_duration = request.get('max_{}_duration_to_pt'.format(mode), 1800) + print("max_duration", max_duration) + print(str(dp_future)) dp = dp_future.wait_and_get(timeout=direct_path_timeout) if dp_future else None dp_duration = dp.journeys[0].durations.total if getattr(dp, 'journeys', None) else max_duration + return min(max_duration, dp_duration) diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py b/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py index 16e87444bb..aba6034c05 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py @@ -225,7 +225,6 @@ def _async_request(self): self._futures.append(self._future_manager.create_future(self._do_request, origin, destination)) def wait_and_get(self, timeout=None): - # timeout=None -> wait forever... timer = gevent.timeout.Timeout(timeout, exception=False) diff --git a/source/jormungandr/jormungandr/scenarios/journey_filter.py b/source/jormungandr/jormungandr/scenarios/journey_filter.py index 135a708172..2bed1771f4 100644 --- a/source/jormungandr/jormungandr/scenarios/journey_filter.py +++ b/source/jormungandr/jormungandr/scenarios/journey_filter.py @@ -36,6 +36,8 @@ from jormungandr.scenarios.utils import compare, get_or_default from navitiacommon import response_pb2 from jormungandr.utils import ( + get_pt_object_from_json, + json_address_from_uri, pb_del_if, ComposedFilter, portable_min, @@ -693,6 +695,10 @@ def apply_final_journey_filters(response_list, instance, request): filter_non_car_tagged_journey(journeys, request) + + + + def is_direct_path_walking(j): if not j: return False diff --git a/source/jormungandr/jormungandr/scenarios/new_default.py b/source/jormungandr/jormungandr/scenarios/new_default.py index 47053d9fbc..fd7bc311c2 100644 --- a/source/jormungandr/jormungandr/scenarios/new_default.py +++ b/source/jormungandr/jormungandr/scenarios/new_default.py @@ -1449,6 +1449,9 @@ def fill_journeys(self, request_type, api_request, instance): api_request, responses, distributed_context, instance, api_request['debug'], request_id ) + + + # We need to reapply some filter after 'finalise_journeys' because # journeys with crow_fly bss and crow_fly walking couldn't be compared # but can results in street_network walking in both case diff --git a/source/jormungandr/jormungandr/street_network/__init__.py b/source/jormungandr/jormungandr/street_network/__init__.py index 20e732b5fb..c348c6d8a2 100644 --- a/source/jormungandr/jormungandr/street_network/__init__.py +++ b/source/jormungandr/jormungandr/street_network/__init__.py @@ -41,4 +41,3 @@ from jormungandr.street_network.car_with_park import CarWithPark from jormungandr.street_network.handimap import Handimap from jormungandr.street_network.andyamo import Andyamo -from jormungandr.street_network.bike import Bike diff --git a/source/jormungandr/jormungandr/street_network/bike.py b/source/jormungandr/jormungandr/street_network/bike.py deleted file mode 100644 index 425f8fcdd4..0000000000 --- a/source/jormungandr/jormungandr/street_network/bike.py +++ /dev/null @@ -1,198 +0,0 @@ -# Copyright (c) 2001-2024, Hove and/or its affiliates. All rights reserved. -# -# This file is part of Navitia, -# the software to build cool stuff with public transport. -# -# Hope you'll enjoy and contribute to this project, -# powered by Hove (www.hove.com). -# Help us simplify mobility and open public transport: -# a non ending quest to the responsive locomotion way of traveling! -# -# LICENCE: This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# Stay tuned using -# twitter @navitia -# channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org -# https://groups.google.com/d/forum/navitia -# www.navitia.io -from __future__ import absolute_import, print_function, unicode_literals, division - -import six -import logging -import copy -from jormungandr.street_network.street_network import AbstractStreetNetworkService, StreetNetworkPathType -from jormungandr import utils, park_modes as pm -from jormungandr.utils import SectionSorter -from functools import cmp_to_key - - -from navitiacommon import response_pb2 - - -class Bike(AbstractStreetNetworkService): - def __init__(self, instance, service_url, modes=None, id=None, timeout=10, api_key=None, **kwargs): - self.instance = instance - self.modes = modes or [pm.ParkModes.with_park] - assert list(self.modes) == [pm.ParkModes.with_park], ( - 'Class: ' + str(self.__class__) + ' can only be used with ParkModes.with_park mode. ' - ) - self.sn_system_id = id or 'bike' - config = kwargs.get('street_network', {}) - if 'service_url' not in config['args']: - config['args'].update({'service_url': None}) - if 'instance' not in config['args']: - config['args'].update({'instance': instance}) - - config['args'].update({'modes': self.modes}) - self.street_network = utils.create_object(config) - - def status(self): - return { - 'id': six.text_type(self.sn_system_id), - 'class': self.__class__.__name__, - 'modes': self.modes, - 'backend_class': self.street_network.__class__.__name__, - } - - - - def _direct_path(self, instance, mode, pt_object_origin, pt_object_destination, fallback_extremity, request, direct_path_type, request_id): - copy_request = copy.deepcopy(request) - response = self.street_network.direct_path( - instance, mode, pt_object_origin, pt_object_destination, fallback_extremity, copy_request, direct_path_type, request_id - ) - - if not response: - return response - - - def _add_additional_section_in_fallback( - self, response, pt_object_origin, pt_object_destination, request, direct_path_type - ): - logger = logging.getLogger(__name__) - logger.info("Creating additional section for direct path") - - for journey in response.journeys: - # Depending of the fallback type(beginning/ending fallback), the additional section's - # place can be the origin/destination of the pt_journey - # - if direct_path_type == StreetNetworkPathType.BEGINNING_FALLBACK: - self._add_additional_section_after_first_section_bike( - journey, pt_object_destination, request["additional_time_after_last_section_bike"] - ) - else: - self._add_additional_section_before_last_section_bike( - journey, pt_object_origin, request["additional_time_after_last_section_bike"] - ) - - - def _add_additional_section_after_first_section_bike(self, journey, pt_object, additional_time): - logging.getLogger(__name__).info("Creating additional section_after_first_section_bike") - - additional_section = self._create_additional_section( - pt_object, additional_time, journey.sections[-1].end_date_time, "section_1" - ) - - # We have to complete the destination of the first section ourselves - # Because Jormun does not do it afterwards - journey.sections[-1].destination.CopyFrom(pt_object) - - self._update_journey(journey, additional_section) - - def _add_additional_section_before_last_section_bike(self, journey, pt_object, additional_time): - logging.getLogger(__name__).info("Creating additional section_after_first_section_bike") - - additional_section = self._create_additional_section( - pt_object, additional_time, journey.sections[-1].end_date_time, "section_1" - ) - - # We have to complete the destination of the first section ourselves - # Because Jormun does not do it afterwards - journey.sections[-1].destination.CopyFrom(pt_object) - - for s in journey.sections: - s.end_date_time += additional_time - s.begin_date_time += additional_time - - self._update_journey(journey, additional_section) - - def _create_additional_section(self, pt_object, additional_time, begin_date_time, section_id): - additional_section = response_pb2.Section() - - additional_section.id = section_id - additional_section.origin.CopyFrom(pt_object) - additional_section.destination.CopyFrom(pt_object) - additional_section.duration = additional_time - additional_section.type = response_pb2.WAITING - additional_section.begin_date_time = begin_date_time - additional_section.end_date_time = additional_section.begin_date_time + additional_section.duration - - return additional_section - - def _update_journey(self, journey, additional_section): - journey.duration += additional_section.duration - journey.durations.total += additional_section.duration - journey.arrival_date_time += additional_section.duration - - journey.sections.extend([additional_section]) - journey.sections.sort(key=cmp_to_key(SectionSorter())) - - journey.nb_sections += 1 - - def _get_street_network_routing_matrix( - self, instance, origins, destinations, street_network_mode, max_duration, request, request_id, **kwargs - ): - - copy_request = copy.deepcopy(request) - response = self.street_network.get_street_network_routing_matrix( - instance, - origins, - destinations, - street_network_mode, - max_duration, - copy_request, - request_id, - **kwargs - ) - - if response and len(response.rows): - self._add_additional_time_in_routing_matrix( - response.rows[0].routing_response, origins, destinations, copy_request - ) - - return response - - - def _add_additional_time_in_routing_matrix(self, response, origins, destinations, request): - addtional_matrix_time = ( - request["additional_time_after_first_section_bike"] - if len(origins) == 1 - else request["additional_time_before_last_section_bike"] - ) - - for r in response: - r.duration += addtional_matrix_time - - def make_path_key(self, mode, orig_uri, dest_uri, streetnetwork_path_type, period_extremity): - """ - :param orig_uri, dest_uri, mode: matters obviously - :param streetnetwork_path_type: whether it's a fallback at - the beginning, the end of journey or a direct path without PT also matters especially for car (to know if we - park before or after) - :param period_extremity: is a PeriodExtremity (a datetime and its meaning on the - fallback period) - Nota: period_extremity is not taken into consideration so far because we assume that a - direct path from A to B remains the same even the departure time are different (no realtime) - """ - return self.street_network.make_path_key(mode, orig_uri, dest_uri, streetnetwork_path_type, None) diff --git a/source/jormungandr/jormungandr/street_network/streetnetwork_backend_manager.py b/source/jormungandr/jormungandr/street_network/streetnetwork_backend_manager.py index a2b2dc8768..7efb53e0c2 100644 --- a/source/jormungandr/jormungandr/street_network/streetnetwork_backend_manager.py +++ b/source/jormungandr/jormungandr/street_network/streetnetwork_backend_manager.py @@ -83,6 +83,7 @@ def _append_default_street_network_to_config(self, instance_configuration): 'modes': ['ridesharing'], } + modes_in_configs = set( list(itertools.chain.from_iterable(config.get('modes', []) for config in instance_configuration)) ) @@ -94,12 +95,15 @@ def _append_default_street_network_to_config(self, instance_configuration): if 'ridesharing' in modes_not_set: instance_configuration.append(ridesharing) + kraken['modes'] = [m for m in modes_not_set - {'taxi', 'ridesharing'}] + instance_configuration.append(copy.deepcopy(kraken)) return instance_configuration def _create_street_network_backends(self, instance, instance_configuration): + # type: (Instance, List[Dict[str, Any]]) -> None for config in instance_configuration: # Set default arguments @@ -240,7 +244,6 @@ def get_street_network_legacy(self, instance, mode, request=None): # type: (Instance, str, Dict[str, Any]) -> AbstractStreetNetworkService overriden_sn_id = (request or {}).get('_street_network') if overriden_sn_id: - def predicate(s): return s.sn_system_id == overriden_sn_id @@ -249,6 +252,7 @@ def predicate(s): def predicate(s): return mode in s.modes + print("instance_bn", self._streetnetwork_backends_by_instance_legacy[instance]) sn = next((s for s in self._streetnetwork_backends_by_instance_legacy[instance] if predicate(s)), None) if sn is None: raise TechnicalError( diff --git a/source/jormungandr/jormungandr/street_network/taxi.py b/source/jormungandr/jormungandr/street_network/taxi.py index 3bc38cf5a6..e5584abc1a 100644 --- a/source/jormungandr/jormungandr/street_network/taxi.py +++ b/source/jormungandr/jormungandr/street_network/taxi.py @@ -35,8 +35,6 @@ from jormungandr import utils, fallback_modes as fm from jormungandr.utils import SectionSorter from functools import cmp_to_key - - from navitiacommon import response_pb2 diff --git a/source/jormungandr/requirements.txt b/source/jormungandr/requirements.txt index ee6b8921ed..73911babbe 100644 --- a/source/jormungandr/requirements.txt +++ b/source/jormungandr/requirements.txt @@ -58,4 +58,4 @@ newrelic==6.8.0.163 ; python_version >= "3.9" greenlet==0.4.15 ; python_version <= "3.6" pickle-mixin==1.0.2 Flask-Caching==1.7.2 -boto3==1.28.82 +boto3==1.17.112 diff --git a/source/navitiacommon/navitiacommon/default_values.py b/source/navitiacommon/navitiacommon/default_values.py index 2fb4602e93..64da1f7b40 100644 --- a/source/navitiacommon/navitiacommon/default_values.py +++ b/source/navitiacommon/navitiacommon/default_values.py @@ -151,11 +151,9 @@ # Additionnal time in second before the taxi section when used as last section mode additional_time_before_last_section_taxi = 5 * 60 -# Additionnal time in second after the bike section when used as first section mode -additional_time_after_first_section_bike = 5 * 60 +# Additionnal time in second after the parking section when used as first section mode +on_street_bike_parking_duration = 5 * 60 -# Additionnal time in second before the bike section when used as last section mode -additional_time_before_last_section_bike = 5 * 60 max_walking_direct_path_duration = 24 * 60 * 60 diff --git a/source/navitiacommon/navitiacommon/models/__init__.py b/source/navitiacommon/navitiacommon/models/__init__.py index 9e129f7a9d..26f59b3732 100644 --- a/source/navitiacommon/navitiacommon/models/__init__.py +++ b/source/navitiacommon/navitiacommon/models/__init__.py @@ -516,12 +516,8 @@ class Instance(db.Model): # type: ignore db.Integer, default=default_values.additional_time_before_last_section_taxi, nullable=False ) - additional_time_after_first_section_bike = db.Column( - db.Integer, default=default_values.additional_time_after_first_section_bike, nullable=False - ) - - additional_time_before_last_section_bike = db.Column( - db.Integer, default=default_values.additional_time_before_last_section_bike, nullable=False + on_street_bike_parking_duration = db.Column( + db.Integer, default=default_values.on_street_bike_parking_duration, nullable=False ) max_walking_direct_path_duration = db.Column( diff --git a/source/routing/raptor_api.cpp b/source/routing/raptor_api.cpp index d57445c3d8..b44cb13318 100644 --- a/source/routing/raptor_api.cpp +++ b/source/routing/raptor_api.cpp @@ -397,6 +397,8 @@ static void compute_metadata(pbnavitia::Journey* pb_journey) { total_car_distance += section.length(); break; case pbnavitia::StreetNetworkMode::Bike: + total_bike_duration += section.duration(); + total_bike_distance += section.length(); case pbnavitia::StreetNetworkMode::Bss: total_bike_duration += section.duration(); total_bike_distance += section.length(); diff --git a/source/tyr/tyr/fields.py b/source/tyr/tyr/fields.py index 92e3c8e428..18a2b8b3f9 100644 --- a/source/tyr/tyr/fields.py +++ b/source/tyr/tyr/fields.py @@ -198,8 +198,7 @@ def format(self, value): 'autocomplete_backend': fields.Raw, 'additional_time_after_first_section_taxi': fields.Raw, 'additional_time_before_last_section_taxi': fields.Raw, - 'additional_time_after_first_section_bike': fields.Raw, - 'additional_time_before_last_section_bike': fields.Raw, + 'on_street_bike_parking_duration': fields.Raw, 'max_additional_connections': fields.Raw, 'successive_physical_mode_to_limit_id': fields.Raw, 'car_park_provider': fields.Raw, diff --git a/source/tyr/tyr/resources.py b/source/tyr/tyr/resources.py index ac6ce606a3..95373c6061 100644 --- a/source/tyr/tyr/resources.py +++ b/source/tyr/tyr/resources.py @@ -711,6 +711,16 @@ def put(self, version=0, id=None, name=None): default=instance.additional_time_before_last_section_taxi, ) + + parser.add_argument( + "on_street_bike_parking_duration", + type=int, + help="additionnal time after the bike section when used as first section mode", + location=("json", "values"), + default=instance.on_street_bike_parking_duration, + ) + + parser.add_argument( 'additional_time_before_first_section_bike', type=int, @@ -1066,8 +1076,7 @@ def map_args_to_instance(attr_name): 'autocomplete_backend', 'additional_time_after_first_section_taxi', 'additional_time_before_last_section_taxi', - 'additional_time_after_first_section_bike', - 'additional_time_after_last_section_bike', + 'on_street_bike_parking_duration', 'max_additional_connections', 'car_park_provider', 'street_network_car', From fd1696f9341e6fc2c764b106d1c99dfb09e61593 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Thu, 28 Nov 2024 08:46:56 +0100 Subject: [PATCH 03/20] revert to default changes --- .../jormungandr/interfaces/v1/journey_common.py | 12 +----------- .../jormungandr/scenarios/journey_filter.py | 6 ------ .../street_network/streetnetwork_backend_manager.py | 6 +----- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py index 5fc98b881d..27b6246612 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py +++ b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py @@ -233,16 +233,6 @@ def __init__(self, output_type_serializer): 'last_section_mode[]=bss&last_section_mode[]=bike`', ) - parser_get.add_argument( - "park_mode[]", - type=OptionValue(park_modes.all_park_modes), - dest="park_mode", - action="append", - help='If you want to use park modes in your journey. ' - 'Note: the park_modes[] concern only the bike objects. ' - ) - - parser_get.add_argument( "last_section_mode[]", type=OptionValue(fallback_modes.all_fallback_modes), @@ -254,7 +244,7 @@ def __init__(self, output_type_serializer): parser_get.add_argument( "park_mode[]", type=OptionValue(park_modes.all_park_modes), - dest="origin_mode", + dest="park_mode", action="append", help='Force the park mode if the first section is by bike\n' ) diff --git a/source/jormungandr/jormungandr/scenarios/journey_filter.py b/source/jormungandr/jormungandr/scenarios/journey_filter.py index 2bed1771f4..135a708172 100644 --- a/source/jormungandr/jormungandr/scenarios/journey_filter.py +++ b/source/jormungandr/jormungandr/scenarios/journey_filter.py @@ -36,8 +36,6 @@ from jormungandr.scenarios.utils import compare, get_or_default from navitiacommon import response_pb2 from jormungandr.utils import ( - get_pt_object_from_json, - json_address_from_uri, pb_del_if, ComposedFilter, portable_min, @@ -695,10 +693,6 @@ def apply_final_journey_filters(response_list, instance, request): filter_non_car_tagged_journey(journeys, request) - - - - def is_direct_path_walking(j): if not j: return False diff --git a/source/jormungandr/jormungandr/street_network/streetnetwork_backend_manager.py b/source/jormungandr/jormungandr/street_network/streetnetwork_backend_manager.py index 7efb53e0c2..a2b2dc8768 100644 --- a/source/jormungandr/jormungandr/street_network/streetnetwork_backend_manager.py +++ b/source/jormungandr/jormungandr/street_network/streetnetwork_backend_manager.py @@ -83,7 +83,6 @@ def _append_default_street_network_to_config(self, instance_configuration): 'modes': ['ridesharing'], } - modes_in_configs = set( list(itertools.chain.from_iterable(config.get('modes', []) for config in instance_configuration)) ) @@ -95,15 +94,12 @@ def _append_default_street_network_to_config(self, instance_configuration): if 'ridesharing' in modes_not_set: instance_configuration.append(ridesharing) - kraken['modes'] = [m for m in modes_not_set - {'taxi', 'ridesharing'}] - instance_configuration.append(copy.deepcopy(kraken)) return instance_configuration def _create_street_network_backends(self, instance, instance_configuration): - # type: (Instance, List[Dict[str, Any]]) -> None for config in instance_configuration: # Set default arguments @@ -244,6 +240,7 @@ def get_street_network_legacy(self, instance, mode, request=None): # type: (Instance, str, Dict[str, Any]) -> AbstractStreetNetworkService overriden_sn_id = (request or {}).get('_street_network') if overriden_sn_id: + def predicate(s): return s.sn_system_id == overriden_sn_id @@ -252,7 +249,6 @@ def predicate(s): def predicate(s): return mode in s.modes - print("instance_bn", self._streetnetwork_backends_by_instance_legacy[instance]) sn = next((s for s in self._streetnetwork_backends_by_instance_legacy[instance] if predicate(s)), None) if sn is None: raise TechnicalError( From e4669f7e3bd00ea5f11c8bfab6e9a1ba8bd363bf Mon Sep 17 00:00:00 2001 From: Pondonda Date: Thu, 28 Nov 2024 10:47:34 +0100 Subject: [PATCH 04/20] add tests cases --- source/jormungandr/requirements.txt | 2 +- source/jormungandr/tests/park_mode_tests.py | 228 ++++++++++++++++++++ 2 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 source/jormungandr/tests/park_mode_tests.py diff --git a/source/jormungandr/requirements.txt b/source/jormungandr/requirements.txt index 73911babbe..ee6b8921ed 100644 --- a/source/jormungandr/requirements.txt +++ b/source/jormungandr/requirements.txt @@ -58,4 +58,4 @@ newrelic==6.8.0.163 ; python_version >= "3.9" greenlet==0.4.15 ; python_version <= "3.6" pickle-mixin==1.0.2 Flask-Caching==1.7.2 -boto3==1.17.112 +boto3==1.28.82 diff --git a/source/jormungandr/tests/park_mode_tests.py b/source/jormungandr/tests/park_mode_tests.py new file mode 100644 index 0000000000..8510ec9db0 --- /dev/null +++ b/source/jormungandr/tests/park_mode_tests.py @@ -0,0 +1,228 @@ +# Copyright (c) 2001-2024, Hove and/or its affiliates. All rights reserved. +# +# This file is part of Navitia, +# the software to build cool stuff with public transport. +# +# Hope you'll enjoy and contribute to this project, +# powered by Hove (www.hove.com). +# Help us simplify mobility and open public transport: +# a non ending quest to the responsive locomotion way of traveling! +# +# LICENCE: This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# Stay tuned using +# twitter @navitia +# channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org +# https://groups.google.com/d/forum/navitia +# www.navitia.io + + + +from __future__ import absolute_import, print_function, unicode_literals, division +from .tests_mechanism import AbstractTestFixture, dataset + +@dataset({"park_modes_test": {}}) +class TestParkMode(AbstractTestFixture): + """ + Test park mode features + """ + + def test_first_section_park_mode_none_with_access_point(self): + """" + Test park mode none with _access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=none&_access_points=true" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] != 'park' + + + def test_first_section_park_mode_none_without_access_point(self): + """" + Test park mode none without access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=none" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] != 'park' + + + def test_first_section_park_mode_on_street_with_access_point(self): + """" + Test park mode on street with access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=on_street&_access_points=true" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 0: + assert len( journey['sections'][0]['vias']) > 0 + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] == 'park' + assert journey['sections'][1]['type'] == 'street_network' + + # Verify if the park sections doesnt have any from and to. + assert journey['sections'][1]['from']["embedded_type"] is None + assert journey['sections'][1]['to']["embedded_type"] is None + + + def test_first_section_park_mode_on_street_without_access_point(self): + """" + Test park mode on street without access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=on_street" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 0: + assert len( journey['sections'][0]['vias']) > 0 + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] == 'park' + assert journey['sections'][1]['type'] == 'street_network' + + # Verify if the park sections doesnt have any from and to. + assert journey['sections'][1]['from']["embedded_type"] is None + assert journey['sections'][1]['to']["embedded_type"] is None + + + def test_first_section_park_mode_park_and_ride_with_access_point(self): + """" + Test park mode park and ride with access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride&_access_points=true" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] != 'park' + + def test_first_section_park_mode_park_and_ride_without_access_point(self): + """" + Test park mode park and ride without access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] != 'park' + + + def test_last_section_mode_park_mode_none_with_access_point(self): + """" + Test park mode none with _access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=none&_access_points=true" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] != 'park' + + + def test_last_section_mode_park_mode_none_without_access_point(self): + """" + Test park mode none without access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=none" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] != 'park' + + + def test_last_section_mode_park_mode_on_street_with_access_point(self): + """" + Test park mode on street with access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=on_street&_access_points=true" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 0: + assert len( journey['sections'][0]['vias']) > 0 + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] == 'park' + assert journey['sections'][1]['type'] == 'street_network' + + # Verify if the park sections doesnt have any from and to. + assert journey['sections'][1]['from']["embedded_type"] is None + assert journey['sections'][1]['to']["embedded_type"] is None + + + def test_last_section_mode_park_mode_on_street_without_access_point(self): + """" + Test park mode on street without access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=on_street" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 0: + assert len( journey['sections'][0]['vias']) > 0 + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] == 'park' + assert journey['sections'][1]['type'] == 'street_network' + + # Verify if the park sections doesnt have any from and to. + assert journey['sections'][1]['from']["embedded_type"] is None + assert journey['sections'][1]['to']["embedded_type"] is None + + + def test_last_section_mode_park_mode_park_and_ride_with_access_point(self): + """" + Test park mode park and ride with access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride&_access_points=true" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] != 'park' + + def test_last_section_mode_park_mode_park_and_ride_without_access_point(self): + """" + Test park mode park and ride without access point + """ + query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride" + response = self.query(query) + assert len(response['journeys']) > 0 + + for journey in response['journeys']: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] != 'park' From a18aa30833fa0a959bd7b84bb47deaec03af13d0 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Thu, 28 Nov 2024 11:35:48 +0100 Subject: [PATCH 05/20] revert some changes --- source/jormungandr/jormungandr/instance.py | 2 - .../jormungandr/interfaces/v1/Journeys.py | 21 +++++----- .../interfaces/v1/journey_common.py | 3 +- .../jormungandr/scenarios/distributed.py | 8 +--- .../scenarios/helper_classes/helper_utils.py | 39 ++++++++++--------- .../jormungandr/scenarios/new_default.py | 3 -- 6 files changed, 31 insertions(+), 45 deletions(-) diff --git a/source/jormungandr/jormungandr/instance.py b/source/jormungandr/jormungandr/instance.py index 4d80c1bcb2..8a3c551dbc 100644 --- a/source/jormungandr/jormungandr/instance.py +++ b/source/jormungandr/jormungandr/instance.py @@ -1039,7 +1039,6 @@ def _get_street_network(self, mode, request): :param request: This parameter in required only for file configuration. :return: street_network backend connector for the mode """ - if app.config[str('DISABLE_DATABASE')]: return self._streetnetwork_backend_manager.get_street_network_legacy(self, mode, request) else: @@ -1060,7 +1059,6 @@ def get_street_network(self, mode, request): if mode != fallback_modes.FallbackModes.car.name: return self._get_street_network(mode, request) - walking_service = self._get_street_network(fallback_modes.FallbackModes.walking.name, request) car_service = self._get_street_network(fallback_modes.FallbackModes.car.name, request) return street_network.CarWithPark( diff --git a/source/jormungandr/jormungandr/interfaces/v1/Journeys.py b/source/jormungandr/jormungandr/interfaces/v1/Journeys.py index 7d00a71f10..306b5612fd 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/Journeys.py +++ b/source/jormungandr/jormungandr/interfaces/v1/Journeys.py @@ -142,9 +142,6 @@ def wrapper(*args, **kwargs): args['from'] = journey['from']['id'] args['rel'] = 'journeys' journey['links'] = [create_external_link('v1.journeys', **args)] - - - elif allowed_ids and 'public_transport' in (s['type'] for s in journey['sections']): # exactly one first_section_mode if any(s['type'].startswith('bss') for s in journey['sections'][:2]): @@ -438,15 +435,15 @@ def wrapper(*args, **kwargs): for j in response.get('journeys', []): if 'sections' not in j: continue - # logging.debug( - # 'for journey changing origin: {old_o} to {new_o}' - # ', destination to {old_d} to {new_d}'.format( - # old_o=j.get('sections', [{}])[0].get('from').get('id'), - # new_o=(g.origin_detail or {}).get('id'), - # old_d=j.get('sections', [{}])[-1].get('to').get('id'), - # new_d=(g.destination_detail or {}).get('id'), - # ) - # ) + logging.debug( + 'for journey changing origin: {old_o} to {new_o}' + ', destination to {old_d} to {new_d}'.format( + old_o=j.get('sections', [{}])[0].get('from').get('id'), + new_o=(g.origin_detail or {}).get('id'), + old_d=j.get('sections', [{}])[-1].get('to').get('id'), + new_d=(g.destination_detail or {}).get('id'), + ) + ) if g.origin_detail: self.clean_global_origin_destination_detail(g.origin_detail) j['sections'][0]['from'] = g.origin_detail diff --git a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py index 27b6246612..fb5e9c9d90 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py +++ b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py @@ -232,7 +232,6 @@ def __init__(self, output_type_serializer): 'first_section_mode[]=bike&last_section_mode[]=walking&' 'last_section_mode[]=bss&last_section_mode[]=bike`', ) - parser_get.add_argument( "last_section_mode[]", type=OptionValue(fallback_modes.all_fallback_modes), @@ -246,7 +245,7 @@ def __init__(self, output_type_serializer): type=OptionValue(park_modes.all_park_modes), dest="park_mode", action="append", - help='Force the park mode if the first section is by bike\n' + help='Force the park mode if the first section is by bike\n', ) # for retrocompatibility purpose, we duplicate (without []): parser_get.add_argument( diff --git a/source/jormungandr/jormungandr/scenarios/distributed.py b/source/jormungandr/jormungandr/scenarios/distributed.py index 05fa63d988..3d9f65fb48 100644 --- a/source/jormungandr/jormungandr/scenarios/distributed.py +++ b/source/jormungandr/jormungandr/scenarios/distributed.py @@ -343,7 +343,6 @@ def finalise_journeys(self, future_manager, request, responses, context, instanc for response in responses: pt_journey_fare_pool.async_compute_fare(response, request_id) - wait_and_complete_pt_journey( requested_orig_obj=context.requested_orig_obj, requested_dest_obj=context.requested_dest_obj, @@ -357,8 +356,6 @@ def finalise_journeys(self, future_manager, request, responses, context, instanc journeys=journeys_to_complete, request_id="{}_complete_pt_journey".format(request_id), ) - - if request['_loki_compute_pt_journey_fare'] is True and request['_pt_planner'] == "loki": wait_and_complete_pt_journey_fare( pt_elements=journeys_to_complete, pt_journey_fare_pool=pt_journey_fare_pool @@ -593,10 +590,7 @@ def graphical_isochrones(self, request, instance): ] = instance.additional_time_after_first_section_taxi if request.get('on_street_bike_parking_duration') is None: - request[ - 'on_street_bike_parking_duration' - ] = instance.on_street_bike_parking_duration - + request['on_street_bike_parking_duration'] = instance.on_street_bike_parking_duration krakens_call = set({(request["origin_mode"][0], request["destination_mode"][0], "indifferent")}) pt_object_origin = None diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py index 16fb5ef829..acff40ef3c 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py @@ -214,9 +214,6 @@ def _extend_with_bike_park_street_network(origin, begin_date_time, destination): return bike_park_to_sp_section - - - def _extend_with_car_park( fallback_dp, pt_journey, fallback_type, walking_speed, car_park, car_park_duration, car_park_crowfly_duration ): @@ -415,6 +412,7 @@ def add_poi_access_point_in_sections(fallback_type, via_poi_access, sections): poi_access.is_exit = True poi_access.is_entrance = True + def _update_journey(journey, park_section, street_mode_section, to_replace, new_fallbacks): journey.duration += park_section.duration + street_mode_section.duration journey.durations.total += park_section.duration + street_mode_section.duration @@ -424,7 +422,10 @@ def _update_journey(journey, park_section, street_mode_section, to_replace, new_ journey.sections.extend(new_fallbacks) journey.nb_sections += 1 -def _update_fallback_with_bike_mode(journey, fallback_dp, fallback_period_extremity, fallback_type, via_pt_access, via_poi_access,**kwargs): + +def _update_fallback_with_bike_mode( + journey, fallback_dp, fallback_period_extremity, fallback_type, via_pt_access, via_poi_access, **kwargs +): """ Replace journey's fallback sections with the given fallback_dp. @@ -442,16 +443,21 @@ def _update_fallback_with_bike_mode(journey, fallback_dp, fallback_period_extrem s.begin_date_time += kwargs["additional_time"] s.end_date_time += kwargs["additional_time"] park_section = _extend_with_bike_park(fallback_sections[-1].end_date_time, kwargs["additional_time"]) - street_mode_section = _extend_with_bike_park_street_network(fallback_sections[-1].destination, park_section.end_date_time, journey.sections[0].destination) + street_mode_section = _extend_with_bike_park_street_network( + fallback_sections[-1].destination, park_section.end_date_time, journey.sections[0].destination + ) _update_journey(journey, park_section, street_mode_section, journey.sections[0], fallback_sections) elif fallback_type == StreetNetworkPathType.ENDING_FALLBACK and kwargs["destination_mode"] == ["bike"]: - street_mode_section = _extend_with_bike_park_street_network(fallback_sections[0].destination, fallback_sections[0].begin_date_time, journey.sections[-1].destination) + street_mode_section = _extend_with_bike_park_street_network( + fallback_sections[0].destination, + fallback_sections[0].begin_date_time, + journey.sections[-1].destination, + ) park_section = _extend_with_bike_park(street_mode_section.begin_date_time, kwargs["additional_time"]) fallback_sections[0].begin_date_time += kwargs["additional_time"] _update_journey(journey, park_section, street_mode_section, journey.sections[-1], fallback_sections) - add_poi_access_point_in_sections(fallback_type, via_poi_access, fallback_sections) if isinstance(via_pt_access, type_pb2.PtObject) and via_pt_access.embedded_type == type_pb2.ACCESS_POINT: @@ -462,9 +468,6 @@ def _update_fallback_with_bike_mode(journey, fallback_dp, fallback_period_extrem journey.sections.sort(key=cmp_to_key(SectionSorter())) - - - def _update_fallback_sections( journey, fallback_dp, fallback_period_extremity, fallback_type, via_pt_access, via_poi_access ): @@ -712,7 +715,9 @@ def _build_fallback( fallback_dp_copy, fallback_type, requested_obj, via_poi_access, language ) - if request["park_mode"] == ["on_street"] and (request["origin_mode"] == ["bike"] or request["destination_mode"] == ["bike"]): + if request["park_mode"] == ["on_street"] and ( + request["origin_mode"] == ["bike"] or request["destination_mode"] == ["bike"] + ): _update_fallback_with_bike_mode( pt_journey, fallback_dp_copy, @@ -720,10 +725,10 @@ def _build_fallback( fallback_type, via_pt_access, via_poi_access, - park_mode = request["park_mode"], - origin_mode = request["origin_mode"], - destination_mode = request["destination_mode"], - additional_time = request["on_street_bike_parking_duration"] + park_mode=request["park_mode"], + origin_mode=request["origin_mode"], + destination_mode=request["destination_mode"], + additional_time=request["on_street_bike_parking_duration"], ) else: _update_fallback_sections( @@ -781,13 +786,9 @@ def get_max_fallback_duration(request, mode, dp_future, direct_path_timeout): :return: max_fallback_duration """ # 30 minutes by default - print("request", request) max_duration = request.get('max_{}_duration_to_pt'.format(mode), 1800) - print("max_duration", max_duration) - print(str(dp_future)) dp = dp_future.wait_and_get(timeout=direct_path_timeout) if dp_future else None dp_duration = dp.journeys[0].durations.total if getattr(dp, 'journeys', None) else max_duration - return min(max_duration, dp_duration) diff --git a/source/jormungandr/jormungandr/scenarios/new_default.py b/source/jormungandr/jormungandr/scenarios/new_default.py index fd7bc311c2..47053d9fbc 100644 --- a/source/jormungandr/jormungandr/scenarios/new_default.py +++ b/source/jormungandr/jormungandr/scenarios/new_default.py @@ -1449,9 +1449,6 @@ def fill_journeys(self, request_type, api_request, instance): api_request, responses, distributed_context, instance, api_request['debug'], request_id ) - - - # We need to reapply some filter after 'finalise_journeys' because # journeys with crow_fly bss and crow_fly walking couldn't be compared # but can results in street_network walking in both case From 6016cceffbe8212462080dd9efba4678f5d66bce Mon Sep 17 00:00:00 2001 From: Pondonda Date: Thu, 28 Nov 2024 13:46:02 +0100 Subject: [PATCH 06/20] pre commit fix --- .../jormungandr/jormungandr/fallback_modes.py | 1 - source/jormungandr/jormungandr/park_modes.py | 5 +-- .../helper_classes/streetnetwork_path.py | 1 + .../jormungandr/street_network/taxi.py | 2 + source/jormungandr/tests/park_mode_tests.py | 43 ++++++++----------- source/tyr/tyr/resources.py | 6 +-- 6 files changed, 23 insertions(+), 35 deletions(-) diff --git a/source/jormungandr/jormungandr/fallback_modes.py b/source/jormungandr/jormungandr/fallback_modes.py index 11514c38ab..dc64217375 100644 --- a/source/jormungandr/jormungandr/fallback_modes.py +++ b/source/jormungandr/jormungandr/fallback_modes.py @@ -88,5 +88,4 @@ def get_allowed_combinations_str(cls): all_fallback_modes = FallbackModes.modes_str() - allowed_combinations = FallbackModes.get_allowed_combinations_str() diff --git a/source/jormungandr/jormungandr/park_modes.py b/source/jormungandr/jormungandr/park_modes.py index 216fc99982..d39554cced 100644 --- a/source/jormungandr/jormungandr/park_modes.py +++ b/source/jormungandr/jormungandr/park_modes.py @@ -39,18 +39,15 @@ class ParkMode(Enum): on_street = response_pb2.OnStreet park_and_ride = response_pb2.ParkAndRide - @classmethod def modes_str(cls): return {e.name for e in cls} - @classmethod def modes_enum(cls): return set(cls) - @classmethod def get_allowed_combinations_enums(cls): def _combi(first_sections_modes, last_section_modes): @@ -61,11 +58,11 @@ def _combi(first_sections_modes, last_section_modes): return _combi(cls.modes_enum(), cls.modes_enum()) - @classmethod def get_allowed_combinations_str(cls): # python 2/3 portability import six + allowed_combinations_enum = cls.get_allowed_combinations_enums() # transform all enum to str return set(six.moves.map(lambda modes: (modes[0].name, modes[1].name), allowed_combinations_enum)) diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py b/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py index aba6034c05..16e87444bb 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py @@ -225,6 +225,7 @@ def _async_request(self): self._futures.append(self._future_manager.create_future(self._do_request, origin, destination)) def wait_and_get(self, timeout=None): + # timeout=None -> wait forever... timer = gevent.timeout.Timeout(timeout, exception=False) diff --git a/source/jormungandr/jormungandr/street_network/taxi.py b/source/jormungandr/jormungandr/street_network/taxi.py index e5584abc1a..3bc38cf5a6 100644 --- a/source/jormungandr/jormungandr/street_network/taxi.py +++ b/source/jormungandr/jormungandr/street_network/taxi.py @@ -35,6 +35,8 @@ from jormungandr import utils, fallback_modes as fm from jormungandr.utils import SectionSorter from functools import cmp_to_key + + from navitiacommon import response_pb2 diff --git a/source/jormungandr/tests/park_mode_tests.py b/source/jormungandr/tests/park_mode_tests.py index 8510ec9db0..f836c5a26a 100644 --- a/source/jormungandr/tests/park_mode_tests.py +++ b/source/jormungandr/tests/park_mode_tests.py @@ -28,10 +28,10 @@ # www.navitia.io - from __future__ import absolute_import, print_function, unicode_literals, division from .tests_mechanism import AbstractTestFixture, dataset + @dataset({"park_modes_test": {}}) class TestParkMode(AbstractTestFixture): """ @@ -39,7 +39,7 @@ class TestParkMode(AbstractTestFixture): """ def test_first_section_park_mode_none_with_access_point(self): - """" + """ " Test park mode none with _access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=none&_access_points=true" @@ -51,9 +51,8 @@ def test_first_section_park_mode_none_with_access_point(self): assert journey['sections'][0]['mode'] == 'bike' assert journey['sections'][1]['type'] != 'park' - def test_first_section_park_mode_none_without_access_point(self): - """" + """ " Test park mode none without access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=none" @@ -65,9 +64,8 @@ def test_first_section_park_mode_none_without_access_point(self): assert journey['sections'][0]['mode'] == 'bike' assert journey['sections'][1]['type'] != 'park' - def test_first_section_park_mode_on_street_with_access_point(self): - """" + """ " Test park mode on street with access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=on_street&_access_points=true" @@ -76,7 +74,7 @@ def test_first_section_park_mode_on_street_with_access_point(self): for journey in response['journeys']: if len(journey['sections']) > 0: - assert len( journey['sections'][0]['vias']) > 0 + assert len(journey['sections'][0]['vias']) > 0 assert journey['sections'][0]['mode'] == 'bike' assert journey['sections'][1]['type'] == 'park' assert journey['sections'][1]['type'] == 'street_network' @@ -85,9 +83,8 @@ def test_first_section_park_mode_on_street_with_access_point(self): assert journey['sections'][1]['from']["embedded_type"] is None assert journey['sections'][1]['to']["embedded_type"] is None - def test_first_section_park_mode_on_street_without_access_point(self): - """" + """ " Test park mode on street without access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=on_street" @@ -96,7 +93,7 @@ def test_first_section_park_mode_on_street_without_access_point(self): for journey in response['journeys']: if len(journey['sections']) > 0: - assert len( journey['sections'][0]['vias']) > 0 + assert len(journey['sections'][0]['vias']) > 0 assert journey['sections'][0]['mode'] == 'bike' assert journey['sections'][1]['type'] == 'park' assert journey['sections'][1]['type'] == 'street_network' @@ -105,9 +102,8 @@ def test_first_section_park_mode_on_street_without_access_point(self): assert journey['sections'][1]['from']["embedded_type"] is None assert journey['sections'][1]['to']["embedded_type"] is None - def test_first_section_park_mode_park_and_ride_with_access_point(self): - """" + """ " Test park mode park and ride with access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride&_access_points=true" @@ -120,7 +116,7 @@ def test_first_section_park_mode_park_and_ride_with_access_point(self): assert journey['sections'][1]['type'] != 'park' def test_first_section_park_mode_park_and_ride_without_access_point(self): - """" + """ " Test park mode park and ride without access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride" @@ -132,9 +128,8 @@ def test_first_section_park_mode_park_and_ride_without_access_point(self): assert journey['sections'][0]['mode'] == 'bike' assert journey['sections'][1]['type'] != 'park' - def test_last_section_mode_park_mode_none_with_access_point(self): - """" + """ " Test park mode none with _access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=none&_access_points=true" @@ -146,9 +141,8 @@ def test_last_section_mode_park_mode_none_with_access_point(self): assert journey['sections'][0]['mode'] == 'bike' assert journey['sections'][1]['type'] != 'park' - def test_last_section_mode_park_mode_none_without_access_point(self): - """" + """ " Test park mode none without access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=none" @@ -160,9 +154,8 @@ def test_last_section_mode_park_mode_none_without_access_point(self): assert journey['sections'][0]['mode'] == 'bike' assert journey['sections'][1]['type'] != 'park' - def test_last_section_mode_park_mode_on_street_with_access_point(self): - """" + """ " Test park mode on street with access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=on_street&_access_points=true" @@ -171,7 +164,7 @@ def test_last_section_mode_park_mode_on_street_with_access_point(self): for journey in response['journeys']: if len(journey['sections']) > 0: - assert len( journey['sections'][0]['vias']) > 0 + assert len(journey['sections'][0]['vias']) > 0 assert journey['sections'][0]['mode'] == 'bike' assert journey['sections'][1]['type'] == 'park' assert journey['sections'][1]['type'] == 'street_network' @@ -180,9 +173,8 @@ def test_last_section_mode_park_mode_on_street_with_access_point(self): assert journey['sections'][1]['from']["embedded_type"] is None assert journey['sections'][1]['to']["embedded_type"] is None - def test_last_section_mode_park_mode_on_street_without_access_point(self): - """" + """ " Test park mode on street without access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=on_street" @@ -191,7 +183,7 @@ def test_last_section_mode_park_mode_on_street_without_access_point(self): for journey in response['journeys']: if len(journey['sections']) > 0: - assert len( journey['sections'][0]['vias']) > 0 + assert len(journey['sections'][0]['vias']) > 0 assert journey['sections'][0]['mode'] == 'bike' assert journey['sections'][1]['type'] == 'park' assert journey['sections'][1]['type'] == 'street_network' @@ -200,9 +192,8 @@ def test_last_section_mode_park_mode_on_street_without_access_point(self): assert journey['sections'][1]['from']["embedded_type"] is None assert journey['sections'][1]['to']["embedded_type"] is None - def test_last_section_mode_park_mode_park_and_ride_with_access_point(self): - """" + """ " Test park mode park and ride with access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride&_access_points=true" @@ -215,7 +206,7 @@ def test_last_section_mode_park_mode_park_and_ride_with_access_point(self): assert journey['sections'][1]['type'] != 'park' def test_last_section_mode_park_mode_park_and_ride_without_access_point(self): - """" + """ " Test park mode park and ride without access point """ query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride" diff --git a/source/tyr/tyr/resources.py b/source/tyr/tyr/resources.py index 95373c6061..a3309e9a32 100644 --- a/source/tyr/tyr/resources.py +++ b/source/tyr/tyr/resources.py @@ -711,7 +711,6 @@ def put(self, version=0, id=None, name=None): default=instance.additional_time_before_last_section_taxi, ) - parser.add_argument( "on_street_bike_parking_duration", type=int, @@ -720,13 +719,12 @@ def put(self, version=0, id=None, name=None): default=instance.on_street_bike_parking_duration, ) - parser.add_argument( 'additional_time_before_first_section_bike', type=int, help='additional time after the bike section when used as first section mode', location=('json', 'values'), - default=instance.additional_time_before_first_section_bike + default=instance.additional_time_before_first_section_bike, ) parser.add_argument( @@ -734,7 +732,7 @@ def put(self, version=0, id=None, name=None): type=int, help='additional time before the bike section when used as first section mode', location=('json', 'values'), - default=instance.additional_time_before_first_section_bike + default=instance.additional_time_before_first_section_bike, ) parser.add_argument( From 2a8040ce7e811d9e5c630d4075662ef27b9b9f04 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Thu, 28 Nov 2024 15:54:35 +0100 Subject: [PATCH 07/20] adding bragi call --- .../jormungandr/scenarios/distributed.py | 5 +- .../helper_classes/complete_pt_journey.py | 4 +- .../helper_classes/fallback_durations.py | 2 +- .../scenarios/helper_classes/helper_utils.py | 46 +++++++++-------- .../scenarios/helper_classes/place_by_uri.py | 2 +- .../helper_classes/places_free_access.py | 2 +- .../helper_classes/proximities_by_crowfly.py | 3 +- .../scenarios/helper_classes/pt_journey.py | 2 +- .../helper_classes/streetnetwork_path.py | 2 +- .../helper_classes/timer_logger_helper.py | 50 +++++++++++++++++++ 10 files changed, 90 insertions(+), 28 deletions(-) create mode 100644 source/jormungandr/jormungandr/scenarios/helper_classes/timer_logger_helper.py diff --git a/source/jormungandr/jormungandr/scenarios/distributed.py b/source/jormungandr/jormungandr/scenarios/distributed.py index 3d9f65fb48..d35242809f 100644 --- a/source/jormungandr/jormungandr/scenarios/distributed.py +++ b/source/jormungandr/jormungandr/scenarios/distributed.py @@ -53,7 +53,7 @@ from jormungandr.new_relic import record_custom_parameter from navitiacommon import response_pb2, type_pb2 from flask_restful import abort -from .helper_classes.helper_utils import timed_logger +from .helper_classes.timer_logger_helper import timed_logger from .helper_classes.helper_exceptions import ( NoGraphicalIsochroneFoundException, PtException, @@ -355,6 +355,9 @@ def finalise_journeys(self, future_manager, request, responses, context, instanc request=request, journeys=journeys_to_complete, request_id="{}_complete_pt_journey".format(request_id), + instance=instance, + future_manager=future_manager, + _request_id=request_id, ) if request['_loki_compute_pt_journey_fare'] is True and request['_pt_planner'] == "loki": wait_and_complete_pt_journey_fare( diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/complete_pt_journey.py b/source/jormungandr/jormungandr/scenarios/helper_classes/complete_pt_journey.py index 38c95fa7fc..4df5bfef5d 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/complete_pt_journey.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/complete_pt_journey.py @@ -32,9 +32,9 @@ complete_pt_journey, compute_fallback, _build_crowflies, - timed_logger, complete_transfer, ) +from .timer_logger_helper import timed_logger from .helper_exceptions import InvalidDateBoundException from jormungandr.street_network.street_network import StreetNetworkPathType from collections import namedtuple @@ -166,6 +166,7 @@ def wait_and_complete_pt_journey( request, journeys, request_id, + **kwargs ): """ In this function, we compute all fallback path once the pt journey is finished, then we build the @@ -206,6 +207,7 @@ def wait_and_complete_pt_journey( orig_fallback_durations_pool=orig_fallback_durations_pool, dest_fallback_durations_pool=dest_fallback_durations_pool, request=request, + **kwargs ) if {pt_element.dep_mode, pt_element.arr_mode} & {'car', 'car_no_park'}: tag_LEZ(pt_element.pt_journeys) diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/fallback_durations.py b/source/jormungandr/jormungandr/scenarios/helper_classes/fallback_durations.py index 158089d60e..9b7b5581ef 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/fallback_durations.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/fallback_durations.py @@ -38,7 +38,7 @@ from jormungandr import new_relic, excluded_zones_manager from jormungandr.fallback_modes import FallbackModes import logging -from .helper_utils import timed_logger +from .timer_logger_helper import timed_logger import six from navitiacommon import type_pb2 from jormungandr.exceptions import GeoveloTechnicalError diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py index acff40ef3c..3a8a9b8c23 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py @@ -40,14 +40,13 @@ ) from jormungandr.street_network.utils import crowfly_distance_between from jormungandr.fallback_modes import FallbackModes, all_fallback_modes +from jormungandr.scenarios.helper_classes.place_by_uri import PlaceByUri from .helper_exceptions import * from navitiacommon import response_pb2, type_pb2 import copy import logging import six from functools import cmp_to_key -from contextlib import contextmanager -import time CAR_PARK_DURATION = 300 # secs @@ -426,6 +425,7 @@ def _update_journey(journey, park_section, street_mode_section, to_replace, new_ def _update_fallback_with_bike_mode( journey, fallback_dp, fallback_period_extremity, fallback_type, via_pt_access, via_poi_access, **kwargs ): + """ Replace journey's fallback sections with the given fallback_dp. @@ -439,6 +439,14 @@ def _update_fallback_with_bike_mode( # We have to create the link between the fallback and the pt part manually here if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK and kwargs["origin_mode"] == ["bike"]: + place_by_uri_instance = PlaceByUri( + kwargs["future_manager"], + kwargs["instance"], + fallback_sections[-1].destination.uri, + kwargs["request_id"], + ) + address = place_by_uri_instance.wait_and_get() + fallback_sections[-1].destination.CopyFrom(address) for s in journey.sections: s.begin_date_time += kwargs["additional_time"] s.end_date_time += kwargs["additional_time"] @@ -449,6 +457,14 @@ def _update_fallback_with_bike_mode( _update_journey(journey, park_section, street_mode_section, journey.sections[0], fallback_sections) elif fallback_type == StreetNetworkPathType.ENDING_FALLBACK and kwargs["destination_mode"] == ["bike"]: + place_by_uri_instance = PlaceByUri( + kwargs["future_manager"], + kwargs["instance"], + fallback_sections[0].destination.uri, + kwargs["request_id"], + ) + address = place_by_uri_instance.wait_and_get() + fallback_sections[0].destination.CopyFrom(address) street_mode_section = _extend_with_bike_park_street_network( fallback_sections[0].destination, fallback_sections[0].begin_date_time, @@ -652,6 +668,7 @@ def _build_fallback( fallback_durations_pool, request, fallback_type, + **kwargs ): accessibles_by_crowfly = obj_accessible_by_crowfly.wait_and_get() fallback_durations = fallback_durations_pool.wait_and_get(mode) @@ -729,6 +746,10 @@ def _build_fallback( origin_mode=request["origin_mode"], destination_mode=request["destination_mode"], additional_time=request["on_street_bike_parking_duration"], + instance=kwargs["instance"], + future_manager=kwargs["future_manager"], + request_id=kwargs["_request_id"], + request=request, ) else: _update_fallback_sections( @@ -887,6 +908,7 @@ def complete_pt_journey( orig_fallback_durations_pool, dest_fallback_durations_pool, request, + **kwargs ): """ We complete the pt_journey by adding the beginning fallback and the ending fallback @@ -905,6 +927,7 @@ def complete_pt_journey( orig_fallback_durations_pool, request=request, fallback_type=StreetNetworkPathType.BEGINNING_FALLBACK, + **kwargs ) pt_journey = _build_fallback( @@ -916,6 +939,7 @@ def complete_pt_journey( dest_fallback_durations_pool, request=request, fallback_type=StreetNetworkPathType.ENDING_FALLBACK, + **kwargs ) logger.debug("finish building pt journey starts with %s and ends with %s", dep_mode, arr_mode) @@ -954,24 +978,6 @@ def check_final_results_or_raise(final_results, orig_fallback_durations_pool, de ) -@contextmanager -def timed_logger(logger, task_name, request_id): - start = time.time() - try: - yield logger - finally: - end = time.time() - elapsed_time = (end - start) * 1000 - start_in_ms = int(start * 1000) - end_in_ms = int(end * 1000) - - logger.info( - "Task : {}, request : {}, start : {}, end : {}, elapsed time: {} ms".format( - task_name, request_id, start_in_ms, end_in_ms, '%.2e' % elapsed_time - ) - ) - - def complete_transfer(pt_journey, transfer_pool): """ We complete the pt_journey by adding to transfer section : diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/place_by_uri.py b/source/jormungandr/jormungandr/scenarios/helper_classes/place_by_uri.py index 224a0965cb..2aa267bcd9 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/place_by_uri.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/place_by_uri.py @@ -29,7 +29,7 @@ from __future__ import absolute_import from jormungandr import new_relic import logging -from .helper_utils import timed_logger +from .timer_logger_helper import timed_logger class PlaceByUri: diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/places_free_access.py b/source/jormungandr/jormungandr/scenarios/helper_classes/places_free_access.py index e6f975e4ad..cd76e3d063 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/places_free_access.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/places_free_access.py @@ -33,7 +33,7 @@ from jormungandr import utils, new_relic from collections import namedtuple import logging -from .helper_utils import timed_logger +from .timer_logger_helper import timed_logger from jormungandr.street_network.utils import crowfly_distance_between FreeAccessObject = namedtuple('FreeAccessObject', ['uri', 'lon', 'lat']) diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/proximities_by_crowfly.py b/source/jormungandr/jormungandr/scenarios/helper_classes/proximities_by_crowfly.py index 675d27f103..03d3159ac5 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/proximities_by_crowfly.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/proximities_by_crowfly.py @@ -29,7 +29,8 @@ from __future__ import absolute_import import jormungandr.street_network.utils -from .helper_utils import get_max_fallback_duration, timed_logger +from .helper_utils import get_max_fallback_duration +from .timer_logger_helper import timed_logger from jormungandr import utils, new_relic, fallback_modes as fm import logging from navitiacommon import type_pb2 diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/pt_journey.py b/source/jormungandr/jormungandr/scenarios/helper_classes/pt_journey.py index de40d334fa..d1100aa92f 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/pt_journey.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/pt_journey.py @@ -37,7 +37,7 @@ import copy import logging from functools import cmp_to_key -from .helper_utils import timed_logger +from .timer_logger_helper import timed_logger PtPoolElement = namedtuple('PtPoolElement', ['dep_mode', 'arr_mode', 'pt_journey']) diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py b/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py index 16e87444bb..9833f891d1 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/streetnetwork_path.py @@ -32,7 +32,6 @@ import logging import gevent from .helper_utils import ( - timed_logger, prepend_first_coord, append_last_coord, extend_path_with_via_poi_access, @@ -40,6 +39,7 @@ is_valid_direct_path_streetwork, is_valid_direct_path, ) +from .timer_logger_helper import timed_logger from navitiacommon import type_pb2, response_pb2 from jormungandr.exceptions import GeoveloTechnicalError from .helper_exceptions import StreetNetworkException diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/timer_logger_helper.py b/source/jormungandr/jormungandr/scenarios/helper_classes/timer_logger_helper.py new file mode 100644 index 0000000000..56af1e9f29 --- /dev/null +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/timer_logger_helper.py @@ -0,0 +1,50 @@ +# encoding: utf-8 +# Copyright (c) 2001-2024, Hove and/or its affiliates. All rights reserved. +# +# This file is part of Navitia, +# the software to build cool stuff with public transport. +# +# Hope you'll enjoy and contribute to this project, +# powered by Hove (www.hove.com). +# Help us simplify mobility and open public transport: +# a non ending quest to the responsive locomotion way of traveling! +# +# LICENCE: This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# Stay tuned using +# twitter @navitia +# channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org +# https://groups.google.com/d/forum/navitia +# www.navitia.io + +from contextlib import contextmanager +import time + + +@contextmanager +def timed_logger(logger, task_name, request_id): + start = time.time() + try: + yield logger + finally: + end = time.time() + elapsed_time = (end - start) * 1000 + start_in_ms = int(start * 1000) + end_in_ms = int(end * 1000) + + logger.info( + "Task : {}, request : {}, start : {}, end : {}, elapsed time: {} ms".format( + task_name, request_id, start_in_ms, end_in_ms, '%.2e' % elapsed_time + ) + ) From 425335d0369b3c554abd880c0684cb4c8910dbfd Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 07:25:05 +0100 Subject: [PATCH 08/20] adding walking time --- .../jormungandr/default_settings.py | 4 +- .../jormungandr/jormungandr/fallback_modes.py | 1 + .../jormungandr/interfaces/v1/Journeys.py | 1 + source/jormungandr/jormungandr/park_modes.py | 8 +- .../scenarios/helper_classes/helper_utils.py | 180 +++++++++++--- source/jormungandr/tests/park_mode_tests.py | 219 ------------------ ...b9c_add_on_street_bike_parking_duration.py | 22 ++ source/tyr/tyr/resources.py | 16 -- 8 files changed, 179 insertions(+), 272 deletions(-) delete mode 100644 source/jormungandr/tests/park_mode_tests.py create mode 100644 source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py diff --git a/source/jormungandr/jormungandr/default_settings.py b/source/jormungandr/jormungandr/default_settings.py index eefc590a56..f6c773a581 100644 --- a/source/jormungandr/jormungandr/default_settings.py +++ b/source/jormungandr/jormungandr/default_settings.py @@ -12,7 +12,7 @@ } # 1000ms # path of the configuration file for each instances -INSTANCES_DIR = os.getenv('JORMUNGANDR_INSTANCES_DIR', './jormung_conf') +INSTANCES_DIR = os.getenv('JORMUNGANDR_INSTANCES_DIR', '/etc/jormungandr.d') INSTANCES_TIMEOUT = float(os.getenv('JORMUNGANDR_INSTANCES_TIMEOUT_S', 10)) @@ -32,7 +32,7 @@ 'JORMUNGANDR_SQLALCHEMY_DATABASE_URI', 'postgresql://navitia:navitia@localhost/jormungandr' ) -DISABLE_DATABASE = boolean(os.getenv('JORMUNGANDR_DISABLE_DATABASE', True)) +DISABLE_DATABASE = boolean(os.getenv('JORMUNGANDR_DISABLE_DATABASE', False)) # Active the asynchronous ridesharing mode ASYNCHRONOUS_RIDESHARING = boolean(os.getenv('JORMUNGANDR_ASYNCHRONOUS_RIDESHARING', False)) diff --git a/source/jormungandr/jormungandr/fallback_modes.py b/source/jormungandr/jormungandr/fallback_modes.py index dc64217375..11514c38ab 100644 --- a/source/jormungandr/jormungandr/fallback_modes.py +++ b/source/jormungandr/jormungandr/fallback_modes.py @@ -88,4 +88,5 @@ def get_allowed_combinations_str(cls): all_fallback_modes = FallbackModes.modes_str() + allowed_combinations = FallbackModes.get_allowed_combinations_str() diff --git a/source/jormungandr/jormungandr/interfaces/v1/Journeys.py b/source/jormungandr/jormungandr/interfaces/v1/Journeys.py index 306b5612fd..077a1000df 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/Journeys.py +++ b/source/jormungandr/jormungandr/interfaces/v1/Journeys.py @@ -75,6 +75,7 @@ from copy import deepcopy from jormungandr.travelers_profile import TravelerProfile from navitiacommon.constants import ENUM_LANGUAGE +import urllib.parse import base64 diff --git a/source/jormungandr/jormungandr/park_modes.py b/source/jormungandr/jormungandr/park_modes.py index d39554cced..34bb57bcbf 100644 --- a/source/jormungandr/jormungandr/park_modes.py +++ b/source/jormungandr/jormungandr/park_modes.py @@ -31,13 +31,13 @@ from enum import Enum -from navitiacommon import response_pb2 +from navitiacommon import request_pb2 class ParkMode(Enum): - none = response_pb2.NONE - on_street = response_pb2.OnStreet - park_and_ride = response_pb2.ParkAndRide + none = request_pb2.NONE + on_street = request_pb2.OnStreet + park_and_ride = request_pb2.ParkAndRide @classmethod def modes_str(cls): diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py index 3a8a9b8c23..153b0ee1d9 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py @@ -31,6 +31,7 @@ from __future__ import absolute_import, unicode_literals +from jormungandr.park_modes import ParkMode from jormungandr.street_network.street_network import StreetNetworkPathType from jormungandr.utils import ( PeriodExtremity, @@ -41,6 +42,7 @@ from jormungandr.street_network.utils import crowfly_distance_between from jormungandr.fallback_modes import FallbackModes, all_fallback_modes from jormungandr.scenarios.helper_classes.place_by_uri import PlaceByUri +import math from .helper_exceptions import * from navitiacommon import response_pb2, type_pb2 import copy @@ -201,15 +203,16 @@ def _extend_with_bike_park(begin_date_time, duration): return bike_park_section -def _extend_with_bike_park_street_network(origin, begin_date_time, destination): +def _extend_with_bike_park_street_network(origin, begin_date_time, destination, end_date_time, duration): bike_park_to_sp_section = response_pb2.Section() - bike_park_to_sp_section.id = "Section_2" + bike_park_to_sp_section.id = "Street_network_section_2" bike_park_to_sp_section.origin.CopyFrom(origin) bike_park_to_sp_section.destination.CopyFrom(destination) bike_park_to_sp_section.type = response_pb2.STREET_NETWORK bike_park_to_sp_section.street_network.mode = response_pb2.Walking bike_park_to_sp_section.begin_date_time = begin_date_time - # bike_park_to_sp_section.end_date_time = begin_date_time + duration + bike_park_to_sp_section.end_date_time = end_date_time + duration + bike_park_to_sp_section.duration = duration return bike_park_to_sp_section @@ -419,66 +422,181 @@ def _update_journey(journey, park_section, street_mode_section, to_replace, new_ journey.sections.remove(to_replace) journey.sections.extend([street_mode_section, park_section]) journey.sections.extend(new_fallbacks) - journey.nb_sections += 1 + journey.nb_sections += 2 + + +def haversine(cord1, cord2): + """ + Calculate the great-circle distance between two points on the Earth's surface using the Haversine formula. + + Parameters: + cord1 (object): An object with 'lat' and 'lon' attributes representing the latitude and longitude of the first point in degrees. + cord2 (object): An object with 'lat' and 'lon' attributes representing the latitude and longitude of the second point in degrees. + + Returns: + float: The distance between the two points in kilometers. + """ + lat1, lon1 = cord1.lat, cord1.lon + lat2, lon2 = cord2.lat, cord2.lon + # Radius of the Earth in kilometers + r = 6371.0 + + # Convert latitude and longitude from degrees to radians + lat1_rad, lon1_rad = math.radians(lat1), math.radians(lon1) + lat2_rad, lon2_rad = math.radians(lat2), math.radians(lon2) + + # Differences in coordinates + delta_lat = lat2_rad - lat1_rad + delta_lon = lon2_rad - lon1_rad + + # Haversine formula + a = math.sin(delta_lat / 2) ** 2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon / 2) ** 2 + c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) + + # Distance in kilometers + distance = r * c + return distance + + +def walking_time(cord1, cord2, speed_kmh=3): + """ + Calculate the walking time between two coordinates. + + Args: + cord1 (tuple): The (latitude, longitude) of the starting point. + cord2 (tuple): The (latitude, longitude) of the destination point. + speed_kmh (float, optional): Walking speed in kilometers per hour. Defaults to 5 km/h. + + Returns: + float: The walking time in secondes. + """ + distance = haversine(cord1, cord2) + # Time in hours + time_hours = distance / speed_kmh + # Convert to secondes + seconds = time_hours * 60 * 60 + return round(seconds) + + +def _get_place(kwargs, uri): + """ + Retrieve a place instance based on the provided URI. + + Args: + kwargs (dict): A dictionary containing the following keys: + - future_manager: The future manager instance. + - instance: The instance to be used. + - request_id: The ID of the request. + uri (str): The URI of the place to retrieve. + + Returns: + PlaceByUri: An instance of PlaceByUri after waiting for the result. + """ + place_by_uri_instance = PlaceByUri(kwargs["future_manager"], kwargs["instance"], uri, kwargs["request_id"]) + return place_by_uri_instance.wait_and_get() def _update_fallback_with_bike_mode( journey, fallback_dp, fallback_period_extremity, fallback_type, via_pt_access, via_poi_access, **kwargs ): - """ - Replace journey's fallback sections with the given fallback_dp. - - Note: the replacement is done in place of the journey + Updates the journey with bike mode fallback sections. + + This function updates the journey sections with bike mode fallback sections based on the fallback type + (BEGINNING_FALLBACK or ENDING_FALLBACK). It aligns the fallback direct path datetime, updates the section IDs, + and creates the necessary links between the fallback and public transport parts. It also handles the addition + of POI access points in the sections. + + Args: + journey (Journey): The journey object to be updated. + fallback_dp (DirectPath): The direct path object for the fallback. + fallback_period_extremity (datetime): The extremity datetime for the fallback period. + fallback_type (StreetNetworkPathType): The type of fallback (BEGINNING_FALLBACK or ENDING_FALLBACK). + via_pt_access (PtObject): The public transport access point object. + via_poi_access (POIObject): The point of interest access point object. + **kwargs: Additional keyword arguments, including: + - origin_mode (list): The mode of origin (e.g., ["bike"]). + - destination_mode (list): The mode of destination (e.g., ["bike"]). + - future_manager (FutureManager): The future manager instance. + - instance (Instance): The instance object. + - request_id (str): The request ID. + - additional_time (timedelta): The additional time to be added to the sections. + + Returns: + None """ + # Validate required arguments + if not all(kwargs.get(key) for key in ("future_manager", "instance", "request_id")): + raise EntryPointException( + "Future manager, instance, and request ID are required.", response_pb2.Error.internal_error + ) + aligned_fallback = _align_fallback_direct_path_datetime(fallback_dp, fallback_period_extremity) fallback_sections = aligned_fallback.journeys[0].sections - - # update the 'id' which isn't set _rename_fallback_sections_ids(fallback_sections) # We have to create the link between the fallback and the pt part manually here if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK and kwargs["origin_mode"] == ["bike"]: - place_by_uri_instance = PlaceByUri( - kwargs["future_manager"], - kwargs["instance"], - fallback_sections[-1].destination.uri, - kwargs["request_id"], - ) - address = place_by_uri_instance.wait_and_get() + address = _get_place(kwargs, fallback_sections[-1].destination.uri) + walktime = walking_time(address.address.coord, journey.sections[0].destination.stop_point.coord) fallback_sections[-1].destination.CopyFrom(address) for s in journey.sections: - s.begin_date_time += kwargs["additional_time"] - s.end_date_time += kwargs["additional_time"] + s.begin_date_time += kwargs["additional_time"] + walktime + s.end_date_time += kwargs["additional_time"] + walktime park_section = _extend_with_bike_park(fallback_sections[-1].end_date_time, kwargs["additional_time"]) street_mode_section = _extend_with_bike_park_street_network( - fallback_sections[-1].destination, park_section.end_date_time, journey.sections[0].destination + fallback_sections[-1].destination, + park_section.end_date_time, + journey.sections[0].destination, + (fallback_sections[-1].end_date_time + park_section.duration) - journey.sections[0].end_date_time, + walktime, + ) + street_mode_section.street_network.coordinates.extend( + [journey.sections[0].destination.stop_point.coord, fallback_sections[-1].destination.address.coord] ) _update_journey(journey, park_section, street_mode_section, journey.sections[0], fallback_sections) - + if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK and kwargs["origin_mode"] != ["bike"]: + section_to_replace = journey.sections[0] + journey.sections.remove(section_to_replace) + fallback_sections[-1].destination.CopyFrom(journey.sections[0].origin) + journey.sections.extend(fallback_sections) elif fallback_type == StreetNetworkPathType.ENDING_FALLBACK and kwargs["destination_mode"] == ["bike"]: - place_by_uri_instance = PlaceByUri( - kwargs["future_manager"], - kwargs["instance"], - fallback_sections[0].destination.uri, - kwargs["request_id"], + walktime = walking_time( + journey.sections[-1].origin.stop_point.coord, fallback_sections[0].origin.address.coord ) - address = place_by_uri_instance.wait_and_get() - fallback_sections[0].destination.CopyFrom(address) + address = _get_place(kwargs, fallback_sections[0].origin.uri) + fallback_sections[0].origin.CopyFrom(address) street_mode_section = _extend_with_bike_park_street_network( - fallback_sections[0].destination, + journey.sections[-1].origin, fallback_sections[0].begin_date_time, - journey.sections[-1].destination, + fallback_sections[0].origin, + (fallback_sections[0].begin_date_time + kwargs["additional_time"]) + - journey.sections[-1].begin_date_time, + walktime, ) park_section = _extend_with_bike_park(street_mode_section.begin_date_time, kwargs["additional_time"]) fallback_sections[0].begin_date_time += kwargs["additional_time"] + street_mode_section.street_network.coordinates.extend( + [journey.sections[-1].origin.stop_point.coord, fallback_sections[0].origin.address.coord] + ) _update_journey(journey, park_section, street_mode_section, journey.sections[-1], fallback_sections) + elif fallback_type == StreetNetworkPathType.ENDING_FALLBACK and kwargs["destination_mode"] != ["bike"]: + section_to_replace = journey.sections[-1] + journey.sections.remove(section_to_replace) + fallback_sections[0].origin.CopyFrom(journey.sections[-1].destination) + journey.sections.extend(fallback_sections) add_poi_access_point_in_sections(fallback_type, via_poi_access, fallback_sections) if isinstance(via_pt_access, type_pb2.PtObject) and via_pt_access.embedded_type == type_pb2.ACCESS_POINT: if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK: journey.sections[-1].vias.add().CopyFrom(via_pt_access.access_point) + target_section = next((s for s in journey.sections if s.id == "Street_network_section_2"), None) + if target_section: + target_section.vias.extend(journey.sections[-1].vias) + target_section.street_network.path_items.extend( + [journey.sections[-1].street_network.path_items[-1]] + ) else: journey.sections[0].vias.add().CopyFrom(via_pt_access.access_point) journey.sections.sort(key=cmp_to_key(SectionSorter())) @@ -732,7 +850,7 @@ def _build_fallback( fallback_dp_copy, fallback_type, requested_obj, via_poi_access, language ) - if request["park_mode"] == ["on_street"] and ( + if request["park_mode"] == [ParkMode.on_street.name] and ( request["origin_mode"] == ["bike"] or request["destination_mode"] == ["bike"] ): _update_fallback_with_bike_mode( diff --git a/source/jormungandr/tests/park_mode_tests.py b/source/jormungandr/tests/park_mode_tests.py deleted file mode 100644 index f836c5a26a..0000000000 --- a/source/jormungandr/tests/park_mode_tests.py +++ /dev/null @@ -1,219 +0,0 @@ -# Copyright (c) 2001-2024, Hove and/or its affiliates. All rights reserved. -# -# This file is part of Navitia, -# the software to build cool stuff with public transport. -# -# Hope you'll enjoy and contribute to this project, -# powered by Hove (www.hove.com). -# Help us simplify mobility and open public transport: -# a non ending quest to the responsive locomotion way of traveling! -# -# LICENCE: This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# Stay tuned using -# twitter @navitia -# channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org -# https://groups.google.com/d/forum/navitia -# www.navitia.io - - -from __future__ import absolute_import, print_function, unicode_literals, division -from .tests_mechanism import AbstractTestFixture, dataset - - -@dataset({"park_modes_test": {}}) -class TestParkMode(AbstractTestFixture): - """ - Test park mode features - """ - - def test_first_section_park_mode_none_with_access_point(self): - """ " - Test park mode none with _access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=none&_access_points=true" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 1: - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] != 'park' - - def test_first_section_park_mode_none_without_access_point(self): - """ " - Test park mode none without access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=none" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 1: - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] != 'park' - - def test_first_section_park_mode_on_street_with_access_point(self): - """ " - Test park mode on street with access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=on_street&_access_points=true" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 0: - assert len(journey['sections'][0]['vias']) > 0 - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] == 'park' - assert journey['sections'][1]['type'] == 'street_network' - - # Verify if the park sections doesnt have any from and to. - assert journey['sections'][1]['from']["embedded_type"] is None - assert journey['sections'][1]['to']["embedded_type"] is None - - def test_first_section_park_mode_on_street_without_access_point(self): - """ " - Test park mode on street without access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=on_street" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 0: - assert len(journey['sections'][0]['vias']) > 0 - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] == 'park' - assert journey['sections'][1]['type'] == 'street_network' - - # Verify if the park sections doesnt have any from and to. - assert journey['sections'][1]['from']["embedded_type"] is None - assert journey['sections'][1]['to']["embedded_type"] is None - - def test_first_section_park_mode_park_and_ride_with_access_point(self): - """ " - Test park mode park and ride with access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride&_access_points=true" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 1: - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] != 'park' - - def test_first_section_park_mode_park_and_ride_without_access_point(self): - """ " - Test park mode park and ride without access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&first_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 1: - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] != 'park' - - def test_last_section_mode_park_mode_none_with_access_point(self): - """ " - Test park mode none with _access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=none&_access_points=true" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 1: - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] != 'park' - - def test_last_section_mode_park_mode_none_without_access_point(self): - """ " - Test park mode none without access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=none" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 1: - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] != 'park' - - def test_last_section_mode_park_mode_on_street_with_access_point(self): - """ " - Test park mode on street with access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=on_street&_access_points=true" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 0: - assert len(journey['sections'][0]['vias']) > 0 - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] == 'park' - assert journey['sections'][1]['type'] == 'street_network' - - # Verify if the park sections doesnt have any from and to. - assert journey['sections'][1]['from']["embedded_type"] is None - assert journey['sections'][1]['to']["embedded_type"] is None - - def test_last_section_mode_park_mode_on_street_without_access_point(self): - """ " - Test park mode on street without access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=on_street" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 0: - assert len(journey['sections'][0]['vias']) > 0 - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] == 'park' - assert journey['sections'][1]['type'] == 'street_network' - - # Verify if the park sections doesnt have any from and to. - assert journey['sections'][1]['from']["embedded_type"] is None - assert journey['sections'][1]['to']["embedded_type"] is None - - def test_last_section_mode_park_mode_park_and_ride_with_access_point(self): - """ " - Test park mode park and ride with access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride&_access_points=true" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 1: - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] != 'park' - - def test_last_section_mode_park_mode_park_and_ride_without_access_point(self): - """ " - Test park mode park and ride without access point - """ - query = "v1/coverage/main_routing_test/journeys?from=2.36893%3B48.88413&to=2.28928%3B48.84710&last_section_mode%5B%5D=bike&park_mode%5B%5D=park_and_ride" - response = self.query(query) - assert len(response['journeys']) > 0 - - for journey in response['journeys']: - if len(journey['sections']) > 1: - assert journey['sections'][0]['mode'] == 'bike' - assert journey['sections'][1]['type'] != 'park' diff --git a/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py b/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py new file mode 100644 index 0000000000..ee35c94686 --- /dev/null +++ b/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py @@ -0,0 +1,22 @@ +"""empty message + +Revision ID: c3ba234a3b9c +Revises: fd13bb348665 +Create Date: 2024-11-29 11:45:56.806718 + +""" + +# revision identifiers, used by Alembic. +revision = 'c3ba234a3b9c' +down_revision = 'fd13bb348665' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('instance', sa.Column('on_street_bike_parking_duration', sa.Integer(), nullable=False)) + + +def downgrade(): + op.drop_column('instance', 'on_street_bike_parking_duration') diff --git a/source/tyr/tyr/resources.py b/source/tyr/tyr/resources.py index a3309e9a32..08ddf6cdf4 100644 --- a/source/tyr/tyr/resources.py +++ b/source/tyr/tyr/resources.py @@ -719,22 +719,6 @@ def put(self, version=0, id=None, name=None): default=instance.on_street_bike_parking_duration, ) - parser.add_argument( - 'additional_time_before_first_section_bike', - type=int, - help='additional time after the bike section when used as first section mode', - location=('json', 'values'), - default=instance.additional_time_before_first_section_bike, - ) - - parser.add_argument( - 'additional_time_before_last_section_bike', - type=int, - help='additional time before the bike section when used as first section mode', - location=('json', 'values'), - default=instance.additional_time_before_first_section_bike, - ) - parser.add_argument( 'max_additional_connections', type=int, From 19938cfd2e1121343ebd6801357dbe736ab93e5f Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 08:43:45 +0100 Subject: [PATCH 09/20] update navitia-proto version --- source/navitia-proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 160000 => 100644 source/navitia-proto diff --git a/source/navitia-proto b/source/navitia-proto deleted file mode 160000 index 1b261a831c..0000000000 --- a/source/navitia-proto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1b261a831c2be711d07d5682de8b05afd0764a87 diff --git a/source/navitia-proto b/source/navitia-proto new file mode 100644 index 0000000000..722192bced --- /dev/null +++ b/source/navitia-proto @@ -0,0 +1 @@ +Subproject commit 6a2edc1d043b6c8025707948e14029380a4a2a36 \ No newline at end of file From 4d2ab2737b86d86c2c1cfe87a213549baa9a6786 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 08:47:53 +0100 Subject: [PATCH 10/20] add new proto version --- source/navitia-proto | 1 - 1 file changed, 1 deletion(-) delete mode 100644 source/navitia-proto diff --git a/source/navitia-proto b/source/navitia-proto deleted file mode 100644 index 722192bced..0000000000 --- a/source/navitia-proto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6a2edc1d043b6c8025707948e14029380a4a2a36 \ No newline at end of file From cc5236f644c5c4c9498be2c2f6ab5b0e7e7d6c25 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 09:31:55 +0100 Subject: [PATCH 11/20] Add navitia-proto submodule --- .gitmodules | 2 +- source/navitia-proto | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 160000 source/navitia-proto diff --git a/.gitmodules b/.gitmodules index ffc744fde0..eb2fcfbff6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,7 +15,7 @@ url = git@github.com:hove-io/chaos-proto.git [submodule "source/navitia-proto"] path = source/navitia-proto - url = git@github.com:hove-io/navitia-proto.git + url = https://github.com/hove-io/navitia-proto.git [submodule "source/third_party/prometheus-cpp"] path = source/third_party/prometheus-cpp url = https://github.com/jupp0r/prometheus-cpp diff --git a/source/navitia-proto b/source/navitia-proto new file mode 160000 index 0000000000..6a2edc1d04 --- /dev/null +++ b/source/navitia-proto @@ -0,0 +1 @@ +Subproject commit 6a2edc1d043b6c8025707948e14029380a4a2a36 From 2bda5d69a27ab3da45083c89bf73c8f4cd6673cd Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 09:37:50 +0100 Subject: [PATCH 12/20] restore gitmodule --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index eb2fcfbff6..ffc744fde0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,7 +15,7 @@ url = git@github.com:hove-io/chaos-proto.git [submodule "source/navitia-proto"] path = source/navitia-proto - url = https://github.com/hove-io/navitia-proto.git + url = git@github.com:hove-io/navitia-proto.git [submodule "source/third_party/prometheus-cpp"] path = source/third_party/prometheus-cpp url = https://github.com/jupp0r/prometheus-cpp From f79aac7ae6a853e754a5a91b32ce708f7e3f0dc5 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 10:54:16 +0100 Subject: [PATCH 13/20] restor routing --- source/routing/raptor_api.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/routing/raptor_api.cpp b/source/routing/raptor_api.cpp index b44cb13318..d57445c3d8 100644 --- a/source/routing/raptor_api.cpp +++ b/source/routing/raptor_api.cpp @@ -397,8 +397,6 @@ static void compute_metadata(pbnavitia::Journey* pb_journey) { total_car_distance += section.length(); break; case pbnavitia::StreetNetworkMode::Bike: - total_bike_duration += section.duration(); - total_bike_distance += section.length(); case pbnavitia::StreetNetworkMode::Bss: total_bike_duration += section.duration(); total_bike_distance += section.length(); From e2afa60736bd7a0d49775619824041415021d615 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 16:25:05 +0100 Subject: [PATCH 14/20] fix after reviews --- .../scenarios/helper_classes/helper_utils.py | 85 ++++++------------- 1 file changed, 28 insertions(+), 57 deletions(-) diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py index 153b0ee1d9..5a00cd7d21 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py @@ -39,7 +39,7 @@ get_pt_object_coord, generate_id, ) -from jormungandr.street_network.utils import crowfly_distance_between +from jormungandr.street_network.utils import crowfly_distance_between, get_manhattan_duration from jormungandr.fallback_modes import FallbackModes, all_fallback_modes from jormungandr.scenarios.helper_classes.place_by_uri import PlaceByUri import math @@ -49,6 +49,8 @@ import logging import six from functools import cmp_to_key +from contextlib import contextmanager +import time CAR_PARK_DURATION = 300 # secs @@ -193,9 +195,9 @@ def _make_ending_car_park_sections( car_park_to_sp_section.duration = car_park_crowfly_duration -def _extend_with_bike_park(begin_date_time, duration): +def _make_bike_park(begin_date_time, duration): bike_park_section = response_pb2.Section() - bike_park_section.id = "Section_1" + bike_park_section.id = "section_bike_park" bike_park_section.duration = duration bike_park_section.type = response_pb2.PARK bike_park_section.begin_date_time = begin_date_time @@ -203,7 +205,7 @@ def _extend_with_bike_park(begin_date_time, duration): return bike_park_section -def _extend_with_bike_park_street_network(origin, begin_date_time, destination, end_date_time, duration): +def _make_bike_park_street_network(origin, begin_date_time, destination, end_date_time, duration): bike_park_to_sp_section = response_pb2.Section() bike_park_to_sp_section.id = "Street_network_section_2" bike_park_to_sp_section.origin.CopyFrom(origin) @@ -425,57 +427,20 @@ def _update_journey(journey, park_section, street_mode_section, to_replace, new_ journey.nb_sections += 2 -def haversine(cord1, cord2): - """ - Calculate the great-circle distance between two points on the Earth's surface using the Haversine formula. - - Parameters: - cord1 (object): An object with 'lat' and 'lon' attributes representing the latitude and longitude of the first point in degrees. - cord2 (object): An object with 'lat' and 'lon' attributes representing the latitude and longitude of the second point in degrees. - - Returns: - float: The distance between the two points in kilometers. - """ - lat1, lon1 = cord1.lat, cord1.lon - lat2, lon2 = cord2.lat, cord2.lon - # Radius of the Earth in kilometers - r = 6371.0 - - # Convert latitude and longitude from degrees to radians - lat1_rad, lon1_rad = math.radians(lat1), math.radians(lon1) - lat2_rad, lon2_rad = math.radians(lat2), math.radians(lon2) - - # Differences in coordinates - delta_lat = lat2_rad - lat1_rad - delta_lon = lon2_rad - lon1_rad - - # Haversine formula - a = math.sin(delta_lat / 2) ** 2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon / 2) ** 2 - c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) - - # Distance in kilometers - distance = r * c - return distance - - -def walking_time(cord1, cord2, speed_kmh=3): +def walking_time(cord1, cord2, walking_speed): """ Calculate the walking time between two coordinates. Args: cord1 (tuple): The (latitude, longitude) of the starting point. cord2 (tuple): The (latitude, longitude) of the destination point. - speed_kmh (float, optional): Walking speed in kilometers per hour. Defaults to 5 km/h. + walking_speed (float, optional): Walking speed in meter per seconds. Returns: float: The walking time in secondes. """ - distance = haversine(cord1, cord2) - # Time in hours - time_hours = distance / speed_kmh - # Convert to secondes - seconds = time_hours * 60 * 60 - return round(seconds) + distance = crowfly_distance_between(cord1, cord2) + return get_manhattan_duration(distance, walking_speed) def _get_place(kwargs, uri): @@ -536,15 +501,19 @@ def _update_fallback_with_bike_mode( _rename_fallback_sections_ids(fallback_sections) # We have to create the link between the fallback and the pt part manually here - if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK and kwargs["origin_mode"] == ["bike"]: + if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK and "bike" in kwargs["origin_mode"]: address = _get_place(kwargs, fallback_sections[-1].destination.uri) - walktime = walking_time(address.address.coord, journey.sections[0].destination.stop_point.coord) + walktime = walking_time( + address.address.coord, + journey.sections[0].destination.stop_point.coord, + kwargs["instance"].walking_speed, + ) fallback_sections[-1].destination.CopyFrom(address) for s in journey.sections: s.begin_date_time += kwargs["additional_time"] + walktime s.end_date_time += kwargs["additional_time"] + walktime - park_section = _extend_with_bike_park(fallback_sections[-1].end_date_time, kwargs["additional_time"]) - street_mode_section = _extend_with_bike_park_street_network( + park_section = _make_bike_park(fallback_sections[-1].end_date_time, kwargs["additional_time"]) + street_mode_section = _make_bike_park_street_network( fallback_sections[-1].destination, park_section.end_date_time, journey.sections[0].destination, @@ -555,18 +524,20 @@ def _update_fallback_with_bike_mode( [journey.sections[0].destination.stop_point.coord, fallback_sections[-1].destination.address.coord] ) _update_journey(journey, park_section, street_mode_section, journey.sections[0], fallback_sections) - if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK and kwargs["origin_mode"] != ["bike"]: + if fallback_type == StreetNetworkPathType.BEGINNING_FALLBACK and "bike" not in kwargs["origin_mode"]: section_to_replace = journey.sections[0] journey.sections.remove(section_to_replace) fallback_sections[-1].destination.CopyFrom(journey.sections[0].origin) journey.sections.extend(fallback_sections) - elif fallback_type == StreetNetworkPathType.ENDING_FALLBACK and kwargs["destination_mode"] == ["bike"]: + elif fallback_type == StreetNetworkPathType.ENDING_FALLBACK and "bike" in kwargs["destination_mode"]: walktime = walking_time( - journey.sections[-1].origin.stop_point.coord, fallback_sections[0].origin.address.coord + journey.sections[-1].origin.stop_point.coord, + fallback_sections[0].origin.address.coord, + kwargs["instance"].walking_speed, ) address = _get_place(kwargs, fallback_sections[0].origin.uri) fallback_sections[0].origin.CopyFrom(address) - street_mode_section = _extend_with_bike_park_street_network( + street_mode_section = _make_bike_park_street_network( journey.sections[-1].origin, fallback_sections[0].begin_date_time, fallback_sections[0].origin, @@ -574,13 +545,13 @@ def _update_fallback_with_bike_mode( - journey.sections[-1].begin_date_time, walktime, ) - park_section = _extend_with_bike_park(street_mode_section.begin_date_time, kwargs["additional_time"]) + park_section = _make_bike_park(street_mode_section.begin_date_time, kwargs["additional_time"]) fallback_sections[0].begin_date_time += kwargs["additional_time"] street_mode_section.street_network.coordinates.extend( [journey.sections[-1].origin.stop_point.coord, fallback_sections[0].origin.address.coord] ) _update_journey(journey, park_section, street_mode_section, journey.sections[-1], fallback_sections) - elif fallback_type == StreetNetworkPathType.ENDING_FALLBACK and kwargs["destination_mode"] != ["bike"]: + elif fallback_type == StreetNetworkPathType.ENDING_FALLBACK and "bike" not in kwargs["destination_mode"]: section_to_replace = journey.sections[-1] journey.sections.remove(section_to_replace) fallback_sections[0].origin.CopyFrom(journey.sections[-1].destination) @@ -850,8 +821,8 @@ def _build_fallback( fallback_dp_copy, fallback_type, requested_obj, via_poi_access, language ) - if request["park_mode"] == [ParkMode.on_street.name] and ( - request["origin_mode"] == ["bike"] or request["destination_mode"] == ["bike"] + if ParkMode.on_street.name in request["park_mode"] and ( + "bike" in request["origin_mode"] or "bike" in request["destination_mode"] ): _update_fallback_with_bike_mode( pt_journey, From 167aa7f80b934109691381f2eb4cfa09ad0d053e Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 16:25:57 +0100 Subject: [PATCH 15/20] remove unacessary code for park_mode --- source/jormungandr/jormungandr/park_modes.py | 23 -------------------- 1 file changed, 23 deletions(-) diff --git a/source/jormungandr/jormungandr/park_modes.py b/source/jormungandr/jormungandr/park_modes.py index 34bb57bcbf..4e57f7084f 100644 --- a/source/jormungandr/jormungandr/park_modes.py +++ b/source/jormungandr/jormungandr/park_modes.py @@ -44,28 +44,5 @@ def modes_str(cls): return {e.name for e in cls} - @classmethod - def modes_enum(cls): - return set(cls) - - @classmethod - def get_allowed_combinations_enums(cls): - def _combi(first_sections_modes, last_section_modes): - from itertools import product - - # cartesian product between two iterables - return set(product(first_sections_modes, last_section_modes)) - - return _combi(cls.modes_enum(), cls.modes_enum()) - - @classmethod - def get_allowed_combinations_str(cls): - # python 2/3 portability - import six - - allowed_combinations_enum = cls.get_allowed_combinations_enums() - # transform all enum to str - return set(six.moves.map(lambda modes: (modes[0].name, modes[1].name), allowed_combinations_enum)) - all_park_modes = ParkMode.modes_str() From 661753b38e67433f18f4597d7fb79c1e7daea17f Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 19:22:58 +0100 Subject: [PATCH 16/20] reverting some code review changes that causes bugs --- .../jormungandr/scenarios/helper_classes/helper_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py index 5a00cd7d21..c7960183de 100644 --- a/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py +++ b/source/jormungandr/jormungandr/scenarios/helper_classes/helper_utils.py @@ -821,8 +821,8 @@ def _build_fallback( fallback_dp_copy, fallback_type, requested_obj, via_poi_access, language ) - if ParkMode.on_street.name in request["park_mode"] and ( - "bike" in request["origin_mode"] or "bike" in request["destination_mode"] + if request["park_mode"] == [ParkMode.on_street.name] and ( + request["origin_mode"] == ["bike"] or request["destination_mode"] == ["bike"] ): _update_fallback_with_bike_mode( pt_journey, From cdda66c2809cfe20d255e844f4a4abc85a13e658 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Mon, 2 Dec 2024 19:23:44 +0100 Subject: [PATCH 17/20] adding integration tests --- .../tests/routing_tests_experimental.py | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/source/jormungandr/tests/routing_tests_experimental.py b/source/jormungandr/tests/routing_tests_experimental.py index 6e4e66c6c8..182cbceaa5 100644 --- a/source/jormungandr/tests/routing_tests_experimental.py +++ b/source/jormungandr/tests/routing_tests_experimental.py @@ -1489,3 +1489,77 @@ def test_same_journey_schedules_link(self): assert href_value is not None # Before correction: assert href_value.count('allowed_id') == 11 assert href_value.count('allowed_id') == 2 + + +@dataset({"main_routing_test": {"scenario": "distributed"}}) +class TestBikeWithParkingPenalty(NewDefaultScenarioAbstractTestFixture): + def test_bike_with_parking_penalty_first_section(self): + query = ( + sub_query + + "&datetime=20120614T075000" + + "&from=2.36893;48.88413" + + "&to=2.28928;48.84710" + + "&first_section_mode[]=bike" + + "&bike_speed=0.1" + + "&park_mode[]=on_street" + ) + + response = self.query_region(query) + check_best(response) + + journeys = get_not_null(response, 'journeys') + assert len(journeys) > 0 + for journey in journeys: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] == 'park' + assert journey['sections'][2]['type'] == 'street_network' + assert journey['sections'][2]['mode'] == 'walking' + assert len(journey['sections'][2]['geojson']['coordinates']) == 2 + + def test_bike_with_parking_penalty_last_section(self): + query = ( + sub_query + + "&datetime=20120614T075000" + + "&from=2.36893;48.88413" + + "&to=2.28928;48.84710" + + "&last_section_mode[]=bike" + + "&bike_speed=0.1" + + "&park_mode[]=on_street" + ) + + response = self.query_region(query) + check_best(response) + + journeys = get_not_null(response, 'journeys') + assert len(journeys) > 0 + for journey in journeys: + if len(journey['sections']) > 1: + assert journey['sections'][-1]['mode'] == 'bike' + assert journey['sections'][-2]['type'] == 'park' + assert journey['sections'][-3]['type'] == 'street_network' + + def test_bike_with_parking_penalty_first_section_and_access_points(self): + query = ( + sub_query + + "&datetime=20120614T075000" + + "&from=2.36893;48.88413" + + "&to=2.28928;48.84710" + + "&first_section_mode[]=bike" + + "&bike_speed=0.1" + + "&park_mode[]=on_street" + + "&_access_points=true" + ) + + response = self.query_region(query) + check_best(response) + + journeys = get_not_null(response, 'journeys') + assert len(journeys) > 0 + for journey in journeys: + if len(journey['sections']) > 1: + assert journey['sections'][0]['mode'] == 'bike' + assert journey['sections'][1]['type'] == 'park' + assert journey['sections'][2]['type'] == 'street_network' + assert journey['sections'][2]['mode'] == 'walking' + assert len(journey['sections'][2]['vias']) >= 1 From d1efb7fc36fe312c4228935858c37c8f564f66d2 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Tue, 3 Dec 2024 04:59:31 +0100 Subject: [PATCH 18/20] update park mode help reference --- .../jormungandr/interfaces/v1/journey_common.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py index fb5e9c9d90..910eb7554b 100644 --- a/source/jormungandr/jormungandr/interfaces/v1/journey_common.py +++ b/source/jormungandr/jormungandr/interfaces/v1/journey_common.py @@ -245,7 +245,13 @@ def __init__(self, output_type_serializer): type=OptionValue(park_modes.all_park_modes), dest="park_mode", action="append", - help='Force the park mode if the first section is by bike\n', + help='Force the park mode for the first or last section of a journey\n' + 'Need to be set with one of the first_section_mode[] or last_section_mode[] corresponding to vehicles that could be parked\n' + 'Note: Only work with the first or last section mode being a bike for the moment\n' + 'Eg: If you want to park a bike at the departure, you need:\n' + '`first_section_mode[]=bike&park_mode[]=on_street`' + 'Eg: If you want to park a bike at the arrival, you need:\n' + '`last_section_mode[]=bike&park_mode[]=on_street`', ) # for retrocompatibility purpose, we duplicate (without []): parser_get.add_argument( From d26bac7159cd012fcb34e37d734be14f6fda69b7 Mon Sep 17 00:00:00 2001 From: Pondonda Date: Tue, 3 Dec 2024 09:35:38 +0100 Subject: [PATCH 19/20] adding server_default --- .../c3ba234a3b9c_add_on_street_bike_parking_duration.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py b/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py index ee35c94686..e135e73aa3 100644 --- a/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py +++ b/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py @@ -15,7 +15,10 @@ def upgrade(): - op.add_column('instance', sa.Column('on_street_bike_parking_duration', sa.Integer(), nullable=False)) + op.add_column( + 'instance', + sa.Column('on_street_bike_parking_duration', sa.Integer(), nullable=False, server_default='500'), + ) def downgrade(): From 49a0db8185dab23210c15a62c4641112f281df5b Mon Sep 17 00:00:00 2001 From: Pondonda Date: Tue, 3 Dec 2024 10:17:11 +0100 Subject: [PATCH 20/20] update server default value --- .../c3ba234a3b9c_add_on_street_bike_parking_duration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py b/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py index e135e73aa3..2f7ec2c334 100644 --- a/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py +++ b/source/tyr/migrations/versions/c3ba234a3b9c_add_on_street_bike_parking_duration.py @@ -17,7 +17,7 @@ def upgrade(): op.add_column( 'instance', - sa.Column('on_street_bike_parking_duration', sa.Integer(), nullable=False, server_default='500'), + sa.Column('on_street_bike_parking_duration', sa.Integer(), nullable=False, server_default='300'), )