Example #1
0
def blablalines_init_class_test():
    instance = MockInstance()
    ridesharing_manager = RidesharingServiceManager(instance, [])
    service = ridesharing_manager._init_class(config_blablalines["class"],
                                              config_blablalines["args"])
    assert isinstance(service, Blablalines)
    assert service.system_id == "blablalines"
Example #2
0
def instant_system_init_class_test():
    instance = MockInstance()
    ridesharing_manager = RidesharingServiceManager(instance, [])
    service = ridesharing_manager._init_class(config_instant_system["class"],
                                              config_instant_system["args"])
    assert isinstance(service, InstantSystem)
    assert service.system_id == 'instant_system'
Example #3
0
def get_ridesharing_service_test():
    configs = [
        {
            "class":
            "jormungandr.scenarios.ridesharing.instant_system.InstantSystem",
            "args": {
                "service_url": "toto",
                "api_key": "toto key",
                "network": "N",
                "rating_scale_min": 0,
                "rating_scale_max": 10,
                "crowfly_radius": 200,
                "timeframe_duration": 1800,
                "feed_publisher": DUMMY_INSTANT_SYSTEM_FEED_PUBLISHER,
            },
        },
        {
            "class":
            "jormungandr.scenarios.ridesharing.instant_system.InstantSystem",
            "args": {
                "service_url": "tata",
                "api_key": "tata key",
                "network": "M",
                "rating_scale_min": 1,
                "rating_scale_max": 5,
                "crowfly_radius": 200,
                "timeframe_duration": 1800,
            },
        },
    ]
    instance = DummyInstance()
    ridesharing_service_manager = RidesharingServiceManager(instance, configs)
    ridesharing_service_manager.init_ridesharing_services()
    services = ridesharing_service_manager.get_all_ridesharing_services()
    assert len(services) == 2

    assert services[0].service_url == 'toto'
    assert services[0].api_key == 'toto key'
    assert services[0].network == 'N'
    assert services[0].system_id == 'instant_system'
    assert services[0].rating_scale_min == 0
    assert services[0].rating_scale_max == 10
    assert services[0]._get_feed_publisher() == RsFeedPublisher(
        **DUMMY_INSTANT_SYSTEM_FEED_PUBLISHER)

    assert services[1].service_url == 'tata'
    assert services[1].api_key == 'tata key'
    assert services[1].network == 'M'
    assert services[1].system_id == 'instant_system'
    assert services[1].rating_scale_min == 1
    assert services[1].rating_scale_max == 5
    assert services[1]._get_feed_publisher() == RsFeedPublisher(
        **DEFAULT_INSTANT_SYSTEM_FEED_PUBLISHER)
Example #4
0
def get_ridesharing_service_test():
    configs = [
        {
            "class": "jormungandr.scenarios.ridesharing.karos.Karos",
            "args": {
                "service_url": "toto",
                "api_key": "toto key",
                "network": "N",
                "timeout": 10,
                "timedelta": 7000,
                "departure_radius": 15,
                "arrival_radius": 15,
                "feed_publisher": DUMMY_KAROS_FEED_PUBLISHER,
            },
        },
        {
            "class": "jormungandr.scenarios.ridesharing.karos.Karos",
            "args": {
                "service_url": "tata",
                "api_key": "tata key",
                "network": "M"
            },
        },
    ]
    instance = DummyInstance()
    ridesharing_service_manager = RidesharingServiceManager(instance, configs)
    ridesharing_service_manager.init_ridesharing_services()
    services = ridesharing_service_manager.get_all_ridesharing_services()
    assert len(services) == 2

    assert services[0].service_url == 'toto'
    assert services[0].api_key == 'toto key'
    assert services[0].network == 'N'
    assert services[0].system_id == 'karos'
    assert services[0].timeout == 10
    assert services[0].timedelta == 7000
    assert services[0].departure_radius == 15
    assert services[0].arrival_radius == 15
    assert services[0]._get_feed_publisher() == RsFeedPublisher(
        **DUMMY_KAROS_FEED_PUBLISHER)

    assert services[1].service_url == 'tata'
    assert services[1].api_key == 'tata key'
    assert services[1].network == 'M'
    assert services[1].system_id == 'karos'
    # Default values
    assert services[1].timeout == 2
    assert services[1].timedelta == 3600
    assert services[1].departure_radius == 2
    assert services[1].arrival_radius == 2

    assert services[1]._get_feed_publisher() == RsFeedPublisher(
        **DEFAULT_KAROS_FEED_PUBLISHER)
