From 49ba72f720f4cbd90749b4e72c06c97836fd7cfe Mon Sep 17 00:00:00 2001 From: Nolan Conaway Date: Wed, 20 Nov 2019 11:13:02 -0500 Subject: [PATCH 1/3] update docs, add handling for empty route id --- test/__init__.py | 1 + test/data/has_empty_route_id.protobuf | Bin 0 -> 186349 bytes test/test_models.py | 11 +++++ underground/metadata.py | 8 ++-- underground/models.py | 58 ++++++++++++++++++++++---- 5 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 test/data/has_empty_route_id.protobuf diff --git a/test/__init__.py b/test/__init__.py index a2ec59a..333e4c6 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -21,4 +21,5 @@ "feed_36_weekend.protobuf", "feed_51_weekday.protobuf", "feed_51_weekend.protobuf", + "has_empty_route_id.protobuf", ] diff --git a/test/data/has_empty_route_id.protobuf b/test/data/has_empty_route_id.protobuf new file mode 100644 index 0000000000000000000000000000000000000000..f90137d3572852f4cf5d346ce5c70b6f082a9187 GIT binary patch literal 186349 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 L|MGu+>A(Iz!aBG{ literal 0 HcmV?d00001 diff --git a/test/test_models.py b/test/test_models.py index 00ba520..69c189b 100644 --- a/test/test_models.py +++ b/test/test_models.py @@ -144,3 +144,14 @@ def test_extract_dict_elapsed_ignored(): stops = SubwayFeed(**sample_data).extract_stop_dict() assert "IGNORED" not in stops["1"] assert "EXISTS" in stops["1"] + + +def test_empty_route_id(): + """Test the route functionality when the route id is a blacnk string. + + This uses example data i found in the wild. + """ + trip = {"route_id": "", "start_date": "20191120", "trip_id": "060750_..N"} + trip = models.Trip(**trip) + assert trip.route_id_mapped == "" + assert not trip.route_is_assigned diff --git a/underground/metadata.py b/underground/metadata.py index 5642056..edb395f 100644 --- a/underground/metadata.py +++ b/underground/metadata.py @@ -30,9 +30,11 @@ "Z": 36, } -# There are some routes with aliases that we need to map onto the original ID to -# find the feed ID. -ROUTE_REMAP = {"5X": "5", "6X": "6", "7X": "7", "FX": "F"} +# There are some routes with aliases that we need to map onto the original ID. +# The empty string occurs if the trip has not yet been assigned a route. I have found +# these cases "in the wild" and would rather write code to skip over them than have +# the application break. +ROUTE_REMAP = {"5X": "5", "6X": "6", "7X": "7", "FX": "F", "": ""} for k in ROUTE_FEED_MAP: ROUTE_REMAP[k] = k diff --git a/underground/models.py b/underground/models.py index 67932ee..a4fe234 100644 --- a/underground/models.py +++ b/underground/models.py @@ -51,7 +51,7 @@ def check_start_date(cls, start_date): @pydantic.validator("route_id") def check_route(cls, route_id): - """Start_date is an int, so check it conforms to date expectations.""" + """Check for a valid route ID value.""" if route_id not in metadata.ROUTE_REMAP: raise ValueError( "Invalid route (%s). Must be one of %s." @@ -62,17 +62,33 @@ def check_route(cls, route_id): @property def route_id_mapped(self): - """Run some transformations on self.""" + """Find the parent route ID. + + This is helpful for grabbing the, e.g., 5 Train when you might have a 5X. + """ return metadata.ROUTE_REMAP[self.route_id] + @property + def route_is_assigned(self): + """Return a flag indicating that there is a route.""" + return self.route_id != "" + class StopTimeUpdate(pydantic.BaseModel): """Stop times for a trip. - This includes all future Stop Times for the trip but StopTimes from the past + This includes all future Stop Times for the trip but Stop Times from the past are omitted. The first StopTime in the sequence is the stop the train is currently approaching, stopped at or about to leave. A stop is dropped from the sequence when the train departs the station. + + Transit times are provided at all in-between stops except at those locations where + there are “scheduled holds”. At those locations both arrival and departure times + are given. + + Note that the predicted times are not updated when the train is not moving. Feed + consumers can detect this condition using the timestamp in the VehiclePosition + message. """ stop_id: str @@ -107,7 +123,30 @@ class TripUpdate(pydantic.BaseModel): class Vehicle(pydantic.BaseModel): - """Data model for the vehicle feed message.""" + """Data model for the vehicle feed message. + + From the MTA docs: + + A VehiclePosition entity is provided for every trip when it starts moving. Note that + a train can be assigned (see TripUpdate) but has not started to move (e.g. a train + waiting to leave the origin station), therefore, no VehiclePosition is provided. + + The motivation to include VehiclePosition is to provide the timestamp field. This + is the time of the last detected movement of the train. This allows feed consumers + to detect the situation when a train stops moving (aka stalled). The platform + countdown clocks only count down when trains are moving otherwise they persist the + last published arrival time for that train. If one wants to mimic this behavior you + must first determine the absence of movement (stalled train condition) ), then the + countdown must be stopped. + + As an example, a countdown could be stopped for a trip when the difference between + the timestamp in the VehiclePosition and the timestamp in the field header is + greater than, 90 seconds. + + Note: since VehiclePosition information is not provided until the train starts + moving, it is recommended that feed consumers use the origin terminal departure to + determine a train stalled condition. + """ trip: Trip timestamp: datetime.datetime = None @@ -116,7 +155,11 @@ class Vehicle(pydantic.BaseModel): class Entity(pydantic.BaseModel): - """Model for an element within feed entity.""" + """Model for an element within feed entity. + + As a side note, I have never found a case where there is BOTH a VehiclePosition and + a TripUpdate. + """ id: str vehicle: Vehicle = None @@ -178,9 +221,10 @@ def extract_stop_dict(self, timezone: str = dateutils.DEFAULT_TIMEZONE) -> dict: entities_with_updates = filter(lambda x: x.trip_update is not None, self.entity) trip_updates = map(attrgetter("trip_update"), entities_with_updates) - # grab the updates with stop times + # grab the updates with routes and stop times trip_updates_with_stops = filter( - lambda x: x.stop_time_update is not None, trip_updates + lambda x: x.trip.route_is_assigned and x.stop_time_update is not None, + trip_updates, ) # create (route, stop, time) tuples from each trip stops_flat = ( From 6c73a7620f63a5e03411088950d27eb36b843e83 Mon Sep 17 00:00:00 2001 From: Nolan Conaway Date: Wed, 20 Nov 2019 11:14:32 -0500 Subject: [PATCH 2/3] start testing 3.8 --- .github/workflows/push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 3a44738..dac836d 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -10,7 +10,7 @@ jobs: strategy: max-parallel: 2 matrix: - python-version: [3.6, 3.7] + python-version: [3.6, 3.7, 3.8] steps: - uses: actions/checkout@master From 39bbe1ccf2437be8777c905428d25ece2714bd94 Mon Sep 17 00:00:00 2001 From: Nolan Conaway Date: Wed, 20 Nov 2019 11:17:44 -0500 Subject: [PATCH 3/3] increment version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 968840f..c65dc66 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.masonry.api" [tool.poetry] name = "underground" -version = "0.2.7.3" +version = "0.2.7.4" description = "Utilities for NYC's realtime MTA data feeds." license = "MIT" readme = "readme.md"