def add_stops_to_feed(self, feed, data): stops = data.get_stops() stops_by_name = {} for internal_stop_id, a_stop in stops['regular'].items(): if a_stop.name not in stops_by_name: stops_by_name[a_stop.name] = [] stops_by_name[a_stop.name].append(a_stop) for a_stop_name in stops_by_name: stop_areas = [] for a_stop_point in sorted(stops_by_name[a_stop_name], key=get_stop_id): gtfs_stop_point = create_stop_point(a_stop_point, feed) stop_point_has_parent_location = False for a_stop_area in stop_areas: distance_to_parent_station = Helper.get_crow_fly_distance( (a_stop_area.stop_lat, a_stop_area.stop_lon), (a_stop_point.lat, a_stop_point.lon)) if distance_to_parent_station < 500: gtfs_stop_point.parent_station = a_stop_area.stop_id stop_point_has_parent_location = True break if not stop_point_has_parent_location: new_sa = create_stop_area(a_stop_point, feed) gtfs_stop_point.parent_station = new_sa.stop_id stop_areas.append(new_sa)
def add_stops_to_feed(self, feed, data): stops = data.get_stops() stops_by_name = {} for internal_stop_id, a_stop in stops['regular'].items(): if a_stop.name not in stops_by_name: stops_by_name[a_stop.name] = [] stops_by_name[a_stop.name].append(a_stop) for a_stop_name in stops_by_name: stop_areas = [] for a_stop_point in sorted(stops_by_name[a_stop_name], key=get_stop_id): gtfs_stop_point = create_stop_point(a_stop_point, feed) stop_point_has_parent_location = False for a_stop_area in stop_areas: distance_to_parent_station = Helper.get_crow_fly_distance( (a_stop_area.stop_lat, a_stop_area.stop_lon), (a_stop_point.lat, a_stop_point.lon) ) if distance_to_parent_station < 500: gtfs_stop_point.parent_station = a_stop_area.stop_id stop_point_has_parent_location = True break if not stop_point_has_parent_location: new_sa = create_stop_area(a_stop_point, feed) gtfs_stop_point.parent_station = new_sa.stop_id stop_areas.append(new_sa)
def _build_stop(self, stop, osm_type): """Helper function to build a Stop object Returns a initiated Stop object from raw data """ if self._is_valid_stop_candidate(stop): # Make sure name is not empty if "name" not in stop.tags: stop.tags["name"] = "[{}]".format(self.stop_no_name) # Ways don't have a pair of coordinates and need to be calculated if osm_type == "way": (stop.lat, stop.lon) = Helper.get_center_of_nodes( stop.get_nodes()) # Move to Elements class, once attributes with defaults play well # with inheritance https://github.com/python-attrs/attrs/issues/38 osm_url = "https://osm.org/" + str( osm_type) + "/" + str(stop.id) # Create and return Stop object stop = Stop(osm_id=stop.id, osm_type=osm_type, osm_url=osm_url, tags=stop.tags, name=stop.tags['name'], lat=stop.lat, lon=stop.lon) return stop else: logging.warning( "Warning: Potential stop is invalid and has been ignored.") logging.warning( " Check tagging: https://osm.org/%s/%s", osm_type, stop.id) return None
def _define_route_text_color(self, route): """ Returns the route_text_color for the use in the GTFS feed. Can be easily overridden in any creator. """ if route.route_text_color is None: # Auto calculate text color with high contrast route.route_text_color = Helper.calculate_color_of_contrast( route.route_color) return route.route_text_color[1:]
def add_trips_to_feed(self, feed, data): self.service_weekday = feed.GetDefaultServicePeriod() self.service_weekday.SetStartDate( self.config['feed_info']['start_date']) self.service_weekday.SetEndDate(self.config['feed_info']['end_date']) self.service_weekday.SetWeekdayService(True) self.service_weekday.SetWeekendService(True) lines = data.routes for route_ref, line in sorted(lines.iteritems()): if not isinstance(line, Line): continue print("Generating schedule for line: " + route_ref) line_gtfs = feed.AddRoute( short_name=str(line.route_id), long_name=line.name, # we change the route_long_name with the 'from' and 'to' tags # of the last route as the route_master name tag contains # the line code (route_short_name) route_type="Bus", route_id=line.osm_id) line_gtfs.agency_id = feed.GetDefaultAgency().agency_id line_gtfs.route_desc = "" line_gtfs.route_color = "1779c2" line_gtfs.route_text_color = "ffffff" route_index = 0 itineraries = line.get_itineraries() for a_route in itineraries: trip_gtfs = line_gtfs.AddTrip(feed) trip_gtfs.shape_id = self._add_shape_to_feed( feed, a_route.osm_id, a_route) trip_gtfs.direction_id = route_index % 2 route_index += 1 if a_route.fr and a_route.to: trip_gtfs.trip_headsign = a_route.to line_gtfs.route_long_name = a_route.fr.decode( 'utf8') + " ↔ ".decode('utf8') + a_route.to.decode( 'utf8') DEFAULT_ROUTE_FREQUENCY = 30 DEFAULT_TRAVEL_TIME = 120 frequency = None if "frequency" in line.tags: frequency = line.tags['frequency'] try: ROUTE_FREQUENCY = int(frequency) if not ROUTE_FREQUENCY > 0: print("frequency is invalid for route_master " + str(line.osm_id)) ROUTE_FREQUENCY = DEFAULT_ROUTE_FREQUENCY except (ValueError, TypeError) as e: print("frequency not a number for route_master " + str(line.osm_id)) ROUTE_FREQUENCY = DEFAULT_ROUTE_FREQUENCY trip_gtfs.AddFrequency("05:00:00", "22:00:00", ROUTE_FREQUENCY * 60) if 'travel_time' in a_route.tags: try: TRAVEL_TIME = int(a_route.tags['travel_time']) if not TRAVEL_TIME > 0: print("travel_time is invalid for route " + str(a_route.osm_id)) TRAVEL_TIME = DEFAULT_TRAVEL_TIME except (ValueError, TypeError) as e: print("travel_time not a number for route " + str(a_route.osm_id)) TRAVEL_TIME = DEFAULT_TRAVEL_TIME for index_stop, a_stop in enumerate(a_route.stops): stop_id = a_stop.split('/')[-1] departure_time = datetime(2008, 11, 22, 6, 0, 0) if index_stop == 0: trip_gtfs.AddStopTime( feed.GetStop(str(stop_id)), stop_time=departure_time.strftime("%H:%M:%S")) elif index_stop == len(a_route.stops) - 1: departure_time += timedelta(minutes=TRAVEL_TIME) trip_gtfs.AddStopTime( feed.GetStop(str(stop_id)), stop_time=departure_time.strftime("%H:%M:%S")) else: trip_gtfs.AddStopTime(feed.GetStop(str(stop_id))) for secs, stop_time, is_timepoint in trip_gtfs.GetTimeInterpolatedStops( ): if not is_timepoint: stop_time.arrival_secs = secs stop_time.departure_secs = secs trip_gtfs.ReplaceStopTimeObject(stop_time) Helper.interpolate_stop_times(trip_gtfs)
def add_trips_by_day(self, feed, line, service, route, horarios, day): # check if we even have service if horarios is None or len(horarios) == 0: return if isinstance(route, Line): # recurse into "Ida" and "Volta" routes for sub_route in route.get_itineraries(): sub_route.duration = route.duration self.add_trips_by_day(feed, line, service, sub_route, horarios, day) return # have at least two stops if len(route.stops) < 2: sys.stderr.write("Skipping Route, has no stops: " + str(route) + "\n") return # check if we have a match for the first stop key = self.match_first_stops(route, horarios.keys()) if key is None: # Do not print debug output here, because already done in route.match_first_stops() return if route.route_id == DEBUG_ROUTE: print "\n\n\n" + str(route) print day + " - " + key # get shape id shape_id = str(route.route_id) try: feed.GetShape(shape_id) except KeyError: shape = transitfeed.Shape(shape_id) for point in route.shape: shape.AddPoint(lat=float(point["lat"]), lon=float(point["lon"])) feed.AddShapeObject(shape) if len(horarios) > 1 and route.line is None: sys.stderr.write( "Route should have a master: [" + route.route_id + "] " + str( route.osm_url) + "\n") for time_group in horarios[key]: for time_point in time_group: # parse first departure time start_time = datetime.strptime(time_point[0], "%H:%M") start_time = str(start_time.time()) # calculate last arrival time for GTFS start_sec = transitfeed.TimeToSecondsSinceMidnight(start_time) factor = 1 if len(horarios) > 1 and route.line is None: # since this route has only one instead of two trips, double the duration factor = 2 end_sec = start_sec + route.duration.seconds * factor end_time = transitfeed.FormatSecondsSinceMidnight(end_sec) # TODO handle options # opts = time_point[1] trip = line.AddTrip(feed, headsign=route.name, service_period=service) # add empty attributes to make navitia happy trip.block_id = "" trip.wheelchair_accessible = "" trip.bikes_allowed = "" trip.shape_id = shape_id trip.direction_id = "" if route.route_id == DEBUG_ROUTE: print "ADD TRIP " + str(trip.trip_id) + ":" self.add_trip_stops(feed, trip, route, start_time, end_time) # interpolate times, because Navitia can not handle this itself Helper.interpolate_stop_times(trip)
def add_trips_to_feed(self, feed, data): transport_hours = transporthours.main.Main() default_hours = transport_hours.tagsToGtfs(self._DEFAULT_SCHEDULE) default_service_period = self._init_service_period( feed, default_hours[0]) feed.SetDefaultServicePeriod(default_service_period) default_hours_dict = self._group_hours_by_service_period( feed, default_hours) lines = data.routes default_agency = feed.GetDefaultAgency() for route_id, line in sorted(lines.iteritems()): if not isinstance(line, Line): continue logging.info("Generating schedule for line: %s", route_id) if 'network' in line.tags and line.tags['network']: try: agency = feed.GetAgency(line.tags['network']) except KeyError: agency = feed.AddAgency(line.tags['network'], default_agency.agency_url, default_agency.agency_timezone, agency_id=line.tags['network']) logging.info("Added agency: %s", agency.agency_name) if not agency.Validate(): logging.error("Agency data not valid for %s in line", line.tags['network']) if 'operator:website' in line.tags and line.tags[ 'operator:website']: agency.agency_url = line.tags['operator:website'] if not agency.Validate(): logging.error('Url is not valid for agency: %s', agency.agency_url) else: agency = default_agency line_gtfs = feed.AddRoute(short_name=str(line.route_id), long_name=line.name, route_type=line.route_type, route_id=line.osm_id) line_gtfs.agency_id = agency.agency_id line_gtfs.route_desc = "" line_gtfs.route_color = "1779c2" line_gtfs.route_text_color = "ffffff" route_index = 0 itineraries = line.get_itineraries() line_hours_list = transport_hours.tagsToGtfs(line.tags) line_hours_dict = self._group_hours_by_service_period( feed, line_hours_list) for a_route in itineraries: itinerary_hours_list = transport_hours.tagsToGtfs(a_route.tags) if itinerary_hours_list: itinerary_hours_dict = self._group_hours_by_service_period( feed, itinerary_hours_list) elif line_hours_dict: itinerary_hours_dict = line_hours_dict else: itinerary_hours_dict = default_hours_dict logging.warning("schedule is missing, using default") logging.warning( " Add opening_hours & interval tags in OSM - %s", line.osm_url) for service_id, itinerary_hours in itinerary_hours_dict.items( ): service_period = feed.GetServicePeriod(service_id) trip_gtfs = line_gtfs.AddTrip( feed, service_period=service_period) trip_gtfs.shape_id = self._add_shape_to_feed( feed, a_route.osm_id, a_route) trip_gtfs.direction_id = route_index % 2 route_index += 1 if a_route.fr and a_route.to: trip_gtfs.trip_headsign = a_route.to if line_gtfs.route_short_name: # The line.name in the OSM data (route_long_name in the GTFS) # is in the following format: # '{transport mode} {route_short_name if any} : # {A terminus} ↔ {The other terminus}' # But it is good practice to not repeat the route_short_name # in the route_long_name, # so we abridge the route_long_name here if needed line_gtfs.route_long_name = a_route.fr + \ " ↔ ".decode('utf-8') + a_route.to for itinerary_hour in itinerary_hours: trip_gtfs.AddFrequency(itinerary_hour['start_time'], itinerary_hour['end_time'], itinerary_hour['headway']) if 'duration' in a_route.tags: try: travel_time = int(a_route.tags['duration']) if not travel_time > 0: logging.warning( "trip duration %s is invalid - %s", travel_time, a_route.osm_url) travel_time = self._DEFAULT_TRIP_DURATION except (ValueError, TypeError) as e: logging.warning( "trip duration %s is not a number - %s", a_route.tags['duration'], a_route.osm_url) travel_time = self._DEFAULT_TRIP_DURATION else: travel_time = self._DEFAULT_TRIP_DURATION logging.warning( "trip duration is missing, using default (%s min)", travel_time) logging.warning(" Add a duration tag in OSM - %s", a_route.osm_url) for index_stop, a_stop in enumerate(a_route.stops): stop_id = a_stop departure_time = datetime(2008, 11, 22, 6, 0, 0) if index_stop == 0: trip_gtfs.AddStopTime( feed.GetStop(str(stop_id)), stop_time=departure_time.strftime("%H:%M:%S")) elif index_stop == len(a_route.stops) - 1: departure_time += timedelta(minutes=travel_time) trip_gtfs.AddStopTime( feed.GetStop(str(stop_id)), stop_time=departure_time.strftime("%H:%M:%S")) else: trip_gtfs.AddStopTime(feed.GetStop(str(stop_id))) for secs, stop_time, is_timepoint in trip_gtfs.GetTimeInterpolatedStops( ): if not is_timepoint: stop_time.arrival_secs = secs stop_time.departure_secs = secs trip_gtfs.ReplaceStopTimeObject(stop_time) Helper.interpolate_stop_times(trip_gtfs)
def _find_best_name_for_unnamed_stop(self, stop): """Define name for stop without explicit name based on sourroundings """ api = overpy.Overpass() result = api.query(""" <osm-script> <query type="way"> <around lat="%s" lon="%s" radius="50.0"/> <has-kv k="name" /> <has-kv modv="not" k="highway" v="trunk"/> <has-kv modv="not" k="highway" v="primary"/> <has-kv modv="not" k="highway" v="secondary"/> <has-kv modv="not" k="amenity" v="bus_station"/> </query> <print order="quadtile"/> <query type="node"> <around lat="%s" lon="%s" radius="50.0"/> <has-kv k="name"/> <has-kv modv="not" k="highway" v="bus_stop"/> </query> <print order="quadtile"/> </osm-script> """ % (stop.lat, stop.lon, stop.lat, stop.lon)) candidates = [] # get all node candidates for node in result.get_nodes(): if 'name' in node.tags and node.tags["name"] is not None: candidates.append(node) # get way node candidates for way in result.get_ways(): if 'name' in way.tags and way.tags["name"] is not None: candidates.append(way) # leave if no candidates if len(candidates) == 0: # give stop a different name, so we won't search again without # refreshing data stop.name = self.stop_no_name return # find closest candidate winner = None winner_distance = sys.maxint for candidate in candidates: if isinstance(candidate, overpy.Way): lat, lon = Helper.get_center_of_nodes( candidate.get_nodes(resolve_missing=True)) distance = util.ApproximateDistance(lat, lon, stop.lat, stop.lon) else: distance = util.ApproximateDistance(candidate.lat, candidate.lon, stop.lat, stop.lon) if distance < winner_distance: winner = candidate winner_distance = distance # take name from winner stop.name = winner.tags["name"]
def _build_station(self, stop_area, osm_type): """Helper function to build Station objects from stop_areas The function creates a Station object for the stop_area flagged as location_type = 1. This means station, that can group stops. The members of this relation add this station their parent. Returns a initiated Station object from raw data """ # Check relation to be a station or used differently if 'route' in stop_area.tags: return None else: # Check tagging whether this is a stop area. if 'public_transport' not in stop_area.tags: logging.warning( "Potential station has no public_transport tag.") logging.warning(" Please fix on OSM: https://osm.org/%s/%s", osm_type, stop_area.id) return None elif stop_area.tags['public_transport'] != 'stop_area': logging.warning( "Warning: Potential station is not tagged as stop_area.") logging.warning(" Please fix on OSM: https://osm.org/%s/%s", osm_type, stop_area.id) return None # Analzyse member objects (stops) of this stop area members = {} for member in stop_area.members: if member.role == "platform": if isinstance(member, overpy.RelationNode): member_osm_type = "node" elif isinstance(member, overpy.RelationWay): member_osm_type = "way" identifier = member_osm_type + "/" + str(member.ref) if identifier in self.stops['regular']: # Collect the Stop objects that are members # of this Station members[identifier] = self.stops['regular'][identifier] else: logging.error("Station member was not found in data") logging.error(" https://osm.org/relation/%s", stop_area.id) logging.error(" https://osm.org/node/%s", member.ref) if len(members) < 1: # Stop areas with only one stop, are not stations they just # group different elements of one stop together. logging.error("Station with no members has been discarted:") logging.error(" https://osm.org/relation/%s", stop_area.id) return None elif len(members) == 1: logging.warning( "OSM stop area has only one platform and can't be used as a GTFS station:" ) logging.warning(" https://osm.org/relation/%s", stop_area.id) return None # Check name of stop area if 'name' not in stop_area.tags: logging.warning( "Stop area without name. Please fix in OpenStreetMap:") logging.warning(" https://osm.org/relation/%s", stop_area.id) stop_area.name = self.stop_no_name else: stop_area.name = stop_area.tags["name"] # Calculate coordinates for stop area based on the center of it's # members stop_area.lat, stop_area.lon = Helper.get_center_of_nodes( members.values()) # Move to Elements class, once attributes with defaults play well # with inheritance https://github.com/python-attrs/attrs/issues/38 osm_url = "https://osm.org/" + str(osm_type) + "/" + str(stop_area.id) # Create and return Station object station = Station(osm_id=stop_area.id, osm_type=osm_type, osm_url=osm_url, tags=stop_area.tags, name=stop_area.name, lat=stop_area.lat, lon=stop_area.lon) station.set_members(members) logging.info( "Stop area (OSM) has been used to create a station (GTFS):\n") logging.info(" https://osm.org/relation/%s\n", str(stop_area.id)) return station
def add_trips_to_feed(self, feed, data): self.service_weekday = feed.GetDefaultServicePeriod() self.service_weekday.SetStartDate( self.config['feed_info']['start_date']) self.service_weekday.SetEndDate(self.config['feed_info']['end_date']) self.service_weekday.SetWeekdayService(True) self.service_weekday.SetWeekendService(True) lines = data.routes for route_ref, line in sorted(lines.iteritems()): if not isinstance(line, Line): continue print("Generating schedule for line: " + route_ref) line_gtfs = feed.AddRoute( short_name=str(line.route_id), long_name=line.name, # we change the route_long_name with the 'from' and 'to' tags # of the last route as the route_master name tag contains # the line code (route_short_name) route_type="Bus", route_id=line.osm_id) line_gtfs.agency_id = feed.GetDefaultAgency().agency_id line_gtfs.route_desc = "" line_gtfs.route_color = "1779c2" line_gtfs.route_text_color = "ffffff" route_index = 0 itineraries = line.get_itineraries() for a_route in itineraries: trip_gtfs = line_gtfs.AddTrip(feed) trip_gtfs.shape_id = self._add_shape_to_feed( feed, a_route.osm_id, a_route) trip_gtfs.direction_id = route_index % 2 route_index += 1 if a_route.fr and a_route.to: trip_gtfs.trip_headsign = a_route.to line_gtfs.route_long_name = a_route.fr.decode( 'utf8') + " ↔ ".decode( 'utf8') + a_route.to.decode('utf8') DEFAULT_ROUTE_FREQUENCY = 30 DEFAULT_TRAVEL_TIME = 120 frequency = None if "frequency" in line.tags: frequency = line.tags['frequency'] try: ROUTE_FREQUENCY = int(frequency) if not ROUTE_FREQUENCY > 0: print("frequency is invalid for route_master " + str( line.osm_id)) ROUTE_FREQUENCY = DEFAULT_ROUTE_FREQUENCY except (ValueError, TypeError) as e: print("frequency not a number for route_master " + str( line.osm_id)) ROUTE_FREQUENCY = DEFAULT_ROUTE_FREQUENCY trip_gtfs.AddFrequency( "05:00:00", "22:00:00", ROUTE_FREQUENCY * 60) if 'travel_time' in a_route.tags: try: TRAVEL_TIME = int(a_route.tags['travel_time']) if not TRAVEL_TIME > 0: print("travel_time is invalid for route " + str( a_route.osm_id)) TRAVEL_TIME = DEFAULT_TRAVEL_TIME except (ValueError, TypeError) as e: print("travel_time not a number for route " + str( a_route.osm_id)) TRAVEL_TIME = DEFAULT_TRAVEL_TIME else: TRAVEL_TIME = DEFAULT_TRAVEL_TIME for index_stop, a_stop in enumerate(a_route.stops): stop_id = a_stop.split('/')[-1] departure_time = datetime(2008, 11, 22, 6, 0, 0) if index_stop == 0: trip_gtfs.AddStopTime(feed.GetStop( str(stop_id)), stop_time=departure_time.strftime( "%H:%M:%S")) elif index_stop == len(a_route.stops) - 1: departure_time += timedelta(minutes=TRAVEL_TIME) trip_gtfs.AddStopTime(feed.GetStop( str(stop_id)), stop_time=departure_time.strftime( "%H:%M:%S")) else: trip_gtfs.AddStopTime(feed.GetStop(str(stop_id))) for secs, stop_time, is_timepoint in trip_gtfs.GetTimeInterpolatedStops(): if not is_timepoint: stop_time.arrival_secs = secs stop_time.departure_secs = secs trip_gtfs.ReplaceStopTimeObject(stop_time) Helper.interpolate_stop_times(trip_gtfs)
def _add_itinerary_trips(self, feed, itinerary, line, trip_builder, shape_id): """ Add all trips of an itinerary to the GTFS feed. """ # Obtain GTFS route to add trips to it. route = feed.GetRoute(line.route_id) trips_count = 0 # Loop through each timeslot for a trip for trip in trip_builder['schedule']: gtfs_trip = route.AddTrip( feed, headsign=itinerary.to, service_period=trip_builder['service_period']) trips_count += 1 search_idx = 0 # Go through all stops of an itinerary for itinerary_stop_idx, itinerary_stop_id in enumerate( itinerary.get_stops()): # Load full stop object try: itinerary_stop = trip_builder['all_stops']['regular'][ itinerary_stop_id] except ValueError: logging.warning("Itinerary (%s) misses a stop:", itinerary.route_url) logging.warning(" Please review: %s", itinerary_stop_id) continue try: # Load respective GTFS stop object gtfs_stop = feed.GetStop(str(itinerary_stop.stop_id)) except ValueError: logging.warning("Stop in itinerary was not found in GTFS.") logging.warning(" %s", itinerary_stop.osm_url) continue # Make sure we compare same unicode encoding if type(itinerary_stop.name) is str: itinerary_stop.name = itinerary_stop.name.decode('utf-8') schedule_stop_idx = -1 # Check if we have specific time information for this stop. try: schedule_stop_idx = trip_builder['stops'].index( itinerary_stop.name, search_idx) except ValueError: if itinerary_stop.get_parent_station() is not None: # If stop name not found, check for the parent_station name, too. itinerary_station = trip_builder['all_stops'][ 'stations'][str( itinerary_stop.get_parent_station())] if type(itinerary_station.name) is str: itinerary_station.name = itinerary_station.name.decode( 'utf-8') try: schedule_stop_idx = trip_builder['stops'].index( itinerary_station.name, search_idx) except ValueError: pass # Make sure the last stop of itinerary will keep being the last stop in GTFS last_stop_schedule = schedule_stop_idx == len( trip_builder['stops']) - 1 last_stop_itinerary = itinerary_stop_idx == len( itinerary.get_stops()) - 1 if last_stop_schedule != last_stop_itinerary: schedule_stop_idx = -1 if schedule_stop_idx != -1: time = trip[schedule_stop_idx] search_idx = schedule_stop_idx + 1 # Validate time information try: time_at_stop = str( datetime.strptime(time, "%H:%M").time()) except ValueError: logging.warning( 'Time "%s" for the stop was not valid:', time) logging.warning(" %s - %s", itinerary_stop.name, itinerary_stop.osm_url) break gtfs_trip.AddStopTime(gtfs_stop, stop_time=time_at_stop) # Add stop without time information, too (we interpolate later) else: try: gtfs_trip.AddStopTime(gtfs_stop) except transitfeed.problems.OtherProblem: logging.warning( "Could not add first stop to trip without time information." ) logging.warning(" %s - %s", itinerary_stop.name, itinerary_stop.osm_url) break # Add reference to shape gtfs_trip.shape_id = shape_id # Add empty attributes to make navitia happy gtfs_trip.block_id = "" gtfs_trip.wheelchair_accessible = "" gtfs_trip.bikes_allowed = "" gtfs_trip.direction_id = "" # Calculate all times of stops, which were added with no time Helper.interpolate_stop_times(gtfs_trip) return trips_count
def _add_itinerary_trips(self, feed, itinerary, line, trip_builder, shape_id): """ Add all trips of an itinerary to the GTFS feed. """ # Obtain GTFS route to add trips to it. route = feed.GetRoute(line.route_id) trips_count = 0 # Loop through each timeslot for a trip for trip in trip_builder['schedule']: gtfs_trip = route.AddTrip( feed, headsign=itinerary.to, service_period=trip_builder['service_period']) trips_count += 1 # Go through all stops of an itinerary for itinerary_stop_id in itinerary.get_stops(): # Load full stop object try: itinerary_stop = trip_builder['all_stops']['regular'][ itinerary_stop_id] except ValueError: sys.stderr.write("Itinerary (" + itinerary.route_url + ") misses a stop: \n") sys.stderr.write("Please review: " + itinerary_stop_id + "\n") continue try: # Load respective GTFS stop object gtfs_stop = feed.GetStop(str(itinerary_stop.stop_id)) except ValueError: print("Warning: Stop in itinerary was not found in GTFS.") print(" " + itinerary_stop.osm_url) # Make sure we compare same unicode encoding if type(itinerary_stop.name) is str: itinerary_stop.name = itinerary_stop.name.decode('utf-8') time = "-" # Check if we have specific time information for this stop. try: time = trip[trip_builder['stops'].index( itinerary_stop.name)] except ValueError: pass # Validate time information if time != "-": try: time_at_stop = str( datetime.strptime(time, "%H:%M").time()) except ValueError: print('Warning: Time "' + time + '" for the stop was not valid:') print(" " + itinerary_stop.name + " - " + itinerary_stop.osm_url) break gtfs_trip.AddStopTime(gtfs_stop, stop_time=time_at_stop) # Add stop without time information, too (we interpolate later) else: try: gtfs_trip.AddStopTime(gtfs_stop) except ValueError: print("Warning: Could not add first a stop to trip.") print(" " + itinerary_stop.name + " - " + itinerary_stop.osm_id) break # Add reference to shape gtfs_trip.shape_id = shape_id # Add empty attributes to make navitia happy gtfs_trip.block_id = "" gtfs_trip.wheelchair_accessible = "" gtfs_trip.bikes_allowed = "" gtfs_trip.direction_id = "" # Calculate all times of stops, which were added with no time Helper.interpolate_stop_times(gtfs_trip) return trips_count