Example #5
0
def two_ridesharing_service_manager_config_from_file_test():
    """
    creation of a ride sharing services from the configuration file: Blablalines and InstantSystym
    Result: We have to find both services Blablalines and InstantSystem
    """
    instance = MockInstance()
    ridesharing_services_config = [config_blablalines, config_instant_system]
    ridesharing_manager = RidesharingServiceManager(
        instance, ridesharing_services_config)
    ridesharing_manager.init_ridesharing_services()
    assert len(ridesharing_manager.ridesharing_services_configuration) == 2
    assert not ridesharing_manager._ridesharing_services
    assert not ridesharing_manager._rs_services_getter
    assert ridesharing_manager._update_interval == 60
    assert len(ridesharing_manager._ridesharing_services_legacy) == 2
Example #6
0
def blablalines_ridesharing_service_manager_config_from_file_test():
    """
    creation of a ridesharing service from the configuration file: Blablalines
    Result: We must find the service Blablalines
    """
    instance = MockInstance()
    ridesharing_services_config = [config_blablalines]
    ridesharing_manager = RidesharingServiceManager(
        instance, ridesharing_services_config)
    ridesharing_manager.init_ridesharing_services()
    assert len(ridesharing_manager.ridesharing_services_configuration) == 1
    assert not ridesharing_manager._ridesharing_services
    assert not ridesharing_manager._rs_services_getter
    assert ridesharing_manager._update_interval == 60
    assert len(ridesharing_manager._ridesharing_services_legacy) == 1
Example #7
0
def ridesharing_service_manager_config_from_file_and_db_test():
    """
    creation of a ridesharing service from database: InstantSystem
    creation of a ridesharing service from database : Blablalines
    Result: We have to find both services Blablalines and InstantSystem
    """
    instance = MockInstance()
    ridesharing_manager = RidesharingServiceManager(
        instance, [],
        rs_services_getter=mock_get_attr_instant_system_and_blablalines)
    ridesharing_manager.init_ridesharing_services()
    ridesharing_manager.update_config()

    assert len(ridesharing_manager.ridesharing_services_configuration) == 0
    assert len(list(ridesharing_manager._ridesharing_services.values())) == 2
    assert ridesharing_manager._ridesharing_services[
        "InstantSystem"].system_id == "instant_system"
    assert ridesharing_manager._ridesharing_services[
        "Blablalines"].system_id == "blablalines"
    assert ridesharing_manager._rs_services_getter
    assert ridesharing_manager._update_interval == 60
    assert ridesharing_manager._update_interval == 60
    assert len(ridesharing_manager._ridesharing_services_legacy) == 0
    services = ridesharing_manager.get_all_ridesharing_services()
    assert len(services) == 2
Example #8
0
def two_same_ridesharing_service_manager_config_from_file_and_db_test():
    """
    creation of a ridesharing service from the configuration file: InstantSystem
    creation of a ridesharing service from database : InstantSystem
    Result: We must find the service InstantSystem
    """
    instance = MockInstance()
    ridesharing_services_config = [config_instant_system]
    ridesharing_manager = RidesharingServiceManager(
        instance,
        ridesharing_services_config,
        rs_services_getter=mock_get_attr_instant_system)
    ridesharing_manager.init_ridesharing_services()
    ridesharing_manager.update_config()

    assert len(ridesharing_manager.ridesharing_services_configuration) == 1
    assert len(list(ridesharing_manager._ridesharing_services.values())) == 1
    assert ridesharing_manager._ridesharing_services[
        "InstantSystem"].system_id == "instant_system"
    assert ridesharing_manager._rs_services_getter
    assert ridesharing_manager._update_interval == 60
    assert ridesharing_manager._update_interval == 60
    assert len(ridesharing_manager._ridesharing_services_legacy) == 0
    services = ridesharing_manager.get_all_ridesharing_services()
    assert len(services) == 1
