google / transitfeed

A Python library for reading, validating, and writing transit schedule information in the GTFS format.
https://github.com/google/transitfeed/wiki
Apache License 2.0
679 stars 254 forks source link

Fix crash when validating transfers, in case a stop has missing coordinates #513

Closed Bertware closed 4 years ago

Bertware commented 4 years ago

Currently, when trying to validate a GTFS feed which defines transfers to a station without coordinates, feedvalidator crashes. This fix prevents a division by none to avoid this crash.

After applying this fix, the failing distance calculation is logged to the console, and the stops.txt validation catches the stops without coordinates.

FeedValidator extension used: None
Cannot determine distance between stops 9021080080600000 and 9021080080600000 due to missing coordinates
Cannot determine distance between stops 9021080080600000 and 9021080080600000 due to missing coordinates
Cannot determine distance between stops 9022080080600001 and 9021080080600000 due to missing coordinates
Cannot determine distance between stops 9022080080600001 and 9022080010100001 due to missing coordinates
Cannot determine distance between stops 9022074000003001 and 9022080080600001 due to missing coordinates
ERROR: 4 errors and 20353 warnings found

Process finished with exit code 1

Original error log:

validating sj.zip
FeedValidator extension used: None
Yikes, the program threw an unexpected exception!

Hopefully a complete report has been saved to transitfeedcrash.txt,
though if you are seeing this message we've already disappointed you once
today. Please include the report in a new issue at
https://github.com/google/transitfeed/issues
or an email to the public group transitfeed@googlegroups.com. Sorry!

------------------------------------------------------------
transitfeed version 1.2.16

File "C:/DevTools/transitfeed/feedvalidator.py", line 610, in main
       (feed, options) = ParseCommandLineArguments()
 -->   return RunValidationFromOptions(feed, options)

    feed = sj.zip
    options = {'check_duplicate_trips': False, 'manual_entry': True, 'extension': None, 'error_types_ignore_list': None, 'memory_db': False, 'service_gap_interval': 13, 'latest_version': '', 'limit_per_type': 5, 'performance': None, 'output': 'validation-results.html'}

File "C:/DevTools/transitfeed/feedvalidator.py", line 705, in RunValidationFromOptions
       else:
 -->     return RunValidationOutputFromOptions(feed, options)

    feed = sj.zip
    options = {'check_duplicate_trips': False, 'manual_entry': True, 'extension': None, 'error_types_ignore_list': None, 'memory_db': False, 'service_gap_interval': 13, 'latest_version': '', 'limit_per_type': 5, 'performance': None, 'output': 'validation-results.html'}

File "C:/DevTools/transitfeed/feedvalidator.py", line 508, in RunValidationOutputFromOptions
       else:
 -->     return RunValidationOutputToFilename(feed, options, options.output)

    feed = sj.zip
    options = {'check_duplicate_trips': False, 'manual_entry': True, 'extension': None, 'error_types_ignore_list': None, 'memory_db': False, 'service_gap_interval': 13, 'latest_version': '', 'limit_per_type': 5, 'performance': None, 'output': 'validation-results.html'}

File "C:/DevTools/transitfeed/feedvalidator.py", line 515, in RunValidationOutputToFilename
         output_file = open(output_filename, 'w')
 -->     exit_code = RunValidationOutputToFile(feed, options, output_file)
         output_file.close()
    feed = sj.zip
    output_file = <open file 'validation-results.html', mode 'w' at 0x0000000003FAE540>
    options = {'check_duplicate_trips': False, 'manual_entry': True, 'extension': None, 'error_types_ignore_list': None, 'memory_db': False, 'service_gap_interval': 13, 'latest_version': '', 'limit_per_type': 5, 'performance': None, 'output': 'validation-results.html'}
    output_filename = validation-results.html

File "C:/DevTools/transitfeed/feedvalidator.py", line 533, in RunValidationOutputToFile
       problems = transitfeed.ProblemReporter(accumulator)
 -->   schedule, exit_code = RunValidation(feed, options, problems)
       if isinstance(feed, basestring):
    feed = sj.zip
    accumulator = <__main__.HTMLCountingProblemAccumulator object at 0x000000000401E0F0>
    output_file = <open file 'validation-results.html', mode 'w' at 0x0000000003FAE540>
    problems = <transitfeed.problems.ProblemReporter object at 0x000000000401E0B8>
    options = {'check_duplicate_trips': False, 'manual_entry': True, 'extension': None, 'error_types_ignore_list': None, 'memory_db': False, 'service_gap_interval': 13, 'latest_version': '', 'limit_per_type': 5, 'performance': None, 'output': 'validation-results.html'}

