Skip to content
This repository was archived by the owner on Nov 30, 2023. It is now read-only.

Add support for trip to trip transfers #509

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions extensions/googletransit/setup_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from . import fareattribute
from . import route
from . import stop
from . import transfer

def GetGtfsFactory(factory = None):
if not factory:
Expand All @@ -38,4 +39,7 @@ def GetGtfsFactory(factory = None):
# Stop class extension
factory.UpdateClass('Stop', stop.Stop)

# Transfer class extension
factory.UpdateClass('Transfer', transfer.Transfer)

return factory
68 changes: 68 additions & 0 deletions extensions/googletransit/transfer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/python2.5

# Copyright (C) 2011 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import transitfeed
from . import util


class Transfer(transitfeed.Transfer):
"""
Extension of transitfeed.Transfer:
- Adds and validates new fields (see _FIELD_NAMES). See
https://developers.google.com/transit/gtfs/reference/gtfs-extensions#TripToTripTransfers
- Adds new ID columns and takes them into account when validating IDs
"""

_FIELD_NAMES = transitfeed.Transfer._FIELD_NAMES + ['from_route_id', 'to_route_id', 'from_trip_id', 'to_trip_id']
_ID_COLUMNS = transitfeed.Transfer._ID_COLUMNS + ['from_route_id', 'to_route_id', 'from_trip_id', 'to_trip_id']

def _ID(self):
return tuple(self[field] for field in self._ID_COLUMNS)

def ValidateAfterAdd(self, problems):
transitfeed.Transfer.ValidateAfterAdd(self, problems)
self.ValidateFromRouteIdIsValid(problems)
self.ValidateToRouteIdIsValid(problems)
self.ValidateFromTripIdIsValid(problems)
self.ValidateToTripIdIsValid(problems)

def ValidateFromTripIdIsValid(self, problems):
if not util.IsEmpty(self.from_trip_id):
if self.from_trip_id not in self._schedule.trips.keys():
problems.InvalidValue('from_trip_id', self.from_trip_id)
return False
return True

def ValidateToTripIdIsValid(self, problems):
if not util.IsEmpty(self.to_trip_id):
if self.to_trip_id not in self._schedule.trips.keys():
problems.InvalidValue('to_trip_id', self.to_trip_id)
return False
return True

def ValidateFromRouteIdIsValid(self, problems):
if not util.IsEmpty(self.from_route_id):
if self.from_route_id not in self._schedule.routes.keys():
problems.InvalidValue('from_route_id', self.from_route_id)
return False
return True