Example #9
0
def get_ridesharing_service_test():
    configs = [
        {
            "class":
            "jormungandr.scenarios.ridesharing.blablalines.Blablalines",
            "args": {
                "service_url": "toto",
                "api_key": "toto key",
                "network": "N",
                "feed_publisher": DUMMY_BLABLALINES_FEED_PUBLISHER,
            },
        },
        {
            "class":
            "jormungandr.scenarios.ridesharing.blablalines.Blablalines",
            "args": {
                "service_url": "tata",
                "api_key": "tata key",
                "network": "M"
            },
        },
    ]
    instance = DummyInstance()
    ridesharing_service_manager = RidesharingServiceManager(instance, configs)
    ridesharing_service_manager.init_ridesharing_services()
    services = ridesharing_service_manager.get_all_ridesharing_services()

    assert len(services) == 2

    assert services[0].service_url == 'toto'
    assert services[0].api_key == 'toto key'
    assert services[0].network == 'N'
    assert services[0].system_id == 'blablalines'
    assert services[0]._get_feed_publisher() == RsFeedPublisher(
        **DUMMY_BLABLALINES_FEED_PUBLISHER)

    assert services[1].service_url == 'tata'
    assert services[1].api_key == 'tata key'
    assert services[1].network == 'M'
    assert services[1].system_id == 'blablalines'
    assert services[1]._get_feed_publisher() == RsFeedPublisher(
        **DEFAULT_BLABLALINES_FEED_PUBLISHER)
Example #10
0
    def __init__(
            self,
            context,  # type: zmq.Context
            name,  # type: Text
            zmq_socket,  # type: Text
            street_network_configurations,
            ridesharing_configurations,
            realtime_proxies_configuration,
            zmq_socket_type,
            autocomplete_type,
            instance_equipment_providers,  # type: List[Text]
            streetnetwork_backend_manager,
            external_service_provider_configurations,
            pt_zmq_socket=None,  # type: Text
    ):
        self.geom = None
        self.geojson = None
        self._sockets = deque()
        self._pt_sockets = deque()
        self.socket_path = zmq_socket
        self._scenario = None
        self._scenario_name = None
        self.lock = Lock()
        self.context = context
        self.name = name
        self.timezone = None  # timezone will be fetched from the kraken
        self.publication_date = -1
        self.is_initialized = False  # kraken hasn't been called yet we don't have geom nor timezone
        self.breaker = pybreaker.CircuitBreaker(
            fail_max=app.config.get(str('CIRCUIT_BREAKER_MAX_INSTANCE_FAIL'),
                                    5),
            reset_timeout=app.config.get(
                str('CIRCUIT_BREAKER_INSTANCE_TIMEOUT_S'), 60),
        )
        self.georef = georef.Kraken(self)
        self.planner = planner.Kraken(self)
        self._streetnetwork_backend_manager = streetnetwork_backend_manager
        if pt_zmq_socket:
            self.pt_socket_path = pt_zmq_socket
        else:
            self.pt_socket_path = zmq_socket

        disable_database = app.config[str('DISABLE_DATABASE')]
        if disable_database:
            self._streetnetwork_backend_manager.init_streetnetwork_backends_legacy(
                self, street_network_configurations)
            self.ridesharing_services_manager = RidesharingServiceManager(
                self, ridesharing_configurations)
        else:
            self.ridesharing_services_manager = RidesharingServiceManager(
                self, ridesharing_configurations,
                self.get_ridesharing_services_from_db)

        # Init Ridesharing services from config file
        self.ridesharing_services_manager.init_ridesharing_services()

        self.ptref = ptref.PtRef(self)

        self.schedule = schedule.MixedSchedule(self)
        self.realtime_proxy_manager = realtime_schedule.RealtimeProxyManager(
            realtime_proxies_configuration, self)

        self._autocomplete_type = autocomplete_type
        if self._autocomplete_type is not None and self._autocomplete_type not in global_autocomplete:
            raise RuntimeError('impossible to find autocomplete system {} '
                               'cannot initialize instance {}'.format(
                                   autocomplete_type, name))

        self.zmq_socket_type = zmq_socket_type

        if disable_database:
            self.equipment_provider_manager = EquipmentProviderManager(
                app.config[str('EQUIPMENT_DETAILS_PROVIDERS')])
        else:
            self.equipment_provider_manager = EquipmentProviderManager(
                app.config[str('EQUIPMENT_DETAILS_PROVIDERS')],
                self.get_providers_from_db)

        # Init equipment providers from config
        self.equipment_provider_manager.init_providers(
            instance_equipment_providers)

        # Init free-floating providers from config
        if disable_database:
            self.external_service_provider_manager = ExternalServiceManager(
                self, external_service_provider_configurations)
        else:
            self.external_service_provider_manager = ExternalServiceManager(
                self, external_service_provider_configurations,
                self.get_external_service_providers_from_db)
        self.external_service_provider_manager.init_external_services()