File "C:/DevTools/transitfeed/feedvalidator.py", line 590, in RunValidation
                                    gtfs_factory=gtfs_factory)
 -->   schedule = loader.Load()
       # Start validation: children are already validated by the loader.
    feed = sj.zip
    problems = <transitfeed.problems.ProblemReporter object at 0x000000000401E0B8>
    loader = <transitfeed.loader.Loader instance at 0x000000000402EBC8>
    extension_module = <module 'transitfeed' from 'C:\DevTools\transitfeed\transitfeed\__init__.pyc'>
    options = {'check_duplicate_trips': False, 'manual_entry': True, 'extension': None, 'error_types_ignore_list': None, 'memory_db': False, 'service_gap_interval': 13, 'latest_version': '', 'limit_per_type': 5, 'performance': None, 'output': 'validation-results.html'}
    gtfs_factory = <transitfeed.gtfsfactory.GtfsFactory object at 0x000000000402B1D0>

File "C:\DevTools\transitfeed\transitfeed\loader.py", line 588, in Load
         self._LoadShapes()
 -->     self._LoadFeed()

    self = <transitfeed.loader.Loader instance at 0x000000000402EBC8>

File "C:\DevTools\transitfeed\transitfeed\loader.py", line 423, in _LoadFeed
               instance.AddToSchedule(self._schedule, self._problems)
 -->           instance.ValidateAfterAdd(self._problems)
               self._problems.ClearContext()
    row_num = 2088
    d = {'from_trip_id': u'', 'to_stop_id': u'9021080080600000', 'from_stop_id': u'9021080080600000', 'to_trip_id': u'', 'transfer_type': u'2', 'min_transfer_time': u'480'}
    header = ['from_stop_id', 'to_stop_id', 'transfer_type', 'min_transfer_time', 'from_trip_id', 'to_trip_id']
    self = <transitfeed.loader.Loader instance at 0x000000000402EBC8>
    filename = transfers.txt
    instance = <Transfer [('from_stop_id', u'9021080080600000'), ('from_trip_id', u''), ('min_transfer_time', 480), ('to_stop_id', u'9021080080600000'), ('to_trip_id', u''), ('transfer_type', 2)]>
    loading_order = ['agency.txt', 'stops.txt', 'routes.txt', 'trips.txt', 'transfers.txt', 'fare_attributes.txt', 'fare_rules.txt', 'frequencies.txt', 'feed_info.txt']
    object_class = <class 'transitfeed.transfer.Transfer'>
    row = [u'9021080080600000', u'9021080080600000', u'2', u'480', u'', u'']

File "C:\DevTools\transitfeed\transitfeed\transfer.py", line 185, in ValidateAfterAdd
           self.ValidateTransferDistance(problems)
 -->       self.ValidateTransferWalkingTime(problems)

    valid_stop_ids = True
    self = <Transfer [('from_stop_id', u'9021080080600000'), ('from_trip_id', u''), ('min_transfer_time', 480), ('to_stop_id', u'9021080080600000'), ('to_trip_id', u''), ('transfer_type', 2)]>
    problems = <transitfeed.problems.ProblemReporter object at 0x000000000401E0B8>

File "C:\DevTools\transitfeed\transitfeed\transfer.py", line 163, in ValidateTransferWalkingTime
         FAST_WALKING_SPEED= 2 # 2m/s
 -->     if self.min_transfer_time + 120 < distance / FAST_WALKING_SPEED:
           problems.TransferWalkingSpeedTooFast(from_stop_id=self.from_stop_id,
    distance = None
    problems = <transitfeed.problems.ProblemReporter object at 0x000000000401E0B8>
    FAST_WALKING_SPEED = 2
    self = <Transfer [('from_stop_id', u'9021080080600000'), ('from_trip_id', u''), ('min_transfer_time', 480), ('to_stop_id', u'9021080080600000'), ('to_trip_id', u''), ('transfer_type', 2)]>

TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'

------------------------------------------------------------

Yikes, the program threw an unexpected exception!

Hopefully a complete report has been saved to transitfeedcrash.txt,
though if you are seeing this message we've already disappointed you once
today. Please include the report in a new issue at
https://github.com/google/transitfeed/issues
or an email to the public group transitfeed@googlegroups.com. Sorry!

Press enter to continue...
Bertware commented 4 years ago

This PR includes irrelevant commits, will recreate