def ValidateToRouteIdIsValid(self, problems):
if not util.IsEmpty(self.to_route_id):
if self.to_route_id not in self._schedule.routes.keys():
problems.InvalidValue('to_route_id', self.to_route_id)
return False
return True
4 changes: 2 additions & 2 deletions tests/data/googletransit/good_feed/feed_info.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
feed_publisher_name,feed_publisher_url,feed_lang,feed_timezone,feed_valid_from,feed_valid_until
Autorité de passage de démonstration,http://google.com,en,America/Los_Angeles,20070101,20111231
feed_publisher_name,feed_publisher_url,feed_lang,feed_start_date,feed_end_date
Autorité de passage de démonstration,http://google.com,en,20070101,20311231
8 changes: 5 additions & 3 deletions tests/data/googletransit/good_feed/transfers.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from_stop_id,to_stop_id,transfer_type,min_transfer_time
NADAV,NANAA,3,
EMSI,NANAA,2,1200
from_stop_id,to_stop_id,transfer_type,min_transfer_time,from_trip_id,to_trip_id
NADAV,NANAA,3,,,
EMSI,NANAA,2,1200,,
EMSI,EMSI,2,240,,
EMSI,EMSI,2,180,CITY1,CITY2
2 changes: 2 additions & 0 deletions tests/data/googletransit/transfers_duplicate_id/agency.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
agency_id,agency_name,agency_url,agency_timezone,agency_phone
DTA,Autorité de passage de démonstration,http://google.com,America/Los_Angeles,123 12314
3 changes: 3 additions & 0 deletions tests/data/googletransit/transfers_duplicate_id/calendar.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date
FULLW,1,1,1,1,1,1,1,20070101,20251231
WE,0,0,0,0,0,1,1,20070101,20251231
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
service_id,date,exception_type
FULLW,20070604,2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fare_id,price,currency_type,payment_method,transfers,transfer_duration,agency_id
p,1.25,USD,0,0,,DTA
a,5.25,USD,0,0,,DTA
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fare_id,route_id,origin_id,destination_id,contains_id
p,AB,,,
p,STBA,,,
p,BFC,,,
a,AAMV,,,
2 changes: 2 additions & 0 deletions tests/data/googletransit/transfers_duplicate_id/feed_info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feed_publisher_name,feed_publisher_url,feed_lang,feed_start_date,feed_end_date
Autorité de passage de démonstration,http://google.com,en,20070101,20311231
12 changes: 12 additions & 0 deletions tests/data/googletransit/transfers_duplicate_id/frequencies.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
trip_id,start_time,end_time,headway_secs,exact_times
STBA,6:00:00,22:00:00,1800,0
CITY1,6:00:00,7:59:59,1800,0
CITY2,6:00:00,7:59:59,1800,0
CITY1,8:00:00,9:59:59,600,0
CITY2,8:00:00,9:59:59,600,0
CITY1,10:00:00,15:59:59,1800,0
CITY2,10:00:00,15:59:59,1800,0
CITY1,16:00:00,18:59:59,600,0
CITY2,16:00:00,18:59:59,600,0
CITY1,19:00:00,22:00:00,1800,0
CITY2,19:00:00,22:00:00,1800,0
6 changes: 6 additions & 0 deletions tests/data/googletransit/transfers_duplicate_id/routes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
route_id,agency_id,route_short_name,route_long_name,route_desc,route_type,route_url,route_color,route_text_color
AB,DTA,,Airport ⇒ Bullfrog,,3,,,
BFC,DTA,,Bullfrog ⇒ Furnace Creek Resort,,3,,,
STBA,DTA,,Stagecoach ⇒ Airport Shuttle,,3,,,
CITY,DTA,Ō,Bar Circle,Route with ĸool unicode shortname,3,,,
AAMV,DTA,,Airport ⇒ Amargosa Valley,,3,,,
29 changes: 29 additions & 0 deletions tests/data/googletransit/transfers_duplicate_id/stop_times.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
trip_id,arrival_time,departure_time,stop_id,stop_sequence,stop_headsign,pickup_type,drop_off_type,shape_dist_traveled
STBA,6:00:00,6:00:00,STAGECOACH,0,to airport,1,0,0.212
STBA,6:20:00,6:20:00,BEATTY_AIRPORT,2,,0,0,1.043
CITY1,6:00:00,6:00:00,STAGECOACH,0,,,,
CITY1,6:05:00,6:07:00,NANAA,5,going to nadav,2,3,
CITY1,6:12:00,6:14:00,NADAV,10,,,,
CITY1,6:19:00,6:21:00,DADAN,15,,,,
CITY1,6:26:00,6:28:00,EMSI,20,,,,
CITY2,6:28:00,6:30:00,EMSI,100,,,,
CITY2,6:35:00,6:37:00,DADAN,200,,,,
CITY2,6:42:00,6:44:00,NADAV,300,,,,
CITY2,6:49:00,6:51:00,NANAA,400,,,,
CITY2,6:56:00,6:58:00,STAGECOACH,500,,,,
AB1,8:00:00,8:00:00,BEATTY_AIRPORT,1,,,,
AB1,8:10:00,8:15:00,BULLFROG,2,,,,
AB2,12:05:00,12:05:00,BULLFROG,1,,,,
AB2,12:15:00,12:15:00,BEATTY_AIRPORT,2,,,,
BFC1,8:20:00,8:20:00,BULLFROG,1,,,,
BFC1,9:20:00,9:20:00,FUR_CREEK_RES,2,,,,
BFC2,11:00:00,11:00:00,FUR_CREEK_RES,1,,,,
BFC2,12:00:00,12:00:00,BULLFROG,2,,,,
AAMV1,8:00:00,8:00:00,BEATTY_AIRPORT,1,,,,
AAMV1,9:00:00,9:00:00,AMV,2,,,,
AAMV2,10:00:00,10:00:00,AMV,1,,,,
AAMV2,11:00:00,11:00:00,BEATTY_AIRPORT,2,,,,
AAMV3,13:00:00,13:00:00,BEATTY_AIRPORT,1,,,,
AAMV3,14:00:00,14:00:00,AMV,2,,,,
AAMV4,15:00:00,15:00:00,AMV,1,,,,
AAMV4,16:00:00,16:00:00,BEATTY_AIRPORT,2,,,,
11 changes: 11 additions & 0 deletions tests/data/googletransit/transfers_duplicate_id/stops.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
stop_id,stop_name,stop_desc,stop_lat,stop_lon,zone_id,stop_url,stop_code,location_type,parent_station
FUR_CREEK_RES,Furnace Creek Resort (Demo),,36.425288,-117.133162,,,1234,,
BEATTY_AIRPORT,Nye County Airport (Demo),,36.868446,-116.784582,,,1235,0,BEATTY_AIRPORT_STATION
BEATTY_AIRPORT_STATION,Nye County Airport (Demo),,36.868446,-116.784582,,,1235,1,
BULLFROG,Bullfrog (Demo),,36.88108,-116.81797,,,,,
STAGECOACH,Stagecoach Hotel & Casino (Demo),,36.915682,-116.751677,,,1236,,
NADAV,North Ave / D Ave N (Demo),,36.914893,-116.76821,,,1237,,
NANAA,North Ave / N A Ave (Demo),,36.914944,-116.761472,,,1238,,
DADAN,Doing Ave / D Ave N (Demo),,36.909489,-116.768242,,,,,
EMSI,E Main St / S Irving St (Demo),,36.905697,-116.76218,,,,,
AMV,Amargosa Valley (Demo),,36.641496,-116.40094,,,,,
8 changes: 8 additions & 0 deletions tests/data/googletransit/transfers_duplicate_id/transfers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from_stop_id,to_stop_id,transfer_type,min_transfer_time,from_trip_id,to_trip_id
NADAV,NANAA,3,,,
EMSI,NANAA,2,1200,,
EMSI,EMSI,2,240,,
EMSI,EMSI,2,180,CITY1,CITY2
EMSI,EMSI,2,180,CITY2,CITY1
EMSI,EMSI,2,180,AAMV4,AAMV4
EMSI,EMSI,2,180,AAMV4,AAMV4
12 changes: 12 additions & 0 deletions tests/data/googletransit/transfers_duplicate_id/trips.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
route_id,service_id,trip_id,trip_headsign,direction_id,block_id,shape_id
AB,FULLW,AB1,to Bullfrog,0,1,
AB,FULLW,AB2,to Airport,1,2,
STBA,FULLW,STBA,Shuttle,,,
CITY,FULLW,CITY1,,0,,
CITY,FULLW,CITY2,,1,,
BFC,FULLW,BFC1,to Furnace Creek Resort,0,1,
BFC,FULLW,BFC2,to Bullfrog,1,2,
AAMV,WE,AAMV1,to Amargosa Valley,0,,
AAMV,WE,AAMV2,to Airport,1,,
AAMV,WE,AAMV3,to Amargosa Valley,0,,
AAMV,WE,AAMV4,to Airport,1,,
2 changes: 2 additions & 0 deletions tests/data/googletransit/transfers_invalid_trip_id/agency.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
agency_id,agency_name,agency_url,agency_timezone,agency_phone
DTA,Autorité de passage de démonstration,http://google.com,America/Los_Angeles,123 12314
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date
FULLW,1,1,1,1,1,1,1,20070101,20251231
WE,0,0,0,0,0,1,1,20070101,20251231
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
service_id,date,exception_type
FULLW,20070604,2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fare_id,price,currency_type,payment_method,transfers,transfer_duration,agency_id
p,1.25,USD,0,0,,DTA
a,5.25,USD,0,0,,DTA
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fare_id,route_id,origin_id,destination_id,contains_id
p,AB,,,
p,STBA,,,
p,BFC,,,
a,AAMV,,,
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feed_publisher_name,feed_publisher_url,feed_lang,feed_start_date,feed_end_date
Autorité de passage de démonstration,http://google.com,en,20070101,20311231
12 changes: 12 additions & 0 deletions tests/data/googletransit/transfers_invalid_trip_id/frequencies.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
trip_id,start_time,end_time,headway_secs,exact_times
STBA,6:00:00,22:00:00,1800,0
CITY1,6:00:00,7:59:59,1800,0
CITY2,6:00:00,7:59:59,1800,0
CITY1,8:00:00,9:59:59,600,0
CITY2,8:00:00,9:59:59,600,0
CITY1,10:00:00,15:59:59,1800,0
CITY2,10:00:00,15:59:59,1800,0
CITY1,16:00:00,18:59:59,600,0
CITY2,16:00:00,18:59:59,600,0
CITY1,19:00:00,22:00:00,1800,0
CITY2,19:00:00,22:00:00,1800,0
6 changes: 6 additions & 0 deletions tests/data/googletransit/transfers_invalid_trip_id/routes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
route_id,agency_id,route_short_name,route_long_name,route_desc,route_type,route_url,route_color,route_text_color
AB,DTA,,Airport ⇒ Bullfrog,,3,,,
BFC,DTA,,Bullfrog ⇒ Furnace Creek Resort,,3,,,
STBA,DTA,,Stagecoach ⇒ Airport Shuttle,,3,,,
CITY,DTA,Ō,Bar Circle,Route with ĸool unicode shortname,3,,,
AAMV,DTA,,Airport ⇒ Amargosa Valley,,3,,,
29 changes: 29 additions & 0 deletions tests/data/googletransit/transfers_invalid_trip_id/stop_times.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
trip_id,arrival_time,departure_time,stop_id,stop_sequence,stop_headsign,pickup_type,drop_off_type,shape_dist_traveled
STBA,6:00:00,6:00:00,STAGECOACH,0,to airport,1,0,0.212
STBA,6:20:00,6:20:00,BEATTY_AIRPORT,2,,0,0,1.043
CITY1,6:00:00,6:00:00,STAGECOACH,0,,,,
CITY1,6:05:00,6:07:00,NANAA,5,going to nadav,2,3,
CITY1,6:12:00,6:14:00,NADAV,10,,,,
CITY1,6:19:00,6:21:00,DADAN,15,,,,
CITY1,6:26:00,6:28:00,EMSI,20,,,,
CITY2,6:28:00,6:30:00,EMSI,100,,,,
CITY2,6:35:00,6:37:00,DADAN,200,,,,
CITY2,6:42:00,6:44:00,NADAV,300,,,,
CITY2,6:49:00,6:51:00,NANAA,400,,,,
CITY2,6:56:00,6:58:00,STAGECOACH,500,,,,
AB1,8:00:00,8:00:00,BEATTY_AIRPORT,1,,,,
AB1,8:10:00,8:15:00,BULLFROG,2,,,,
AB2,12:05:00,12:05:00,BULLFROG,1,,,,
AB2,12:15:00,12:15:00,BEATTY_AIRPORT,2,,,,
BFC1,8:20:00,8:20:00,BULLFROG,1,,,,
BFC1,9:20:00,9:20:00,FUR_CREEK_RES,2,,,,
BFC2,11:00:00,11:00:00,FUR_CREEK_RES,1,,,,
BFC2,12:00:00,12:00:00,BULLFROG,2,,,,
AAMV1,8:00:00,8:00:00,BEATTY_AIRPORT,1,,,,
AAMV1,9:00:00,9:00:00,AMV,2,,,,
AAMV2,10:00:00,10:00:00,AMV,1,,,,
AAMV2,11:00:00,11:00:00,BEATTY_AIRPORT,2,,,,
AAMV3,13:00:00,13:00:00,BEATTY_AIRPORT,1,,,,
AAMV3,14:00:00,14:00:00,AMV,2,,,,
AAMV4,15:00:00,15:00:00,AMV,1,,,,
AAMV4,16:00:00,16:00:00,BEATTY_AIRPORT,2,,,,
11 changes: 11 additions & 0 deletions tests/data/googletransit/transfers_invalid_trip_id/stops.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
stop_id,stop_name,stop_desc,stop_lat,stop_lon,zone_id,stop_url,stop_code,location_type,parent_station
FUR_CREEK_RES,Furnace Creek Resort (Demo),,36.425288,-117.133162,,,1234,,
BEATTY_AIRPORT,Nye County Airport (Demo),,36.868446,-116.784582,,,1235,0,BEATTY_AIRPORT_STATION
BEATTY_AIRPORT_STATION,Nye County Airport (Demo),,36.868446,-116.784582,,,1235,1,
BULLFROG,Bullfrog (Demo),,36.88108,-116.81797,,,,,
STAGECOACH,Stagecoach Hotel & Casino (Demo),,36.915682,-116.751677,,,1236,,
NADAV,North Ave / D Ave N (Demo),,36.914893,-116.76821,,,1237,,
NANAA,North Ave / N A Ave (Demo),,36.914944,-116.761472,,,1238,,
DADAN,Doing Ave / D Ave N (Demo),,36.909489,-116.768242,,,,,
EMSI,E Main St / S Irving St (Demo),,36.905697,-116.76218,,,,,
AMV,Amargosa Valley (Demo),,36.641496,-116.40094,,,,,
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from_stop_id,to_stop_id,transfer_type,min_transfer_time,from_trip_id,to_trip_id
NADAV,NANAA,3,,,
EMSI,NANAA,2,1200,,
EMSI,EMSI,2,240,,
EMSI,EMSI,2,180,FAKE,CITY2
12 changes: 12 additions & 0 deletions tests/data/googletransit/transfers_invalid_trip_id/trips.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
route_id,service_id,trip_id,trip_headsign,direction_id,block_id,shape_id
AB,FULLW,AB1,to Bullfrog,0,1,
AB,FULLW,AB2,to Airport,1,2,
STBA,FULLW,STBA,Shuttle,,,
CITY,FULLW,CITY1,,0,,
CITY,FULLW,CITY2,,1,,
BFC,FULLW,BFC1,to Furnace Creek Resort,0,1,
BFC,FULLW,BFC2,to Bullfrog,1,2,
AAMV,WE,AAMV1,to Amargosa Valley,0,,
AAMV,WE,AAMV2,to Airport,1,,
AAMV,WE,AAMV3,to Amargosa Valley,0,,
AAMV,WE,AAMV4,to Airport,1,,
16 changes: 16 additions & 0 deletions tests/testgoogletransitextension.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import transitfeed
from tests.testfeedvalidator import FullTests
from tests.util import MemoryZipTestCase, ValidationTestCase
from tests import util


