Skip to content

Commit

Permalink
Merge pull request #4287 from hove-io/add_impact_on_pois
Browse files Browse the repository at this point in the history
Add disruptions on POI
  • Loading branch information
kadhikari authored Aug 2, 2024
2 parents da4b05f + 13aff2f commit 2239687
Show file tree
Hide file tree
Showing 9 changed files with 410 additions and 10 deletions.
2 changes: 1 addition & 1 deletion source/jormungandr/jormungandr/interfaces/v1/Places.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ def get(self, region=None, lon=None, lat=None, uri=None):
uris = uri.split("/")
if len(uris) >= 2:
args["uri"] = transform_id(uris[-1])
# for coherence we check the type of the object
# for coherence, we check the type of the object
obj_type = uris[-2]
if obj_type not in places_types:
abort(404, message='places_nearby api not available for {}'.format(obj_type))
Expand Down
8 changes: 8 additions & 0 deletions source/jormungandr/jormungandr/interfaces/v1/serializer/pt.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class PtObjectSerializer(PbGenericSerializer):
quality = jsonschema.Field(schema_type=int, required=False, display_none=True, deprecated=True)
stop_area = jsonschema.MethodField(schema_type=lambda: StopAreaSerializer())
stop_point = jsonschema.MethodField(schema_type=lambda: StopPointSerializer())
poi = jsonschema.MethodField(schema_type=lambda: PoiSerializer())
line = jsonschema.MethodField(schema_type=lambda: LineSerializer())
network = jsonschema.MethodField(schema_type=lambda: NetworkSerializer())
route = jsonschema.MethodField(schema_type=lambda: RouteSerializer())
Expand Down Expand Up @@ -170,6 +171,12 @@ def get_stop_point(self, obj):
else:
return None

def get_poi(self, obj):
if obj.HasField(str('poi')):
return PoiSerializer(obj.poi, display_none=False).data
else:
return None


class TripSerializer(PbGenericSerializer):
pass
Expand Down Expand Up @@ -357,6 +364,7 @@ class AddressSerializer(PbGenericSerializer):

