<s> from __future__ import division <EOL> import busbus <EOL> import busbus . entity <EOL> from busbus . queryable import Queryable <EOL> from busbus import util <EOL> from busbus . util . arrivals import ArrivalQueryable , ArrivalGeneratorBase <EOL> from busbus . util . csv import CSVReader <EOL> import apsw <EOL> import arrow <EOL> import collections <EOL> import datetime <EOL> import hashlib <EOL> import heapq <EOL> import itertools <EOL> import operator <EOL> import os <EOL> import phonenumbers <EOL> from pkg_resources import resource_string <EOL> import six <EOL> import zipfile <EOL> SCHEMA_USER_VERSION = <NUM_LIT> <EOL> def parse_gtfs_time ( timestr ) : <EOL> """<STR_LIT>""" <EOL> split = timestr . split ( '<STR_LIT::>' ) <EOL> seconds = int ( split [ - <NUM_LIT:1> ] ) <EOL> minutes = int ( split [ - <NUM_LIT:2> ] ) if len ( split ) > <NUM_LIT:1> else <NUM_LIT:0> <EOL> hours = int ( split [ - <NUM_LIT:3> ] ) if len ( split ) > <NUM_LIT:2> else <NUM_LIT:0> <EOL> return ( hours - <NUM_LIT:12> ) * <NUM_LIT> + minutes * <NUM_LIT> + seconds <EOL> def date_to_sql_string ( datestr ) : <EOL> return '<STR_LIT:->' . join ( ( datestr [ : <NUM_LIT:4> ] , datestr [ <NUM_LIT:4> : <NUM_LIT:6> ] , datestr [ <NUM_LIT:6> : ] ) ) <EOL> FIX_TYPE_MAP = { <EOL> '<STR_LIT:date>' : date_to_sql_string , <EOL> '<STR_LIT>' : parse_gtfs_time , <EOL> '<STR_LIT>' : int , <EOL> '<STR_LIT>' : float , <EOL> '<STR_LIT>' : int , <EOL> '<STR_LIT:text>' : lambda s : s , <EOL> } <EOL> class SQLEntityMixin ( object ) : <EOL> def __eq__ ( self , other ) : <EOL> if not isinstance ( other , SQLEntityMixin ) : <EOL> return False <EOL> return ( self . id == getattr ( other , '<STR_LIT:id>' , not self . id ) and <EOL> self . provider == getattr ( other , '<STR_LIT>' , not self . provider ) ) <EOL> @ classmethod <EOL> def _build_select ( cls , columns , named_params = False ) : <EOL> query = '<STR_LIT>' . format ( <EOL> '<STR_LIT:U+002CU+0020>' . join ( '<STR_LIT>' . format ( k , v ) <EOL> for k , v in cls . __field_map__ . items ( ) ) , <EOL> cls . __table__ ) <EOL> if columns : <EOL> if named_params : <EOL> query += '<STR_LIT>' . format ( <EOL> '<STR_LIT>' . join ( '<STR_LIT>' . format ( c ) for c in columns ) ) <EOL> else : <EOL> query += '<STR_LIT>' . format ( <EOL> '<STR_LIT>' . join ( '<STR_LIT>' . format ( c ) for c in columns ) ) <EOL> return query <EOL> def _query ( self , ** kwargs ) : <EOL> return self . provider . _query ( self . __class__ , ** kwargs ) <EOL> @ classmethod <EOL> def from_id ( cls , provider , id , default = None ) : <EOL> """<STR_LIT>""" <EOL> id_field = cls . __field_map__ [ '<STR_LIT:id>' ] <EOL> result = provider . _query ( cls , ** { id_field : id } ) . fetchone ( ) <EOL> if result is None : <EOL> return default <EOL> else : <EOL> return cls ( provider , ** dict ( result ) ) <EOL> class GTFSAgency ( SQLEntityMixin , busbus . Agency ) : <EOL> __table__ = '<STR_LIT>' <EOL> __field_map__ = { <EOL> '<STR_LIT:id>' : '<STR_LIT>' , <EOL> '<STR_LIT:name>' : '<STR_LIT>' , <EOL> '<STR_LIT:url>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> } <EOL> def __init__ ( self , provider , ** data ) : <EOL> if data . get ( '<STR_LIT>' ) : <EOL> data [ '<STR_LIT>' ] = data [ '<STR_LIT>' ] . lower ( ) <EOL> if data . get ( '<STR_LIT>' ) and getattr ( provider , '<STR_LIT>' ) : <EOL> phone = phonenumbers . parse ( data [ '<STR_LIT>' ] , provider . country ) <EOL> data [ '<STR_LIT>' ] = phonenumbers . format_number ( <EOL> phone , phonenumbers . PhoneNumberFormat . E164 ) <EOL> super ( GTFSAgency , self ) . __init__ ( provider , ** data ) <EOL> class GTFSStop ( SQLEntityMixin , busbus . Stop ) : <EOL> __table__ = '<STR_LIT>' <EOL> __field_map__ = { <EOL> '<STR_LIT:id>' : '<STR_LIT>' , <EOL> '<STR_LIT:code>' : '<STR_LIT>' , <EOL> '<STR_LIT:name>' : '<STR_LIT>' , <EOL> '<STR_LIT:description>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT:url>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> } <EOL> def __init__ ( self , provider , ** data ) : <EOL> if data . get ( '<STR_LIT>' ) : <EOL> data [ '<STR_LIT>' ] = busbus . entity . LazyEntityProperty ( <EOL> provider . get , busbus . Stop , data [ '<STR_LIT>' ] ) <EOL> if not data . get ( '<STR_LIT>' ) : <EOL> data [ '<STR_LIT>' ] = provider . _timezone <EOL> if '<STR_LIT>' in data : <EOL> pass <EOL> super ( GTFSStop , self ) . __init__ ( provider , ** data ) <EOL> @ property <EOL> def routes ( self ) : <EOL> result = self . provider . conn . cursor ( ) . execute ( <EOL> '''<STR_LIT>''' , <EOL> ( self . id , self . provider . feed_id ) ) <EOL> return Queryable ( self . provider . get ( busbus . Route , row [ '<STR_LIT>' ] ) <EOL> for row in result ) <EOL> @ property <EOL> def children ( self ) : <EOL> result = self . _query ( parent_station = self . id ) <EOL> return Queryable ( GTFSStop ( self . provider , ** dict ( row ) ) <EOL> for row in result ) <EOL> class GTFSRoute ( SQLEntityMixin , busbus . Route ) : <EOL> __table__ = '<STR_LIT>' <EOL> __field_map__ = { <EOL> '<STR_LIT:id>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT:name>' : '<STR_LIT>' , <EOL> '<STR_LIT:description>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT:url>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> } <EOL> def __init__ ( self , provider , ** data ) : <EOL> if '<STR_LIT>' in data : <EOL> data [ '<STR_LIT>' ] = busbus . entity . LazyEntityProperty ( <EOL> provider . get , busbus . Agency , data [ '<STR_LIT>' ] ) <EOL> if '<STR_LIT>' in data : <EOL> pass <EOL> if data . get ( '<STR_LIT:name>' ) is None : <EOL> data [ '<STR_LIT:name>' ] = data . pop ( '<STR_LIT>' ) <EOL> super ( GTFSRoute , self ) . __init__ ( provider , ** data ) <EOL> @ property <EOL> def stops ( self ) : <EOL> result = self . provider . conn . cursor ( ) . execute ( <EOL> '''<STR_LIT>''' , <EOL> ( self . id , self . provider . feed_id ) ) <EOL> return Queryable ( self . provider . get ( busbus . Stop , row [ '<STR_LIT>' ] ) <EOL> for row in result ) <EOL> @ property <EOL> def directions ( self ) : <EOL> hashes = [ ] <EOL> t_query = """<STR_LIT>""" <EOL> t_filter = { '<STR_LIT>' : self . id , '<STR_LIT>' : self . provider . feed_id } <EOL> cur = self . provider . conn . cursor ( ) <EOL> for trip in cur . execute ( t_query , t_filter ) : <EOL> direction = { } <EOL> innercur = self . provider . conn . cursor ( ) <EOL> result = innercur . execute ( <EOL> """<STR_LIT>""" , <EOL> { '<STR_LIT>' : trip [ '<STR_LIT>' ] , '<STR_LIT>' : self . provider . feed_id } ) <EOL> direction [ '<STR_LIT>' ] = [ GTFSStop ( self . provider , ** dict ( row ) ) <EOL> for row in result ] <EOL> if trip [ '<STR_LIT>' ] is not None : <EOL> direction [ '<STR_LIT>' ] = trip [ '<STR_LIT>' ] <EOL> if trip [ '<STR_LIT>' ] is not None : <EOL> direction [ '<STR_LIT>' ] = trip [ '<STR_LIT>' ] <EOL> if trip [ '<STR_LIT>' ] is not None : <EOL> direction [ '<STR_LIT>' ] = trip [ '<STR_LIT>' ] <EOL> h = util . freezehash ( direction ) <EOL> if h not in hashes : <EOL> hashes . append ( h ) <EOL> yield direction <EOL> class GTFSArrivalGenerator ( ArrivalGeneratorBase ) : <EOL> realtime = False <EOL> def __init__ ( self , provider , stops , routes , start , end ) : <EOL> super ( GTFSArrivalGenerator , self ) . __init__ ( provider , stops , routes , <EOL> start , end ) <EOL> if self . stops is None : <EOL> if self . routes is None : <EOL> self . stops = self . provider . stops <EOL> self . routes = self . provider . routes <EOL> else : <EOL> stops_dict = { } <EOL> for route in self . routes : <EOL> for stop in route . stops : <EOL> stops_dict [ stop . id ] = stop <EOL> self . stops = stops_dict . values ( ) <EOL> else : <EOL> if self . routes is None : <EOL> routes_dict = { } <EOL> for stop in self . stops : <EOL> for route in stop . routes : <EOL> routes_dict [ route . id ] = route <EOL> self . routes = routes_dict . values ( ) <EOL> self . service_cache = { } <EOL> self . freq_cache = { } <EOL> self . it = None <EOL> def _stop_times ( self , stop , route ) : <EOL> return self . provider . conn . cursor ( ) . execute ( <EOL> '''<STR_LIT>''' , <EOL> { '<STR_LIT>' : stop . id , '<STR_LIT>' : route . id , <EOL> '<STR_LIT>' : self . provider . feed_id } ) <EOL> def _build_iterable ( self ) : <EOL> iters = [ ] <EOL> stops = busbus . Stop . add_children ( self . stops ) <EOL> for stop , route in itertools . product ( stops , self . routes ) : <EOL> for stop_time in self . _stop_times ( stop , route ) : <EOL> iters . append ( self . _build_arrivals ( stop , route , stop_time ) ) <EOL> return heapq . merge ( * iters ) <EOL> def _build_arrivals ( self , stop , route , stop_time ) : <EOL> def build_arr ( day , offset = None ) : <EOL> if offset is None : <EOL> offset = datetime . timedelta ( ) <EOL> time = day + datetime . timedelta ( seconds = stop_time [ '<STR_LIT>' ] ) + offset <EOL> if not ( self . start <= time <= self . end ) : <EOL> return <EOL> dep = ( day + stop_time [ '<STR_LIT>' ] + offset if <EOL> stop_time [ '<STR_LIT>' ] else None ) <EOL> bikes_ok = { <NUM_LIT:1> : True , <NUM_LIT:2> : False } . get ( stop_time [ '<STR_LIT>' ] ) <EOL> return busbus . Arrival ( self . provider , stop = stop , route = route , <EOL> time = time , departure_time = dep , <EOL> headsign = stop_time [ '<STR_LIT>' ] , <EOL> short_name = stop_time [ '<STR_LIT>' ] , <EOL> bikes_ok = bikes_ok , realtime = False ) <EOL> days = filter ( self . _valid_date_filter ( stop_time [ '<STR_LIT>' ] ) , <EOL> arrow . Arrow . range ( '<STR_LIT>' , self . start . floor ( '<STR_LIT>' ) , <EOL> self . end . ceil ( '<STR_LIT>' ) ) ) <EOL> freqs = self . _frequencies ( stop_time [ '<STR_LIT>' ] ) <EOL> trip_start = stop_time [ '<STR_LIT>' ] <EOL> for day in days : <EOL> day = day . replace ( hours = <NUM_LIT:12> ) <EOL> for freq in freqs : <EOL> freq_start = day + freq [ '<STR_LIT>' ] <EOL> freq_end = day + freq [ '<STR_LIT>' ] <EOL> rel_time = freq_start - ( day + trip_start ) <EOL> offset = datetime . timedelta ( ) <EOL> while freq_start + offset <= freq_end : <EOL> arrival = build_arr ( day , offset + rel_time ) <EOL> if arrival : <EOL> yield arrival <EOL> offset += freq [ '<STR_LIT>' ] <EOL> if not freqs : <EOL> arrival = build_arr ( day ) <EOL> if arrival : <EOL> yield arrival <EOL> def _valid_date_filter ( self , service_id ) : <EOL> def valid_date ( day ) : <EOL> serv = self . _service ( service_id ) <EOL> weekday = day . format ( '<STR_LIT>' ) . lower ( ) <EOL> day = day . date ( ) <EOL> return ( ( serv [ '<STR_LIT>' ] <= day <= serv [ '<STR_LIT>' ] ) and <EOL> ( serv [ '<STR_LIT>' ] . get ( day , <NUM_LIT:0> ) != <NUM_LIT:2> ) and <EOL> ( serv [ weekday ] or serv [ '<STR_LIT>' ] . get ( day , <NUM_LIT:0> ) == <NUM_LIT:1> ) ) <EOL> return valid_date <EOL> def _frequencies ( self , trip_id ) : <EOL> if trip_id not in self . freq_cache : <EOL> query = """<STR_LIT>""" <EOL> filter = { '<STR_LIT>' : trip_id , '<STR_LIT>' : self . provider . feed_id } <EOL> cur = self . provider . conn . cursor ( ) <EOL> self . freq_cache [ trip_id ] = cur . execute ( query , filter ) . fetchall ( ) <EOL> return self . freq_cache [ trip_id ] <EOL> def _service ( self , id ) : <EOL> if id not in self . service_cache : <EOL> c_query = """<STR_LIT>""" <EOL> c_filter = { '<STR_LIT>' : id , '<STR_LIT>' : self . provider . feed_id } <EOL> cur = self . provider . conn . cursor ( ) <EOL> self . service_cache [ id ] = dict ( next ( cur . execute ( c_query , c_filter ) ) ) <EOL> cd_query = """<STR_LIT>""" <EOL> cd_result = cur . execute ( cd_query , c_filter ) <EOL> self . service_cache [ id ] [ '<STR_LIT>' ] = { r [ '<STR_LIT:date>' ] : r [ '<STR_LIT:e>' ] <EOL> for r in cd_result } <EOL> return self . service_cache [ id ] <EOL> def gtfs_row_tracer ( cur , row ) : <EOL> type_map = { <EOL> '<STR_LIT:date>' : lambda s : datetime . date ( int ( s [ : <NUM_LIT:4> ] ) , int ( s [ <NUM_LIT:5> : <NUM_LIT:7> ] ) , int ( s [ <NUM_LIT:8> : ] ) ) , <EOL> '<STR_LIT>' : lambda i : datetime . timedelta ( seconds = i ) , <EOL> '<STR_LIT>' : lambda i : datetime . timedelta ( seconds = i ) , <EOL> } <EOL> desc = cur . getdescription ( ) <EOL> return { desc [ i ] [ <NUM_LIT:0> ] : ( type_map . get ( desc [ i ] [ <NUM_LIT:1> ] , lambda s : s ) ( x ) <EOL> if row [ i ] is not None else None ) <EOL> for i , x in enumerate ( row ) } <EOL> class GTFSMixin ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , engine , gtfs_url ) : <EOL> super ( GTFSMixin , self ) . __init__ ( engine ) <EOL> if isinstance ( self . engine . config [ '<STR_LIT>' ] , apsw . Connection ) : <EOL> self . conn = self . engine . config [ '<STR_LIT>' ] <EOL> else : <EOL> self . conn = apsw . Connection ( self . engine . config [ '<STR_LIT>' ] ) <EOL> self . conn . setrowtrace ( gtfs_row_tracer ) <EOL> cur = self . conn . cursor ( ) <EOL> version = next ( cur . execute ( '<STR_LIT>' ) ) [ '<STR_LIT>' ] <EOL> if version == <NUM_LIT:0> : <EOL> script = resource_string ( <EOL> __name__ , '<STR_LIT>' . format ( SCHEMA_USER_VERSION ) ) <EOL> if isinstance ( script , six . binary_type ) : <EOL> script = script . decode ( '<STR_LIT:utf-8>' ) <EOL> cur . execute ( script ) <EOL> elif version < SCHEMA_USER_VERSION : <EOL> raise NotImplementedError ( ) <EOL> elif version > SCHEMA_USER_VERSION : <EOL> raise RuntimeError ( '<STR_LIT>' <EOL> '<STR_LIT>' . format ( version , SCHEMA_USER_VERSION ) ) <EOL> tables = [ r [ '<STR_LIT:name>' ] for r in cur . execute ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> if not r [ '<STR_LIT:name>' ] . startswith ( '<STR_LIT:_>' ) ] <EOL> if isinstance ( gtfs_url , six . binary_type ) : <EOL> gtfs_url = gtfs_url . decode ( '<STR_LIT:utf-8>' ) <EOL> resp = self . _cached_requests . get ( gtfs_url ) <EOL> zip = six . BytesIO ( resp . content ) . getvalue ( ) <EOL> hash = hashlib . sha256 ( zip ) . hexdigest ( ) <EOL> resp = [ x [ '<STR_LIT:id>' ] for x in cur . execute ( <EOL> '<STR_LIT>' , <EOL> ( gtfs_url , hash ) ) ] <EOL> if len ( resp ) == <NUM_LIT:1> : <EOL> self . feed_id = resp [ <NUM_LIT:0> ] <EOL> else : <EOL> cur . execute ( '<STR_LIT>' ) <EOL> old_ids = [ ( x [ '<STR_LIT:id>' ] , ) for x in cur . execute ( <EOL> '''<STR_LIT>''' , ( gtfs_url , ) ) ] <EOL> cur . executemany ( '<STR_LIT>' , old_ids ) <EOL> for table in tables : <EOL> cur . executemany ( '<STR_LIT>' . format ( table ) , <EOL> old_ids ) <EOL> cur . execute ( '<STR_LIT>' <EOL> '<STR_LIT>' , ( gtfs_url , hash ) ) <EOL> self . feed_id = self . conn . last_insert_rowid ( ) <EOL> with zipfile . ZipFile ( six . BytesIO ( zip ) ) as z : <EOL> for table in tables : <EOL> filename = table + '<STR_LIT>' <EOL> if filename not in z . namelist ( ) : <EOL> continue <EOL> with z . open ( filename ) as f : <EOL> data = CSVReader ( f ) <EOL> columns = [ ] <EOL> coldata = [ ] <EOL> for x in cur . execute ( <EOL> '<STR_LIT>' . format ( table ) ) : <EOL> if x [ '<STR_LIT:name>' ] in data . header : <EOL> columns . append ( x [ '<STR_LIT:name>' ] ) <EOL> coldata . append ( ( <EOL> x [ '<STR_LIT:type>' ] , data . header . index ( x [ '<STR_LIT:name>' ] ) ) ) <EOL> columns . append ( '<STR_LIT>' ) <EOL> stmt = ( '<STR_LIT>' <EOL> . format ( table , '<STR_LIT:U+002CU+0020>' . join ( columns ) , <EOL> '<STR_LIT:U+002CU+0020>' . join ( ( '<STR_LIT:?>' , ) * len ( columns ) ) ) ) <EOL> def row_gen ( row ) : <EOL> for t , idx in coldata : <EOL> if idx < len ( row ) and row [ idx ] is not None : <EOL> yield FIX_TYPE_MAP [ t ] ( row [ idx ] ) <EOL> else : <EOL> yield None <EOL> yield self . feed_id <EOL> cur . executemany ( stmt , ( row_gen ( row ) for row in data ) ) <EOL> cur . execute ( '<STR_LIT>' ) <EOL> cur . execute ( '<STR_LIT>' ) <EOL> for row in cur . execute ( <EOL> '''<STR_LIT>''' , <EOL> ( self . feed_id , ) ) : <EOL> innercur = self . conn . cursor ( ) <EOL> trip_id = row [ '<STR_LIT>' ] <EOL> known_times = { r [ '<STR_LIT>' ] : dict ( r ) for r in innercur . execute ( <EOL> '''<STR_LIT>''' , <EOL> { '<STR_LIT>' : trip_id , '<STR_LIT>' : self . feed_id } ) } <EOL> if not known_times : <EOL> continue <EOL> unknown_times = [ r [ '<STR_LIT>' ] for r in innercur . execute ( <EOL> '''<STR_LIT>''' , <EOL> { '<STR_LIT>' : trip_id , '<STR_LIT>' : self . feed_id } ) ] <EOL> for i , seq in enumerate ( unknown_times ) : <EOL> left = max ( filter ( lambda k : k < seq , known_times ) ) <EOL> right = min ( filter ( lambda k : k > seq , known_times ) ) <EOL> start = known_times [ left ] . get ( '<STR_LIT:d>' , known_times [ left ] [ '<STR_LIT:a>' ] ) <EOL> gap = known_times [ right ] [ '<STR_LIT:a>' ] - start <EOL> count = len ( list ( filter ( lambda k : left < k < right , <EOL> unknown_times ) ) ) + <NUM_LIT:1> <EOL> time = ( ( gap . total_seconds ( ) * ( i + <NUM_LIT:1> ) / count ) + <EOL> start . total_seconds ( ) ) <EOL> innercur . execute ( <EOL> '''<STR_LIT>''' , <EOL> { '<STR_LIT>' : trip_id , '<STR_LIT>' : self . feed_id , <EOL> '<STR_LIT:a>' : time , '<STR_LIT>' : seq } ) <EOL> min_time = innercur . execute ( <EOL> '''<STR_LIT>''' , <EOL> ( trip_id , self . feed_id ) ) . fetchone ( ) [ '<STR_LIT>' ] <EOL> innercur . execute ( '''<STR_LIT>''' , <EOL> ( min_time , trip_id , self . feed_id ) ) <EOL> cur . execute ( <EOL> '''<STR_LIT>''' , { '<STR_LIT>' : self . feed_id } ) <EOL> cur . execute ( '<STR_LIT>' ) <EOL> def _query ( self , cls , ** kwargs ) : <EOL> if '<STR_LIT>' not in kwargs : <EOL> kwargs [ '<STR_LIT>' ] = self . feed_id <EOL> cur = self . conn . cursor ( ) <EOL> return cur . execute ( cls . _build_select ( <EOL> kwargs . keys ( ) , named_params = True ) , kwargs ) <EOL> def _entity_builder ( self , cls , ** kwargs ) : <EOL> query = self . _query ( cls , ** kwargs ) <EOL> return Queryable ( cls ( self , ** row ) for row in query ) <EOL> def get ( self , cls , id , default = None ) : <EOL> typemap = { <EOL> busbus . Agency : GTFSAgency , <EOL> busbus . Stop : GTFSStop , <EOL> busbus . Route : GTFSRoute , <EOL> } <EOL> try : <EOL> cls = util . entity_type ( cls ) <EOL> except TypeError : <EOL> return default <EOL> if cls in typemap : <EOL> return typemap [ cls ] . from_id ( self , id , default ) <EOL> else : <EOL> return default <EOL> @ property <EOL> def _timezone ( self ) : <EOL> for agency in self . agencies : <EOL> if agency . timezone : <EOL> return agency . timezone <EOL> return None <EOL> @ property <EOL> def agencies ( self ) : <EOL> return self . _entity_builder ( GTFSAgency ) <EOL> @ property <EOL> def stops ( self ) : <EOL> return self . _entity_builder ( GTFSStop ) <EOL> @ property <EOL> def routes ( self ) : <EOL> return self . _entity_builder ( GTFSRoute ) <EOL> @ property <EOL> def arrivals ( self ) : <EOL> return ArrivalQueryable ( self , GTFSArrivalGenerator ) </s>