class ExtensionFullTests(FullTests):
Expand All @@ -50,6 +51,21 @@ def testGoogleTransitGoodFeed(self):
self.assertFalse(re.search(r'ERROR', htmlout))
self.assertFalse(os.path.exists('transitfeedcrash.txt'))

class TransfersInvalidTripIds(util.LoadTestCase):
def runTest(self):
gtfs_factory = extensions.googletransit.GetGtfsFactory()
self.Load('googletransit/transfers_invalid_trip_id', gtfs_factory)
e = self.accumulator.PopException('InvalidValue')
self.assertTrue(re.search(r'from_trip_id', e.column_name))
self.assertTrue(re.search(r'FAKE', e.value))
self.accumulator.AssertNoMoreExceptions()

class TransfersDuplicateIds(util.LoadTestCase):
def runTest(self):
gtfs_factory = extensions.googletransit.GetGtfsFactory()
self.Load('googletransit/transfers_duplicate_id', gtfs_factory)
self.accumulator.PopException('DuplicateID')
self.accumulator.AssertNoMoreExceptions()

class ExtensionMemoryZipTestCase(MemoryZipTestCase):
"""ExtendMemoryZipTestCase to also ignore DeprecatedColumn errors.
Expand Down
4 changes: 2 additions & 2 deletions tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,9 @@ def setUp(self):
self.accumulator = RecordingProblemAccumulator(self, ("ExpirationDate",))
self.problems = transitfeed.ProblemReporter(self.accumulator)

def Load(self, feed_name):
def Load(self, feed_name, gtfs_factory=None):
loader = transitfeed.Loader(
DataPath(feed_name), problems=self.problems, extra_validation=True)
DataPath(feed_name), problems=self.problems, extra_validation=True, gtfs_factory=gtfs_factory)
loader.Load()

def ExpectInvalidValue(self, feed_name, column_name):
Expand Down
6 changes: 3 additions & 3 deletions transitfeed/gtfsfactory.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def __init__(self):
'fare_rules.txt': { 'required': False, 'loading_order': 60,
'classes': ['FareRule']},

'feed_info.txt': { 'required': False, 'loading_order': 100,
'feed_info.txt': { 'required': False, 'loading_order': 100,
'classes': ['FeedInfo']},

'frequencies.txt': { 'required': False, 'loading_order': 70,
Expand All @@ -91,10 +91,10 @@ def __init__(self):
'routes.txt': { 'required': True, 'loading_order': 20,
'classes': ['Route']},

'transfers.txt': { 'required': False, 'loading_order': 30,
'transfers.txt': { 'required': False, 'loading_order': 40,
'classes': ['Transfer']},

'trips.txt': { 'required': True, 'loading_order': 40,
'trips.txt': { 'required': True, 'loading_order': 30,
'classes': ['Trip']},

}
Expand Down