class PoiSerializer(PbGenericSerializer):
coord = CoordSerializer(required=False)
links = DisruptionLinkSerializer(attr='impact_uris', display_none=False)
label = jsonschema.Field(schema_type=str)
administrative_regions = AdminSerializer(many=True, display_none=False)
poi_type = PoiTypeSerializer(display_none=False)
Expand Down
51 changes: 51 additions & 0 deletions source/jormungandr/jormungandr/scenarios/new_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
switch_back_to_ridesharing,
nCr,
updated_common_journey_request_with_default,
get_disruptions_on_poi,
add_disruptions,
get_impact_uris_for_poi,
)
from navitiacommon import type_pb2, response_pb2, request_pb2
from jormungandr.scenarios.qualifier import (
Expand Down Expand Up @@ -99,6 +102,7 @@
from six.moves import range
from six.moves import zip
from functools import cmp_to_key
from datetime import datetime

SECTION_TYPES_TO_RETAIN = {response_pb2.PUBLIC_TRANSPORT, response_pb2.STREET_NETWORK}
JOURNEY_TAGS_TO_RETAIN = ['best_olympics']
Expand Down Expand Up @@ -491,6 +495,50 @@ def update_total_co2_emission(pb_resp):
j.co2_emission.unit = 'gEC'


def update_disruptions_on_pois(instance, pb_resp):
"""
Maintain a set of uri from all journey.section.origin and journey.section.destination of type Poi,
call loki with api api_disruptions&pois[]...
For each disruption on poi, add disruption id in the attribute links and add disruptions in the response
"""
if not pb_resp.journeys:
return
# Add uri of all the pois in a set
poi_uris = set()
poi_objets = []
since_datetime = date_to_timestamp(datetime.utcnow())
until_datetime = date_to_timestamp(datetime.utcnow())
for j in pb_resp.journeys:
for s in j.sections:
if s.origin.embedded_type == type_pb2.POI:
poi_uris.add(s.origin.uri)
poi_objets.append(s.origin.poi)
since_datetime = min(since_datetime, s.begin_date_time)

if s.destination.embedded_type == type_pb2.POI:
poi_uris.add(s.destination.uri)
poi_objets.append(s.destination.poi)
until_datetime = max(until_datetime, s.end_date_time)

if since_datetime >= until_datetime:
since_datetime = until_datetime - 1
# Get disruptions for poi_uris calling loki with api poi_disruptions and poi_uris in param
poi_disruptions = get_disruptions_on_poi(instance, poi_uris, since_datetime, until_datetime)
if poi_disruptions is None:
return

# For each poi in pt_objects:
# add impact_uris from resp_poi and
# copy object poi in impact.impacted_objects
for pt_object in poi_objets:
impact_uris = get_impact_uris_for_poi(poi_disruptions, pt_object)
for impact_uri in impact_uris:
pt_object.impact_uris.append(impact_uri)

# Add all impacts from resp_poi to the response
add_disruptions(pb_resp, poi_disruptions)


def update_total_air_pollutants(pb_resp):
"""
update journey.air_pollutants
Expand Down Expand Up @@ -1434,6 +1482,9 @@ def fill_journeys(self, request_type, api_request, instance):
# need to clean extra terminus after culling journeys
journey_filter.remove_excess_terminus(pb_resp)

# Update disruptions on pois
update_disruptions_on_pois(instance, pb_resp)

self._compute_pagination_links(pb_resp, instance, api_request['clockwise'])
return pb_resp

Expand Down
12 changes: 11 additions & 1 deletion source/jormungandr/jormungandr/scenarios/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@
from navitiacommon.type_pb2 import ActiveStatus, Severity
from jormungandr.interfaces.common import pb_odt_level
from jormungandr.scenarios.utils import places_type, pt_object_type, add_link
from jormungandr.scenarios.utils import build_pagination
from jormungandr.scenarios.utils import (
build_pagination,
fill_disruptions_on_pois,
fill_disruptions_on_places_nearby,
)
from jormungandr.exceptions import UnknownObject


Expand Down Expand Up @@ -301,6 +305,9 @@ def places_nearby(self, request, instance):
req.places_nearby.filter = request["filter"]
req.disable_disruption = request["disable_disruption"] if request.get("disable_disruption") else False
resp = instance.send_and_receive(req)
# For pois, ws should also call loki to get disruptions on pois
if not req.disable_disruption:
fill_disruptions_on_places_nearby(instance, resp)
build_pagination(request, resp)
return resp

Expand Down Expand Up @@ -335,6 +342,9 @@ def __on_ptref(self, resource_name, requested_type, request, instance):
else:
resp = instance.send_and_receive(req)

# For api = pois, ws should also call loki to get disruptions on pois
if (not req.disable_disruption) and req.ptref.requested_type == type_pb2.POI:
fill_disruptions_on_pois(instance, resp)
build_pagination(request, resp)
return resp

Expand Down
119 changes: 119 additions & 0 deletions source/jormungandr/jormungandr/scenarios/tests/helpers_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
is_car_direct_path,
fill_best_boarding_position,
)
from jormungandr.street_network.tests.streetnetwork_test_utils import make_pt_object
from jormungandr import utils

BEST_BOARDING_POSITIONS = [response_pb2.FRONT, response_pb2.MIDDLE]

Expand Down Expand Up @@ -516,3 +518,120 @@ def fill_best_boarding_position_test():
assert response_pb2.BoardingPosition.FRONT in journey.sections[0].best_boarding_positions
assert response_pb2.BoardingPosition.MIDDLE in journey.sections[0].best_boarding_positions
assert response_pb2.BoardingPosition.BACK not in journey.sections[0].best_boarding_positions


def get_response_with_a_disruption_on_poi():
start_period = "20240712T165200"
end_period = "20240812T165200"
response = response_pb2.Response()
impact = response.impacts.add()
impact.uri = "test_impact_uri"
impact.disruption_uri = "test_disruption_uri"
impacted_object = impact.impacted_objects.add()

# poi = make_pt_object(type_pb2.POI, lon=1, lat=2, uri='poi:test_uri')
# impacted_object.pt_object.CopyFrom(poi)
impacted_object.pt_object.name = "poi_name_from_loki"
impacted_object.pt_object.uri = "poi_uri"
impacted_object.pt_object.embedded_type = type_pb2.POI
impact.updated_at = utils.str_to_time_stamp(u'20240712T205200')
application_period = impact.application_periods.add()
application_period.begin = utils.str_to_time_stamp(start_period)
application_period.end = utils.str_to_time_stamp(end_period)

# Add a message
message = impact.messages.add()
message.text = "This is the message sms"
message.channel.id = "sms"
message.channel.name = "sms"
message.channel.content_type = "text"

# Add a severity
impact.severity.effect = type_pb2.Severity.UNKNOWN_EFFECT
impact.severity.name = ' not blocking'
impact.severity.priority = 1
impact.contributor = "shortterm.test_poi"

return response


def get_object_pois_in_ptref_response():
response = response_pb2.Response()
poi = response.pois.add()
poi.uri = "poi_uri"
poi.name = "poi_name_from_kraken"
poi.coord.lat = 2
poi.coord.lon = 1
poi.poi_type.uri = "poi_type:amenity:parking"
poi.poi_type.name = "Parking P+R"
return response


def get_object_pois_in_places_nearby_response():
response = response_pb2.Response()
place_nearby = response.places_nearby.add()
place_nearby.uri = "poi_uri"
place_nearby.name = "poi_name_from_kraken"
place_nearby.embedded_type = type_pb2.POI
place_nearby.poi.uri = "poi_uri"
place_nearby.poi.name = "poi_name_from_kraken"
place_nearby.poi.coord.lat = 2
place_nearby.poi.coord.lon = 1
place_nearby.poi.poi_type.uri = "poi_type:amenity:parking"
place_nearby.poi.poi_type.name = "Parking P+R"
return response


def get_journey_with_pois():
response = response_pb2.Response()
journey = response.journeys.add()

# Walking section from 'stop_a' to 'poi:test_uri'
section = journey.sections.add()
section.type = response_pb2.STREET_NETWORK
section.street_network.mode = response_pb2.Walking
section.origin.uri = 'stop_a'
section.origin.embedded_type = type_pb2.STOP_POINT
section.destination.uri = 'poi_uri'
section.destination.embedded_type = type_pb2.POI
section.destination.poi.uri = 'poi_uri'
section.destination.poi.name = 'poi_name_from_kraken'
section.destination.poi.coord.lon = 1.0
section.destination.poi.coord.lat = 2.0

# Bss section from 'poi:test_uri' to 'poi_b'
section = journey.sections.add()
section.street_network.mode = response_pb2.Bss
section.type = response_pb2.STREET_NETWORK
section.origin.uri = 'poi_uri'
section.origin.embedded_type = type_pb2.POI
section.origin.poi.uri = 'poi_uri'
section.origin.poi.name = 'poi_name_from_kraken'
section.origin.poi.coord.lon = 1.0
section.origin.poi.coord.lat = 2.0
section.destination.uri = 'poi_b'
section.destination.embedded_type = type_pb2.POI

# Walking section from 'poi_b' to 'stop_b'
section = journey.sections.add()
section.type = response_pb2.STREET_NETWORK
section.street_network.mode = response_pb2.Walking
section.origin.uri = 'poi_b'
section.origin.embedded_type = type_pb2.POI
section.destination.uri = 'stop_b'
section.destination.embedded_type = type_pb2.STOP_POINT
return response


def verify_poi_in_impacted_objects(object, poi_empty=True):
assert object.name == "poi_name_from_loki"
assert object.uri == "poi_uri"
assert object.embedded_type == type_pb2.POI
if poi_empty:
assert object.poi.uri == ''
assert object.poi.name == ''
else:
assert object.poi.uri == 'poi_uri'
assert object.poi.name == 'poi_name_from_kraken'
assert object.poi.coord.lon == 1.0
assert object.poi.coord.lat == 2.0
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@
_tag_journey_by_mode,
get_kraken_calls,
update_best_boarding_positions,
update_disruptions_on_pois,
)
from jormungandr.instance import Instance
from jormungandr.scenarios.utils import switch_back_to_ridesharing
from jormungandr.utils import make_origin_destination_key, str_to_time_stamp
from werkzeug.exceptions import HTTPException
import pytest
from pytest_mock import mocker
from collections import defaultdict

"""
Expand Down Expand Up @@ -798,10 +800,34 @@ def __init__(self, name="fake_instance", olympics_forbidden_uris=None):
}


