def FormatException(self, e, output): """Append HTML version of e to list output.""" d = e.GetDictToFormat() for k in ('file_name', 'feedname', 'column_name'): if k in d.keys(): d[k] = '<code>%s</code>' % d[k] problem_text = e.FormatProblem(d).replace('\n', '<br>') output.append('<li>') output.append('<div class="problem">%s</div>' % transitfeed.EncodeUnicode(problem_text)) try: if hasattr(e, 'row_num'): line_str = 'line %d of ' % e.row_num else: line_str = '' output.append('in %s<code>%s</code><br>\n' % (line_str, e.file_name)) row = e.row headers = e.headers column_name = e.column_name table_header = '' # HTML table_data = '' # HTML for header, value in zip(headers, row): attributes = '' if header == column_name: attributes = ' class="problem"' table_header += '<th%s>%s</th>' % (attributes, header) table_data += '<td%s>%s</td>' % (attributes, value) # Make sure output is encoded into UTF-8 output.append('<table class="dump"><tr>%s</tr>\n' % transitfeed.EncodeUnicode(table_header)) output.append('<tr>%s</tr></table>\n' % transitfeed.EncodeUnicode(table_data)) except AttributeError, e: pass # Hope this was getting an attribute from e ;-)
def WriteOutput(title, locations, limit, f): """Write html to f for up to limit trips between locations. Args: title: String used in html title locations: list of (lat, lng) tuples limit: maximum number of queries in the html f: a file object """ output_prefix = """ <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>%(title)s</title> </head> <body> Random queries for %(title)s<p> This list of random queries should speed up important manual testing. Here are some things to check when looking at the results of a query. <ul> <li> Check the agency attribution under the trip results: <ul> <li> has correct name and spelling of the agency <li> opens a page with general information about the service </ul> <li> For each alternate trip check that each of these is reasonable: <ul> <li> the total time of the trip <li> the time for each leg. Bad data frequently results in a leg going a long way in a few minutes. <li> the icons and mode names (Tram, Bus, etc) are correct for each leg <li> the route names and headsigns are correctly formatted and not redundant. For a good example see <a href="http://code.google.com/transit/spec/transit_feed_specification.html#transitScreenshots">the screenshots in the Google Transit Feed Specification</a>. <li> the shape line on the map looks correct. Make sure the polyline does not zig-zag, loop, skip stops or jump far away unless the trip does the same thing. <li> the route is active on the day the trip planner returns </ul> </ul> If you find a problem be sure to save the URL. This file is generated randomly. <ol> """ % locals() output_suffix = """ </ol> </body> </html> """ % locals() f.write(transitfeed.EncodeUnicode(output_prefix)) for source, destination in zip(locations[0:limit], locations[1:limit + 1]): f.write( transitfeed.EncodeUnicode( "<li>%s\n" % LatLngsToGoogleLink(source, destination))) f.write(transitfeed.EncodeUnicode(output_suffix))
def FormatException(self, e, output): """Append HTML version of e to list output.""" d = e.GetDictToFormat() for k in ("file_name", "feedname", "column_name"): if k in d.keys(): d[k] = "<code>%s</code>" % d[k] if "url" in d.keys(): d["url"] = '<a href="%(url)s">%(url)s</a>' % d problem_text = e.FormatProblem(d).replace("\n", "<br>") problem_class = "problem" if e.IsNotice(): problem_class += " notice" output.append("<li>") output.append( '<div class="%s">%s</div>' % (problem_class, transitfeed.EncodeUnicode(problem_text)) ) try: if hasattr(e, "row_num"): line_str = "line %d of " % e.row_num else: line_str = "" output.append( "in %s<code>%s</code><br>\n" % (line_str, transitfeed.EncodeUnicode(e.file_name)) ) row = e.row headers = e.headers column_name = e.column_name table_header = "" # HTML table_data = "" # HTML for header, value in zip(headers, row): attributes = "" if header == column_name: attributes = ' class="problem"' table_header += "<th%s>%s</th>" % (attributes, header) table_data += "<td%s>%s</td>" % (attributes, value) # Make sure output is encoded into UTF-8 output.append( '<table class="dump"><tr>%s</tr>\n' % transitfeed.EncodeUnicode(table_header) ) output.append( "<tr>%s</tr></table>\n" % transitfeed.EncodeUnicode(table_data) ) except AttributeError as e: pass # Hope this was getting an attribute from e ;-) output.append("<br></li>\n")
def WriteOutput(self, feed_location, f, schedule, extension): """Write the html output to f.""" if self.HasIssues(): if self.ErrorCount() + self.WarningCount() == 1: summary = ( '<span class="fail">Found this problem:</span>\n%s' % self.CountTable() ) else: summary = ( '<span class="fail">Found these problems:</span>\n%s' % self.CountTable() ) else: summary = '<span class="pass">feed validated successfully</span>' if self.HasNotices(): summary = ( '<h3 class="issueHeader">Notices:</h3>' + self.FormatType("Notice", self.ProblemListMap(TYPE_NOTICE).items()) + summary ) basename = os.path.basename(feed_location) feed_path = (feed_location[: feed_location.rfind(basename)], basename) agencies = ", ".join( [ '<a href="%s">%s</a>' % (a.agency_url, a.agency_name) for a in schedule.GetAgencyList() ] ) if not agencies: agencies = "?" dates = "No valid service dates found" (start, end) = schedule.GetDateRange() if start and end: def FormatDate(yyyymmdd): src_format = "%Y%m%d" dst_format = "%B %d, %Y" try: return time.strftime( dst_format, time.strptime(yyyymmdd, src_format) ) except ValueError: return yyyymmdd formatted_start = FormatDate(start) formatted_end = FormatDate(end) dates = "%s to %s" % (formatted_start, formatted_end) calendar_summary = CalendarSummary(schedule) if calendar_summary: calendar_summary_html = ( """<br> During the upcoming service dates %(date_summary_range)s: <table> <tr><th class="header">Average trips per date:</th><td class="header">%(mean_trips)s</td></tr> <tr><th class="header">Most trips on a date:</th><td class="header">%(max_trips)s, on %(max_trips_dates)s</td></tr> <tr><th class="header">Least trips on a date:</th><td class="header">%(min_trips)s, on %(min_trips_dates)s</td></tr> </table>""" % calendar_summary ) else: calendar_summary_html = "" output_prefix = """ <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>FeedValidator: %(feed_file)s</title> <style> body {font-family: Georgia, serif; background-color: white} .path {color: gray} div.problem {max-width: 500px} table.dump td,th {background-color: khaki; padding: 2px; font-family:monospace} table.dump td.problem,th.problem {background-color: dc143c; color: white; padding: 2px; font-family:monospace} table.count_outside td {vertical-align: top} table.count_outside {border-spacing: 0px; } table {border-spacing: 5px 0px; margin-top: 3px} h3.issueHeader {padding-left: 0.5em} h4.issueHeader {padding-left: 1em} .pass {background-color: lightgreen} .fail {background-color: yellow} .notice {background-color: yellow} .pass, .fail {font-size: 16pt} .header {background-color: white; font-family: Georgia, serif; padding: 0px} th.header {text-align: right; font-weight: normal; color: gray} .footer {font-size: 10pt} </style> </head> <body> GTFS validation results for feed:<br> <code><span class="path">%(feed_dir)s</span><b>%(feed_file)s</b></code><br> FeedValidator extension used: %(extension)s <br><br> <table> <tr><th class="header">Agencies:</th><td class="header">%(agencies)s</td></tr> <tr><th class="header">Routes:</th><td class="header">%(routes)s</td></tr> <tr><th class="header">Stops:</th><td class="header">%(stops)s</td></tr> <tr><th class="header">Trips:</th><td class="header">%(trips)s</td></tr> <tr><th class="header">Shapes:</th><td class="header">%(shapes)s</td></tr> <tr><th class="header">Effective:</th><td class="header">%(dates)s</td></tr> </table> %(calendar_summary)s <br> %(problem_summary)s <br><br> """ % { "feed_file": feed_path[1], "feed_dir": feed_path[0], "agencies": agencies, "routes": len(schedule.GetRouteList()), "stops": len(schedule.GetStopList()), "trips": len(schedule.GetTripList()), "shapes": len(schedule.GetShapeList()), "dates": dates, "problem_summary": summary, "calendar_summary": calendar_summary_html, "extension": extension, } # In output_suffix string # time.strftime() returns a regular local time string (not a Unicode one) with # default system encoding. And decode() will then convert this time string back # into a Unicode string. We use decode() here because we don't want the operating # system to do any system encoding (which may cause some problem if the string # contains some non-English characters) for the string. Therefore we decode it # back to its original Unicode code print. time_unicode = time.strftime("%B %d, %Y at %I:%M %p %Z").decode( sys.getfilesystemencoding() ) output_suffix = """ <div class="footer"> Generated by <a href="https://github.com/google/transitfeed/wiki/FeedValidator"> FeedValidator</a> version %s on %s. </div> </body> </html>""" % ( transitfeed.__version__, time_unicode, ) f.write(transitfeed.EncodeUnicode(output_prefix)) if self.ProblemListMap(TYPE_ERROR): f.write('<h3 class="issueHeader">Errors:</h3>') f.write(self.FormatType("Error", self.ProblemListMap(TYPE_ERROR).items())) if self.ProblemListMap(TYPE_WARNING): f.write('<h3 class="issueHeader">Warnings:</h3>') f.write( self.FormatType("Warning", self.ProblemListMap(TYPE_WARNING).items()) ) f.write(transitfeed.EncodeUnicode(output_suffix))
def main(): usage = \ '''%prog [options] <input GTFS.zip> [<output.kml>] Reads GTFS file or directory <input GTFS.zip> and creates a KML file <output.kml> that contains the geographical features of the input. If <output.kml> is omitted a default filename is picked based on <input GTFS.zip>. By default the KML contains all stops and shapes. For more information see https://github.com/google/transitfeed/wiki/KMLWriter ''' parser = util.OptionParserLongError( usage=usage, version='%prog '+transitfeed.__version__) parser.add_option('-t', '--showtrips', action='store_true', dest='show_trips', help='include the individual trips for each route') parser.add_option('-a', '--altitude_per_sec', action='store', type='float', dest='altitude_per_sec', help='if greater than 0 trips are drawn with time axis ' 'set to this many meters high for each second of time') parser.add_option('-s', '--splitroutes', action='store_true', dest='split_routes', help='split the routes by type') parser.add_option('-d', '--date_filter', action='store', type='string', dest='date_filter', help='Restrict to trips active on date YYYYMMDD') parser.add_option('-p', '--display_shape_points', action='store_true', dest='shape_points', help='shows the actual points along shapes') parser.add_option('--show_stop_hierarchy', action='store_true', dest='show_stop_hierarchy', help='include station-stop hierarchy info in output') parser.set_defaults(altitude_per_sec=1.0) options, args = parser.parse_args() if len(args) < 1: parser.error('You must provide the path of an input GTFS file.') if args[0] == 'IWantMyCrash': raise Exception('For testCrashHandler') input_path = args[0] if len(args) >= 2: output_path = args[1] else: path = os.path.normpath(input_path) (feed_dir, feed_name) = os.path.split(path) if '.' in feed_name: feed_name = feed_name.rsplit('.', 1)[0] # strip extension output_filename = '%s.kml' % feed_name output_path = os.path.join(feed_dir, output_filename) feed = None try: loader = transitfeed.Loader(input_path) feed = loader.Load() except transitfeed.ExceptionWithContext, e: print >>sys.stderr, ( "\n\nGTFS feed must load without any errors.\n" "While loading %s the following error was found:\n%s\n%s\n" % (input_path, e.FormatContext(), transitfeed.EncodeUnicode(e.FormatProblem()))) sys.exit(1)
def main(): usage = """%prog [options] <input GTFS.zip> [<output.kml>] Reads GTFS file or directory <input GTFS.zip> and creates a KML file <output.kml> that contains the geographical features of the input. If <output.kml> is omitted a default filename is picked based on <input GTFS.zip>. By default the KML contains all stops and shapes. For more information see https://github.com/google/transitfeed/wiki/KMLWriter """ parser = util.OptionParserLongError( usage=usage, version="%prog " + transitfeed.__version__ ) parser.add_option( "-t", "--showtrips", action="store_true", dest="show_trips", help="include the individual trips for each route", ) parser.add_option( "-a", "--altitude_per_sec", action="store", type="float", dest="altitude_per_sec", help="if greater than 0 trips are drawn with time axis " "set to this many meters high for each second of time", ) parser.add_option( "-s", "--splitroutes", action="store_true", dest="split_routes", help="split the routes by type", ) parser.add_option( "-d", "--date_filter", action="store", type="string", dest="date_filter", help="Restrict to trips active on date YYYYMMDD", ) parser.add_option( "-p", "--display_shape_points", action="store_true", dest="shape_points", help="shows the actual points along shapes", ) parser.add_option( "--show_stop_hierarchy", action="store_true", dest="show_stop_hierarchy", help="include station-stop hierarchy info in output", ) parser.set_defaults(altitude_per_sec=1.0) options, args = parser.parse_args() if len(args) < 1: parser.error("You must provide the path of an input GTFS file.") if args[0] == "IWantMyCrash": raise Exception("For testCrashHandler") input_path = args[0] if len(args) >= 2: output_path = args[1] else: path = os.path.normpath(input_path) (feed_dir, feed_name) = os.path.split(path) if "." in feed_name: feed_name = feed_name.rsplit(".", 1)[0] # strip extension output_filename = "%s.kml" % feed_name output_path = os.path.join(feed_dir, output_filename) feed = None try: loader = transitfeed.Loader(input_path) feed = loader.Load() except transitfeed.ExceptionWithContext as e: print( ( "\n\nGTFS feed must load without any errors.\n" "While loading %s the following error was found:\n%s\n%s\n" % ( input_path, e.FormatContext(), transitfeed.EncodeUnicode(e.FormatProblem()), ) ), file=sys.stderr, ) sys.exit(1) print("Writing %s" % output_path) writer = KMLWriter() writer.show_trips = options.show_trips writer.altitude_per_sec = options.altitude_per_sec writer.split_routes = options.split_routes writer.date_filter = options.date_filter writer.shape_points = options.shape_points writer.show_stop_hierarchy = options.show_stop_hierarchy writer.Write(feed, output_path)