Example #11
0
class Instance(object):
    name = None  # type: Text
    _sockets = None  # type: Deque[Tuple[zmq.Socket, float]]
    _pt_sockets = None  # type: Deque[Tuple[zmq.Socket, float]]

    def __init__(
            self,
            context,  # type: zmq.Context
            name,  # type: Text
            zmq_socket,  # type: Text
            street_network_configurations,
            ridesharing_configurations,
            realtime_proxies_configuration,
            zmq_socket_type,
            autocomplete_type,
            instance_equipment_providers,  # type: List[Text]
            streetnetwork_backend_manager,
            external_service_provider_configurations,
            pt_zmq_socket=None,  # type: Text
    ):
        self.geom = None
        self.geojson = None
        self._sockets = deque()
        self._pt_sockets = deque()
        self.socket_path = zmq_socket
        self._scenario = None
        self._scenario_name = None
        self.lock = Lock()
        self.context = context
        self.name = name
        self.timezone = None  # timezone will be fetched from the kraken
        self.publication_date = -1
        self.is_initialized = False  # kraken hasn't been called yet we don't have geom nor timezone
        self.breaker = pybreaker.CircuitBreaker(
            fail_max=app.config.get(str('CIRCUIT_BREAKER_MAX_INSTANCE_FAIL'),
                                    5),
            reset_timeout=app.config.get(
                str('CIRCUIT_BREAKER_INSTANCE_TIMEOUT_S'), 60),
        )
        self.georef = georef.Kraken(self)
        self.planner = planner.Kraken(self)
        self._streetnetwork_backend_manager = streetnetwork_backend_manager
        if pt_zmq_socket:
            self.pt_socket_path = pt_zmq_socket
        else:
            self.pt_socket_path = zmq_socket

        disable_database = app.config[str('DISABLE_DATABASE')]
        if disable_database:
            self._streetnetwork_backend_manager.init_streetnetwork_backends_legacy(
                self, street_network_configurations)
            self.ridesharing_services_manager = RidesharingServiceManager(
                self, ridesharing_configurations)
        else:
            self.ridesharing_services_manager = RidesharingServiceManager(
                self, ridesharing_configurations,
                self.get_ridesharing_services_from_db)

        # Init Ridesharing services from config file
        self.ridesharing_services_manager.init_ridesharing_services()

        self.ptref = ptref.PtRef(self)

        self.schedule = schedule.MixedSchedule(self)
        self.realtime_proxy_manager = realtime_schedule.RealtimeProxyManager(
            realtime_proxies_configuration, self)

        self._autocomplete_type = autocomplete_type
        if self._autocomplete_type is not None and self._autocomplete_type not in global_autocomplete:
            raise RuntimeError('impossible to find autocomplete system {} '
                               'cannot initialize instance {}'.format(
                                   autocomplete_type, name))

        self.zmq_socket_type = zmq_socket_type

        if disable_database:
            self.equipment_provider_manager = EquipmentProviderManager(
                app.config[str('EQUIPMENT_DETAILS_PROVIDERS')])
        else:
            self.equipment_provider_manager = EquipmentProviderManager(
                app.config[str('EQUIPMENT_DETAILS_PROVIDERS')],
                self.get_providers_from_db)

        # Init equipment providers from config
        self.equipment_provider_manager.init_providers(
            instance_equipment_providers)

        # Init free-floating providers from config
        if disable_database:
            self.external_service_provider_manager = ExternalServiceManager(
                self, external_service_provider_configurations)
        else:
            self.external_service_provider_manager = ExternalServiceManager(
                self, external_service_provider_configurations,
                self.get_external_service_providers_from_db)
        self.external_service_provider_manager.init_external_services()

    def get_providers_from_db(self):
        """
        :return: a callable query of equipment providers associated to the current instance in db
        """
        return self._get_models().equipment_details_providers

    def get_ridesharing_services_from_db(self):
        """
        :return: a callable query of ridesharing services associated to the current instance in db
        """
        return self._get_models().ridesharing_services

    def get_external_service_providers_from_db(self):
        """
        :return: a callable query of external services associated to the current instance in db
        """
        return self._get_models().external_services

    @property
    def autocomplete(self):
        if self._autocomplete_type:
            # retrocompat: we need to continue to read configuration from file
            # while we migrate to database configuration
            return global_autocomplete.get(self._autocomplete_type)
        backend = global_autocomplete.get(self.autocomplete_backend)
        if backend is None:
            raise RuntimeError(
                'impossible to find autocomplete {} for instance {}'.format(
                    self.autocomplete_backend, self.name))
        return backend

    def stop_point_fallbacks(self):
        return [
            a for a in global_autocomplete.values()
            if a.is_handling_stop_points()
        ]

    def get_models(self):
        if self.name not in g.instances_model:
            g.instances_model[self.name] = self._get_models()
        return g.instances_model[self.name]

    def __repr__(self):
        return 'instance.{}'.format(self.name)

    @memory_cache.memoize(app.config[str('MEMORY_CACHE_CONFIGURATION')].get(
        str('TIMEOUT_PARAMS'), 30))
    @cache.memoize(app.config[str('CACHE_CONFIGURATION')].get(
        str('TIMEOUT_PARAMS'), 300))
    def _get_models(self):
        if app.config['DISABLE_DATABASE']:
            return None
        return models.Instance.get_by_name(self.name)

    def scenario(self, override_scenario=None):
        """
        once a scenario has been chosen for a request for an instance (coverage), we cannot change it
        """
        if hasattr(g, 'scenario') and g.scenario.get(self.name):
            return g.scenario[self.name]

        def replace_experimental_scenario(s):
            return 'distributed' if s == 'experimental' else s

        if override_scenario:
            logger = logging.getLogger(__name__)
            logger.debug('overriding the scenario for %s with %s', self.name,
                         override_scenario)
            try:
                # for the sake of backwards compatibility... some users may still be using experimental...
                override_scenario = replace_experimental_scenario(
                    override_scenario)
                module = import_module(
                    'jormungandr.scenarios.{}'.format(override_scenario))
            except ImportError:
                logger.exception('scenario not found')
                abort(404,
                      message='invalid scenario: {}'.format(override_scenario))
            scenario = module.Scenario()
            # Save scenario_name and scenario
            self._scenario_name = override_scenario
            self._scenario = scenario
            if not hasattr(g, 'scenario'):
                g.scenario = {}
            g.scenario[self.name] = scenario
            return scenario

        instance_db = self.get_models()
        scenario_name = instance_db.scenario if instance_db else 'new_default'
        # for the sake of backwards compatibility... some users may still be using experimental...
        scenario_name = replace_experimental_scenario(scenario_name)
        if not self._scenario or scenario_name != self._scenario_name:
            logger = logging.getLogger(__name__)
            logger.info('loading of scenario %s for instance %s',
                        scenario_name, self.name)
            self._scenario_name = scenario_name
            module = import_module(
                'jormungandr.scenarios.{}'.format(scenario_name))
            self._scenario = module.Scenario()

        # we save the used scenario for future use
        if not hasattr(g, 'scenario'):
            g.scenario = {}
        g.scenario[self.name] = self._scenario
        return self._scenario

    @property
    def max_waiting_duration(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_waiting_duration', instance_db,
                                    self.name)

    @property
    def journey_order(self):
        # type: () -> Text
        instance_db = self.get_models()
        return get_value_or_default('journey_order', instance_db, self.name)

    @property
    def autocomplete_backend(self):
        # type: () -> Text
        instance_db = self.get_models()
        return get_value_or_default('autocomplete_backend', instance_db,
                                    self.name)

    @property
    def max_walking_duration_to_pt(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_walking_duration_to_pt', instance_db,
                                    self.name)

    @property
    def max_bss_duration_to_pt(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_bss_duration_to_pt', instance_db,
                                    self.name)

    @property
    def max_bike_duration_to_pt(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_bike_duration_to_pt', instance_db,
                                    self.name)

    @property
    def max_car_duration_to_pt(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_car_duration_to_pt', instance_db,
                                    self.name)

    @property
    def max_car_no_park_duration_to_pt(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_car_no_park_duration_to_pt',
                                    instance_db, self.name)

    @property
    def max_ridesharing_duration_to_pt(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_ridesharing_duration_to_pt',
                                    instance_db, self.name)

    @property
    def max_taxi_duration_to_pt(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_taxi_duration_to_pt', instance_db,
                                    self.name)

    @property
    def walking_speed(self):
        # type: () -> float
        instance_db = self.get_models()
        return get_value_or_default('walking_speed', instance_db, self.name)

    @property
    def bss_speed(self):
        # type: () -> float
        instance_db = self.get_models()
        return get_value_or_default('bss_speed', instance_db, self.name)

    @property
    def bike_speed(self):
        # type: () -> float
        instance_db = self.get_models()
        return get_value_or_default('bike_speed', instance_db, self.name)

    @property
    def car_speed(self):
        # type: () -> float
        instance_db = self.get_models()
        return get_value_or_default('car_speed', instance_db, self.name)

    @property
    def car_no_park_speed(self):
        # type: () -> float
        instance_db = self.get_models()
        return get_value_or_default('car_no_park_speed', instance_db,
                                    self.name)

    @property
    def ridesharing_speed(self):
        # type: () -> float
        instance_db = self.get_models()
        return get_value_or_default('ridesharing_speed', instance_db,
                                    self.name)

    @property
    def max_nb_transfers(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_nb_transfers', instance_db, self.name)

    @property
    def min_bike(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('min_bike', instance_db, self.name)

    @property
    def min_bss(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('min_bss', instance_db, self.name)

    @property
    def min_car(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('min_car', instance_db, self.name)

    @property
    def min_taxi(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('min_taxi', instance_db, self.name)

    @property
    def successive_physical_mode_to_limit_id(self):
        # type: () -> Text
        instance_db = self.get_models()
        return get_value_or_default('successive_physical_mode_to_limit_id',
                                    instance_db, self.name)

    @property
    def priority(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('priority', instance_db, self.name)

    @property
    def bss_provider(self):
        # type: () -> bool
        instance_db = self.get_models()
        return get_value_or_default('bss_provider', instance_db, self.name)

    @property
    def car_park_provider(self):
        # type: () -> bool
        instance_db = self.get_models()
        return get_value_or_default('car_park_provider', instance_db,
                                    self.name)

    @property
    def max_additional_connections(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_additional_connections', instance_db,
                                    self.name)

    @property
    def is_free(self):
        # type: () -> bool
        instance_db = self.get_models()
        if not instance_db:
            return False
        else:
            return instance_db.is_free

    @property
    def is_open_data(self):
        # type: () -> bool
        instance_db = self.get_models()
        if not instance_db:
            return False
        else:
            return instance_db.is_open_data

    @property
    def max_duration(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_duration', instance_db, self.name)

    @property
    def walking_transfer_penalty(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('walking_transfer_penalty', instance_db,
                                    self.name)

    @property
    def night_bus_filter_max_factor(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('night_bus_filter_max_factor', instance_db,
                                    self.name)

    @property
    def night_bus_filter_base_factor(self):
        # type: () -> float
        instance_db = self.get_models()
        return get_value_or_default('night_bus_filter_base_factor',
                                    instance_db, self.name)

    @property
    def realtime_pool_size(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('realtime_pool_size', instance_db,
                                    self.name)

    @property
    def min_nb_journeys(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('min_nb_journeys', instance_db, self.name)

    @property
    def max_nb_journeys(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_nb_journeys', instance_db, self.name)

    @property
    def min_journeys_calls(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('min_journeys_calls', instance_db,
                                    self.name)

    @property
    def max_successive_physical_mode(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_successive_physical_mode',
                                    instance_db, self.name)

    @property
    def final_line_filter(self):
        instance_db = self.get_models()
        return get_value_or_default('final_line_filter', instance_db,
                                    self.name)

    @property
    def max_extra_second_pass(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_extra_second_pass', instance_db,
                                    self.name)

    @property
    def asynchronous_ridesharing(self):
        # type: () -> bool
        instance_db = self.get_models()
        return get_value_or_default('asynchronous_ridesharing', instance_db,
                                    self.name)

    @property
    def ridesharing_greenlet_pool_size(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('ridesharing_greenlet_pool_size',
                                    instance_db, self.name)

    @property
    def greenlet_pool_for_ridesharing_services(self):
        # type: () -> bool
        instance_db = self.get_models()
        return get_value_or_default('greenlet_pool_for_ridesharing_services',
                                    instance_db, self.name)

    @property
    def max_nb_crowfly_by_mode(self):
        # type: () -> Dict[Text, int]
        instance_db = self.get_models()
        # the value by default is a dict...
        d = copy.deepcopy(
            get_value_or_default('max_nb_crowfly_by_mode', instance_db,
                                 self.name))
        # In case we add a new max_nb_crowfly for an other mode than
        # the ones already present in the database.
        for mode, duration in default_values.max_nb_crowfly_by_mode.items():
            if mode not in d:
                d[mode] = duration

        return d

    @property
    def poi_dataset(self):
        # type: () -> Text
        instance_db = self.get_models()
        return instance_db.poi_dataset if instance_db else None

    @property
    def max_car_no_park_direct_path_duration(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('max_car_no_park_direct_path_duration',
                                    instance_db, self.name)

    @property
    def min_ridesharing(self):
        # type: () -> int
        instance_db = self.get_models()
        return get_value_or_default('min_ridesharing', instance_db, self.name)

    # TODO: refactorise all properties
    taxi_speed = _make_property_getter('taxi_speed')
    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')

    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')
    max_car_direct_path_duration = _make_property_getter(
        'max_car_direct_path_duration')
    max_taxi_direct_path_duration = _make_property_getter(
        'max_taxi_direct_path_duration')
    max_ridesharing_direct_path_duration = _make_property_getter(
        'max_ridesharing_direct_path_duration')

    street_network_car = _make_property_getter('street_network_car')
    street_network_car_no_park = _make_property_getter(
        'street_network_car_no_park')
    street_network_walking = _make_property_getter('street_network_walking')
    street_network_bike = _make_property_getter('street_network_bike')
    street_network_bss = _make_property_getter('street_network_bss')
    street_network_ridesharing = _make_property_getter(
        'street_network_ridesharing')
    street_network_taxi = _make_property_getter('street_network_taxi')

    stop_points_nearby_duration = _make_property_getter(
        'stop_points_nearby_duration')

    def reap_socket(self, ttl):
        # type: (int) -> None
        if self.zmq_socket_type != 'transient':
            return
        logger = logging.getLogger(__name__)
        now = time.time()

        def _reap_sockets(sockets):
            while True:
                try:
                    socket, t = sockets.popleft()
                    if now - t > ttl:
                        logger.debug("closing one socket for %s", self.name)
                        socket.setsockopt(zmq.LINGER, 0)
                        socket.close()
                    else:
                        self._sockets.appendleft((socket, t))
                        break  # remaining socket are still in "keep alive" state
                except IndexError:
                    break

        _reap_sockets(self._sockets)
        _reap_sockets(self._pt_sockets)

    @contextmanager
    def socket(self, context, pt_socket=False):

        socket = None
        if pt_socket:
            sockets = self._pt_sockets
            socket_path = self.pt_socket_path
        else:
            sockets = self._sockets
            socket_path = self.socket_path

        try:
            socket, _ = sockets.pop()
        except IndexError:  # there is no socket available: lets create one
            socket = context.socket(zmq.REQ)
            socket.connect(socket_path)
        try:
            yield socket
        finally:
            if not socket.closed:
                sockets.append((socket, time.time()))

    def send_and_receive(self, *args, **kwargs):
        """
        encapsulate all call to kraken in a circuit breaker, this way we don't loose time calling dead instance
        """
        try:
            return self.breaker.call(self._send_and_receive, *args, **kwargs)
        except pybreaker.CircuitBreakerError as e:
            raise DeadSocketException(self.name, self.socket_path)

    def _send_and_receive(self,
                          request,
                          timeout=app.config.get('INSTANCE_TIMEOUT', 10000),
                          quiet=False,
                          **kwargs):
        logger = logging.getLogger(__name__)
        deadline = datetime.utcnow() + timedelta(milliseconds=timeout)
        request.deadline = deadline.strftime('%Y%m%dT%H%M%S,%f')
        pt_socket = request.requested_api == type_pb2.pt_planner
        with self.socket(self.context, pt_socket) as socket:
            if 'request_id' in kwargs and kwargs['request_id']:
                request.request_id = kwargs['request_id']
            else:
                try:
                    request.request_id = flask.request.id
                except RuntimeError:
                    # we aren't in a flask context, so there is no request
                    if 'flask_request_id' in kwargs and kwargs[
                            'flask_request_id']:
                        request.request_id = kwargs['flask_request_id']

            socket.send(request.SerializeToString())
            if socket.poll(timeout=timeout) > 0:
                pb = socket.recv()
                resp = response_pb2.Response()
                resp.ParseFromString(pb)
                self.update_property(
                    resp
                )  # we update the timezone and geom of the instances at each request
                return resp
            else:
                socket.setsockopt(zmq.LINGER, 0)
                socket.close()
                if not quiet:
                    logger.error('request on %s failed: %s', self.socket_path,
                                 six.text_type(request))
                raise DeadSocketException(self.name, self.socket_path)

    def get_id(self, id_):
        """
        Get the pt_object that have the given id
        """
        req = request_pb2.Request()
        req.requested_api = type_pb2.place_uri
        req.place_uri.uri = id_
        return self.send_and_receive(req,
                                     timeout=app.config.get(
                                         'INSTANCE_FAST_TIMEOUT', 1000))

    def has_id(self, id_):
        """
        Does this instance has this id
        """
        try:
            return len(self.get_id(id_).places) > 0
        except DeadSocketException:
            return False

    def has_coord(self, lon, lat):
        return self.has_point(geometry.Point(lon, lat))

    def has_point(self, p):
        try:
            return self.geom and self.geom.contains(p)
        except DeadSocketException:
            return False
        except PredicateError:
            logging.getLogger(__name__).exception("has_coord failed")
            return False
        except TopologicalError:
            logging.getLogger(__name__).exception("check_topology failed")
            return False

    def get_external_codes(self, type_, id_):
        """
        Get all pt_object with the given id
        """
        req = request_pb2.Request()
        req.requested_api = type_pb2.place_code
        if type_ not in type_to_pttype:
            raise ValueError(
                "Can't call pt_code API with type: {}".format(type_))
        req.place_code.type = type_to_pttype[type_]
        req.place_code.type_code = "external_code"
        req.place_code.code = id_
        # we set the timeout to 1s
        return self.send_and_receive(req,
                                     timeout=app.config.get(
                                         'INSTANCE_FAST_TIMEOUT', 1000))

    def has_external_code(self, type_, id_):
        """
        Does this instance has the given id
        Returns None if it doesnt, the kraken uri otherwise
        """
        try:
            res = self.get_external_codes(type_, id_)
        except DeadSocketException:
            return False
        if len(res.places) > 0:
            return res.places[0].uri
        return None

    def update_property(self, response):
        """
        update the property of an instance from a response if the metadatas field if present
        """
        # after a successful call we consider the instance initialised even if no data were loaded
        self.is_initialized = True
        if response.HasField(
                str("metadatas"
                    )) and response.publication_date != self.publication_date:
            logging.getLogger(__name__).debug('updating metadata for %s',
                                              self.name)
            with self.lock as lock:
                self.publication_date = response.publication_date
                if response.metadatas.shape and response.metadatas.shape != "":
                    try:
                        self.geom = wkt.loads(response.metadatas.shape)
                    except ReadingError:
                        self.geom = None
                else:
                    self.geom = None
                self.timezone = response.metadatas.timezone
                self._update_geojson()
        set_request_instance_timezone(self)

    def _update_geojson(self):
        """construct the geojson object from the shape"""
        if not self.geom or not self.geom.is_valid:
            self.geojson = None
            return
        # simplify the geom to prevent slow query on bragi
        geom = self.geom.simplify(tolerance=0.01)
        self.geojson = geometry.mapping(geom)

    def init(self):
        """
        Get and store variables of the instance.
        Returns True if we need to clear the cache, False otherwise.
        """
        pub_date = self.publication_date
        req = request_pb2.Request()
        req.requested_api = type_pb2.METADATAS
        request_id = "instance_init"
        try:
            # we use _send_and_receive to avoid the circuit breaker, we don't want fast fail on init :)
            resp = self._send_and_receive(req,
                                          request_id=request_id,
                                          timeout=1000,
                                          quiet=True)
            # the instance is automatically updated on a call
            if self.publication_date != pub_date:
                return True
        except DeadSocketException:
            # we don't do anything on error, a new session will be established to an available kraken on
            # the next request. We don't want to purge all our cache for a small error.
            logging.getLogger(__name__).debug('timeout on init for %s',
                                              self.name)
        return False

    def _get_street_network(self, mode, request):
        if app.config[str('DISABLE_DATABASE')]:
            return self._streetnetwork_backend_manager.get_street_network_legacy(
                self, mode, request)
        else:
            # We get the name of the column in the database corresponding to the mode used in the request
            # And we get the value of this column for this instance
            column_in_db = "street_network_{}".format(mode)
            streetnetwork_backend_conf = getattr(self, column_in_db)
            return self._streetnetwork_backend_manager.get_street_network_db(
                self, streetnetwork_backend_conf)

    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(instance=self,
                                          walking_service=walking_service,
                                          car_service=car_service)

    def get_all_street_networks(self):
        if app.config[str('DISABLE_DATABASE')]:
            return self._streetnetwork_backend_manager.get_all_street_networks_legacy(
                self)
        else:
            return self._streetnetwork_backend_manager.get_all_street_networks_db(
                self)

    def get_all_ridesharing_services(self):
        return self.ridesharing_services_manager.get_all_ridesharing_services()

    def get_autocomplete(self, requested_autocomplete):
        if not requested_autocomplete:
            return self.autocomplete
        autocomplete = global_autocomplete.get(requested_autocomplete)
        if not autocomplete:
            raise TechnicalError(
                'autocomplete {} not available'.format(requested_autocomplete))
        return autocomplete