def AddStopTimeObject(self, stoptime, schedule=None, problems=None): """Add a StopTime object to the end of this trip. Args: stoptime: A StopTime object. Should not be reused in multiple trips. schedule: Schedule object containing this trip which must be passed to Trip.__init__ or here problems: ProblemReporter object for validating the StopTime in its new home Returns: None """ if schedule is None: schedule = self._schedule if schedule is None: warnings.warn( "No longer supported. _schedule attribute is used to get " "stop_times table", DeprecationWarning) if problems is None: problems = schedule.problem_reporter if stoptime._cursor_factory is None: stoptime._cursor_factory = schedule new_secs = stoptime.GetTimeSecs() cursor = schedule._connection.cursor() cursor.execute( "SELECT max(stop_sequence), max(arrival_secs), " "max(departure_secs) FROM stop_times WHERE trip_id=?", (self.trip_id, )) row = cursor.fetchone() if row[0] is None: # This is the first stop_time of the trip stoptime.stop_sequence = 1 if new_secs == None: problems.OtherProblem( 'No time for first StopTime of trip_id "%s"' % (self.trip_id, )) else: stoptime.stop_sequence = row[0] + 1 prev_secs = max(row[1], row[2]) if new_secs != None and new_secs < prev_secs: problems.OtherProblem( 'out of order stop time for stop_id=%s trip_id=%s %s < %s' % (util.EncodeUnicode( stoptime.stop_id), util.EncodeUnicode(self.trip_id), util.FormatSecondsSinceMidnight(new_secs), util.FormatSecondsSinceMidnight(prev_secs))) self._AddStopTimeObjectUnordered(stoptime)
def _Report(self, e): levels = {TYPE_ERROR: logging.ERROR, TYPE_WARNING: logging.WARNING, TYPE_NOTICE: logging.INFO} context = e.FormatContext() if context: #logging.log(levels[e.type],context) logger.log(levels[e.type],context) #exit(1) #logging.log(levels[e.type],util.EncodeUnicode(self._LineWrap(e.FormatProblem(), 78))) logger.log(levels[e.type],util.EncodeUnicode(self._LineWrap(e.FormatProblem(), 78)))
def GetDictToFormat(self): """Return a copy of self as a dict, suitable for passing to FormatProblem""" d = {} for k, v in self.__dict__.items(): # TODO: Better handling of unicode/utf-8 within Schedule objects. # Concatinating a unicode and utf-8 str object causes an exception such # as "UnicodeDecodeError: 'ascii' codec can't decode byte ..." as python # tries to convert the str to a unicode. To avoid that happening within # the problem reporter convert all unicode attributes to utf-8. # Currently valid utf-8 fields are converted to unicode in _ReadCsvDict. # Perhaps all fields should be left as utf-8. d[k] = util.EncodeUnicode(v) return d
def ValidateStops(self, problems, validate_children): # Check for stops that aren't referenced by any trips and broken # parent_station references. Also check that the parent station isn't too # far from its child stops. for stop in self.stops.values(): if validate_children: stop.Validate(problems) cursor = self._connection.cursor() cursor.execute("SELECT count(*) FROM stop_times WHERE stop_id=? LIMIT 1", (stop.stop_id,)) count = cursor.fetchone()[0] if stop.location_type == 0 and count == 0: problems.UnusedStop(stop.stop_id, stop.stop_name) elif stop.location_type == 1 and count != 0: problems.UsedStation(stop.stop_id, stop.stop_name) if stop.location_type != 1 and stop.parent_station: if stop.parent_station not in self.stops: problems.InvalidValue("parent_station", util.EncodeUnicode(stop.parent_station), "parent_station '%s' not found for stop_id " "'%s' in stops.txt" % (util.EncodeUnicode(stop.parent_station), util.EncodeUnicode(stop.stop_id))) elif self.stops[stop.parent_station].location_type != 1: problems.InvalidValue("parent_station", util.EncodeUnicode(stop.parent_station), "parent_station '%s' of stop_id '%s' must " "have location_type=1 in stops.txt" % (util.EncodeUnicode(stop.parent_station), util.EncodeUnicode(stop.stop_id))) else: parent_station = self.stops[stop.parent_station] distance = util.ApproximateDistanceBetweenStops(stop, parent_station) if distance > problems_module.MAX_DISTANCE_BETWEEN_STOP_AND_PARENT_STATION_ERROR: problems.StopTooFarFromParentStation( stop.stop_id, stop.stop_name, parent_station.stop_id, parent_station.stop_name, distance, problems_module.TYPE_ERROR) elif distance > problems_module.MAX_DISTANCE_BETWEEN_STOP_AND_PARENT_STATION_WARNING: problems.StopTooFarFromParentStation( stop.stop_id, stop.stop_name, parent_station.stop_id, parent_station.stop_name, distance, problems_module.TYPE_WARNING)
def ValidateNearbyStops(self, problems): # Check for stops that might represent the same location (specifically, # stops that are less that 2 meters apart) First filter out stops without a # valid lat and lon. Then sort by latitude, then find the distance between # each pair of stations within 2 meters latitude of each other. This avoids # doing n^2 comparisons in the average case and doesn't need a spatial # index. sorted_stops = filter(lambda s: s.stop_lat and s.stop_lon, self.GetStopList()) sorted_stops.sort(key=(lambda x: x.stop_lat)) TWO_METERS_LAT = 0.000018 for index, stop in enumerate(sorted_stops[:-1]): index += 1 while ((index < len(sorted_stops)) and ((sorted_stops[index].stop_lat - stop.stop_lat) < TWO_METERS_LAT)): distance = util.ApproximateDistanceBetweenStops(stop, sorted_stops[index]) if distance < 2: other_stop = sorted_stops[index] if stop.location_type == 0 and other_stop.location_type == 0: problems.StopsTooClose( util.EncodeUnicode(stop.stop_name), util.EncodeUnicode(stop.stop_id), util.EncodeUnicode(other_stop.stop_name), util.EncodeUnicode(other_stop.stop_id), distance) elif stop.location_type == 1 and other_stop.location_type == 1: problems.StationsTooClose( util.EncodeUnicode(stop.stop_name), util.EncodeUnicode(stop.stop_id), util.EncodeUnicode(other_stop.stop_name), util.EncodeUnicode(other_stop.stop_id), distance) elif (stop.location_type in (0, 1) and other_stop.location_type in (0, 1)): if stop.location_type == 0 and other_stop.location_type == 1: this_stop = stop this_station = other_stop elif stop.location_type == 1 and other_stop.location_type == 0: this_stop = other_stop this_station = stop if this_stop.parent_station != this_station.stop_id: problems.DifferentStationTooClose( util.EncodeUnicode(this_stop.stop_name), util.EncodeUnicode(this_stop.stop_id), util.EncodeUnicode(this_station.stop_name), util.EncodeUnicode(this_station.stop_id), distance) index += 1
def WriteGoogleTransitFeed(self, file): """Output this schedule as a Google Transit Feed in file_name. Args: file: path of new feed file (a string) or a file-like object Returns: None """ # Compression type given when adding each file archive = zipfile.ZipFile(file, 'w') if 'agency' in self._table_columns: agency_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(agency_string) columns = self.GetTableColumns('agency') writer.writerow(columns) for a in self._agencies.values(): writer.writerow([util.EncodeUnicode(a[c]) for c in columns]) self._WriteArchiveString(archive, 'agency.txt', agency_string) calendar_dates_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(calendar_dates_string) writer.writerow( self._gtfs_factory.ServicePeriodException._FIELD_NAMES) has_data = False for period in self.service_periods.values(): for row in period.GenerateCalendarDatesFieldValuesTuples(): has_data = True writer.writerow(row) wrote_calendar_dates = False if has_data: wrote_calendar_dates = True self._WriteArchiveString(archive, 'calendar_dates.txt', calendar_dates_string) calendar_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(calendar_string) writer.writerow(self._gtfs_factory.ServicePeriod._FIELD_NAMES) has_data = False for s in self.service_periods.values(): row = s.GetCalendarFieldValuesTuple() if row: has_data = True writer.writerow(row) if has_data or not wrote_calendar_dates: self._WriteArchiveString(archive, 'calendar.txt', calendar_string) if 'stops' in self._table_columns: stop_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(stop_string) columns = self.GetTableColumns('stops') writer.writerow(columns) for s in self.stops.values(): writer.writerow([util.EncodeUnicode(s[c]) for c in columns]) self._WriteArchiveString(archive, 'stops.txt', stop_string) if 'routes' in self._table_columns: route_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(route_string) columns = self.GetTableColumns('routes') writer.writerow(columns) for r in self.routes.values(): writer.writerow([util.EncodeUnicode(r[c]) for c in columns]) self._WriteArchiveString(archive, 'routes.txt', route_string) if 'trips' in self._table_columns: trips_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(trips_string) columns = self.GetTableColumns('trips') writer.writerow(columns) for t in self.trips.values(): writer.writerow([util.EncodeUnicode(t[c]) for c in columns]) self._WriteArchiveString(archive, 'trips.txt', trips_string) # write frequencies.txt (if applicable) headway_rows = [] for trip in self.GetTripList(): headway_rows += trip.GetFrequencyOutputTuples() if headway_rows: headway_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(headway_string) writer.writerow(self._gtfs_factory.Frequency._FIELD_NAMES) writer.writerows(headway_rows) self._WriteArchiveString(archive, 'frequencies.txt', headway_string) # write fares (if applicable) if self.GetFareAttributeList(): fare_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(fare_string) writer.writerow(self._gtfs_factory.FareAttribute._FIELD_NAMES) writer.writerows( f.GetFieldValuesTuple() for f in self.GetFareAttributeList()) self._WriteArchiveString(archive, 'fare_attributes.txt', fare_string) # write fare rules (if applicable) rule_rows = [] for fare in self.GetFareAttributeList(): for rule in fare.GetFareRuleList(): rule_rows.append(rule.GetFieldValuesTuple()) if rule_rows: rule_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(rule_string) writer.writerow(self._gtfs_factory.FareRule._FIELD_NAMES) writer.writerows(rule_rows) self._WriteArchiveString(archive, 'fare_rules.txt', rule_string) stop_times_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(stop_times_string) writer.writerow(self._gtfs_factory.StopTime._FIELD_NAMES) for t in self.trips.values(): writer.writerows(t._GenerateStopTimesTuples()) self._WriteArchiveString(archive, 'stop_times.txt', stop_times_string) # write shapes (if applicable) shape_rows = [] for shape in self.GetShapeList(): seq = 1 for (lat, lon, dist) in shape.points: shape_rows.append((shape.shape_id, lat, lon, seq, dist)) seq += 1 if shape_rows: shape_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(shape_string) writer.writerow(self._gtfs_factory.ShapePoint._FIELD_NAMES) writer.writerows(shape_rows) self._WriteArchiveString(archive, 'shapes.txt', shape_string) if 'transfers' in self._table_columns: transfer_string = StringIO.StringIO() writer = util.CsvUnicodeWriter(transfer_string) columns = self.GetTableColumns('transfers') writer.writerow(columns) for t in self.GetTransferIter(): writer.writerow([util.EncodeUnicode(t[c]) for c in columns]) self._WriteArchiveString(archive, 'transfers.txt', transfer_string) archive.close()
def _Report(self, e): context = e.FormatContext() if context: print context print util.EncodeUnicode(self._LineWrap(e.FormatProblem(), 78))