#!/usr/bin/python2.5 |
#!/usr/bin/python2.5 |
|
|
# Copyright (C) 2007 Google Inc. |
# Copyright (C) 2007 Google Inc. |
# |
# |
# Licensed under the Apache License, Version 2.0 (the "License"); |
# Licensed under the Apache License, Version 2.0 (the "License"); |
# you may not use this file except in compliance with the License. |
# you may not use this file except in compliance with the License. |
# You may obtain a copy of the License at |
# You may obtain a copy of the License at |
# |
# |
# http://www.apache.org/licenses/LICENSE-2.0 |
# http://www.apache.org/licenses/LICENSE-2.0 |
# |
# |
# Unless required by applicable law or agreed to in writing, software |
# Unless required by applicable law or agreed to in writing, software |
# distributed under the License is distributed on an "AS IS" BASIS, |
# distributed under the License is distributed on an "AS IS" BASIS, |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
# See the License for the specific language governing permissions and |
# See the License for the specific language governing permissions and |
# limitations under the License. |
# limitations under the License. |
|
|
"""Google has a homegrown database for managing the company shuttle. The |
"""Google has a homegrown database for managing the company shuttle. The |
database dumps its contents in XML. This scripts converts the proprietary XML |
database dumps its contents in XML. This scripts converts the proprietary XML |
format into a Google Transit Feed Specification file. |
format into a Google Transit Feed Specification file. |
""" |
""" |
|
|
import datetime |
import datetime |
from optparse import OptionParser |
from optparse import OptionParser |
import os.path |
import os.path |
import re |
import re |
import transitfeed |
import transitfeed |
import urllib |
import urllib |
|
|
try: |
try: |
import xml.etree.ElementTree as ET # python 2.5 |
import xml.etree.ElementTree as ET # python 2.5 |
except ImportError, e: |
except ImportError, e: |
import elementtree.ElementTree as ET # older pythons |
import elementtree.ElementTree as ET # older pythons |
|
|
|
|
class NoUnusedStopExceptionProblemReporter( |
class NoUnusedStopExceptionProblemReporter(transitfeed.ProblemReporter): |
transitfeed.ExceptionProblemReporter): |
|
"""The company shuttle database has a few unused stops for reasons unrelated |
"""The company shuttle database has a few unused stops for reasons unrelated |
to this script. Ignore them. |
to this script. Ignore them. |
""" |
""" |
|
|
|
def __init__(self): |
|
accumulator = transitfeed.ExceptionProblemAccumulator() |
|
transitfeed.ProblemReporter.__init__(self, accumulator) |
|
|
def UnusedStop(self, stop_id, stop_name): |
def UnusedStop(self, stop_id, stop_name): |
pass |
pass |
|
|
def SaveFeed(input, output): |
def SaveFeed(input, output): |
tree = ET.parse(urllib.urlopen(input)) |
tree = ET.parse(urllib.urlopen(input)) |
|
|
schedule = transitfeed.Schedule() |
schedule = transitfeed.Schedule() |
service_period = schedule.GetDefaultServicePeriod() |
service_period = schedule.GetDefaultServicePeriod() |
service_period.SetWeekdayService() |
service_period.SetWeekdayService() |
service_period.SetStartDate('20070314') |
service_period.SetStartDate('20070314') |
service_period.SetEndDate('20071231') |
service_period.SetEndDate('20071231') |
# Holidays for 2007 |
# Holidays for 2007 |
service_period.SetDateHasService('20070528', has_service=False) |
service_period.SetDateHasService('20070528', has_service=False) |
service_period.SetDateHasService('20070704', has_service=False) |
service_period.SetDateHasService('20070704', has_service=False) |
service_period.SetDateHasService('20070903', has_service=False) |
service_period.SetDateHasService('20070903', has_service=False) |
service_period.SetDateHasService('20071122', has_service=False) |
service_period.SetDateHasService('20071122', has_service=False) |
service_period.SetDateHasService('20071123', has_service=False) |
service_period.SetDateHasService('20071123', has_service=False) |
service_period.SetDateHasService('20071224', has_service=False) |
service_period.SetDateHasService('20071224', has_service=False) |
service_period.SetDateHasService('20071225', has_service=False) |
service_period.SetDateHasService('20071225', has_service=False) |
service_period.SetDateHasService('20071226', has_service=False) |
service_period.SetDateHasService('20071226', has_service=False) |
service_period.SetDateHasService('20071231', has_service=False) |
service_period.SetDateHasService('20071231', has_service=False) |
|
|
stops = {} # Map from xml stop id to python Stop object |
stops = {} # Map from xml stop id to python Stop object |
agency = schedule.NewDefaultAgency(name='GBus', url='http://shuttle/', |
agency = schedule.NewDefaultAgency(name='GBus', url='http://shuttle/', |
timezone='America/Los_Angeles') |
timezone='America/Los_Angeles') |
|
|
for xml_stop in tree.getiterator('stop'): |
for xml_stop in tree.getiterator('stop'): |
stop = schedule.AddStop(lat=float(xml_stop.attrib['lat']), |
stop = schedule.AddStop(lat=float(xml_stop.attrib['lat']), |
lng=float(xml_stop.attrib['lng']), |
lng=float(xml_stop.attrib['lng']), |
name=xml_stop.attrib['name']) |
name=xml_stop.attrib['name']) |
stops[xml_stop.attrib['id']] = stop |
stops[xml_stop.attrib['id']] = stop |
|
|
for xml_shuttleGroup in tree.getiterator('shuttleGroup'): |
for xml_shuttleGroup in tree.getiterator('shuttleGroup'): |
if xml_shuttleGroup.attrib['name'] == 'Test': |
if xml_shuttleGroup.attrib['name'] == 'Test': |
continue |
continue |
r = schedule.AddRoute(short_name="", |
r = schedule.AddRoute(short_name="", |
long_name=xml_shuttleGroup.attrib['name'], route_type='Bus') |
long_name=xml_shuttleGroup.attrib['name'], route_type='Bus') |
for xml_route in xml_shuttleGroup.getiterator('route'): |
for xml_route in xml_shuttleGroup.getiterator('route'): |
t = r.AddTrip(schedule=schedule, headsign=xml_route.attrib['name'], |
t = r.AddTrip(schedule=schedule, headsign=xml_route.attrib['name'], |
trip_id=xml_route.attrib['id']) |
trip_id=xml_route.attrib['id']) |
trip_stops = [] # Build a list of (time, Stop) tuples |
trip_stops = [] # Build a list of (time, Stop) tuples |
for xml_schedule in xml_route.getiterator('schedule'): |
for xml_schedule in xml_route.getiterator('schedule'): |
trip_stops.append( (int(xml_schedule.attrib['time']) / 1000, |
trip_stops.append( (int(xml_schedule.attrib['time']) / 1000, |
stops[xml_schedule.attrib['stopId']]) ) |
stops[xml_schedule.attrib['stopId']]) ) |
trip_stops.sort() # Sort by time |
trip_stops.sort() # Sort by time |
for (time, stop) in trip_stops: |
for (time, stop) in trip_stops: |
t.AddStopTime(stop=stop, arrival_secs=time, departure_secs=time) |
t.AddStopTime(stop=stop, arrival_secs=time, departure_secs=time) |
|
|
schedule.Validate(problems=NoUnusedStopExceptionProblemReporter()) |
schedule.Validate(problems=NoUnusedStopExceptionProblemReporter()) |
schedule.WriteGoogleTransitFeed(output) |
schedule.WriteGoogleTransitFeed(output) |
|
|
|
|
def main(): |
def main(): |
parser = OptionParser() |
parser = OptionParser() |
parser.add_option('--input', dest='input', |
parser.add_option('--input', dest='input', |
help='Path or URL of input') |
help='Path or URL of input') |
parser.add_option('--output', dest='output', |
parser.add_option('--output', dest='output', |
help='Path of output file. Should end in .zip and if it ' |
help='Path of output file. Should end in .zip and if it ' |
'contains the substring YYYYMMDD it will be replaced with ' |
'contains the substring YYYYMMDD it will be replaced with ' |
'today\'s date. It is impossible to include the literal ' |
'today\'s date. It is impossible to include the literal ' |
'string YYYYYMMDD in the path of the output file.') |
'string YYYYYMMDD in the path of the output file.') |
parser.add_option('--execute', dest='execute', |
parser.add_option('--execute', dest='execute', |
help='Commands to run to copy the output. %(path)s is ' |
help='Commands to run to copy the output. %(path)s is ' |
'replaced with full path of the output and %(name)s is ' |
'replaced with full path of the output and %(name)s is ' |
'replaced with name part of the path. Try ' |
'replaced with name part of the path. Try ' |
'scp %(path)s myhost:www/%(name)s', |
'scp %(path)s myhost:www/%(name)s', |
action='append') |
action='append') |
parser.set_defaults(input=None, output=None, execute=[]) |
parser.set_defaults(input=None, output=None, execute=[]) |
(options, args) = parser.parse_args() |
(options, args) = parser.parse_args() |
|
|
today = datetime.date.today().strftime('%Y%m%d') |
today = datetime.date.today().strftime('%Y%m%d') |
options.output = re.sub(r'YYYYMMDD', today, options.output) |
options.output = re.sub(r'YYYYMMDD', today, options.output) |
(_, name) = os.path.split(options.output) |
(_, name) = os.path.split(options.output) |
path = options.output |
path = options.output |
|
|
SaveFeed(options.input, options.output) |
SaveFeed(options.input, options.output) |
|
|
for command in options.execute: |
for command in options.execute: |
import subprocess |
import subprocess |
def check_call(cmd): |
def check_call(cmd): |
"""Convenience function that is in the docs for subprocess but not |
"""Convenience function that is in the docs for subprocess but not |
installed on my system.""" |
installed on my system.""" |
retcode = subprocess.call(cmd, shell=True) |
retcode = subprocess.call(cmd, shell=True) |
if retcode < 0: |
if retcode < 0: |
raise Exception("Child '%s' was terminated by signal %d" % (cmd, |
raise Exception("Child '%s' was terminated by signal %d" % (cmd, |
-retcode)) |
-retcode)) |
elif retcode != 0: |
elif retcode != 0: |
raise Exception("Child '%s' returned %d" % (cmd, retcode)) |
raise Exception("Child '%s' returned %d" % (cmd, retcode)) |
|
|
# path_output and filename_current can be used to run arbitrary commands |
# path_output and filename_current can be used to run arbitrary commands |
check_call(command % locals()) |
check_call(command % locals()) |
|
|
if __name__ == '__main__': |
if __name__ == '__main__': |
main() |
main() |
|
|