def make_pt_object_poi(property_type="olympic", property_value="1234"):
pt_object_poi = type_pb2.PtObject()
pt_object_poi.embedded_type = type_pb2.POI
property = pt_object_poi.poi.properties.add()
property.type = property_type
property.value = property_value
return pt_object_poi
def journey_with_disruptions_on_poi_test(mocker):
instance = lambda: None
# As in navitia, object poi in the response of places_nearby doesn't have any impact
response_journey_with_pois = helpers_tests.get_journey_with_pois()
assert len(response_journey_with_pois.impacts) == 0
assert len(response_journey_with_pois.journeys) == 1
journey = response_journey_with_pois.journeys[0]
assert len(journey.sections) == 3

# Prepare disruptions on poi as response of end point poi_disruptions of loki
# pt_object poi as impacted object is absent in the response of poi_disruptions
disruptions_with_poi = helpers_tests.get_response_with_a_disruption_on_poi()
assert len(disruptions_with_poi.impacts) == 1
assert disruptions_with_poi.impacts[0].uri == "test_impact_uri"
assert len(disruptions_with_poi.impacts[0].impacted_objects) == 1
object = disruptions_with_poi.impacts[0].impacted_objects[0].pt_object
helpers_tests.verify_poi_in_impacted_objects(object=object, poi_empty=True)

mock = mocker.patch(
'jormungandr.scenarios.new_default.get_disruptions_on_poi', return_value=disruptions_with_poi
)
update_disruptions_on_pois(instance, response_journey_with_pois)

assert len(response_journey_with_pois.impacts) == 1
impact = response_journey_with_pois.impacts[0]
assert len(impact.impacted_objects) == 1
object = impact.impacted_objects[0].pt_object
helpers_tests.verify_poi_in_impacted_objects(object=object, poi_empty=False)

mock.assert_called_once()
return
Loading

0 comments on commit 2239687

Please sign in to comment.