def add_stop(self, key, props): """Add stop to favorite `key`.""" favorite = self.get(key) props = pan.AttrDict(props) self.remove_stop(key, props.id) favorite.stops.append(pan.AttrDict(id=props.id, name=props.name, x=props.x, y=props.y, color=props.color)) self._update_meta(key)
def find_nearby_stops(x, y): """Return a list of stops near given coordinates.""" # XXX: The API endpoint used by find_stops doesn't require # a stopTypes argument, but returns sensibly filtered results. # We try to match that, but don't quite succeed. params = dict(stopTypes=",".join(STOP_TYPES), radius="500", useStopPointHierarchy="false", categories="none", returnLines="true", lat="{:.6f}".format(y), lon="{:.6f}".format(x)) url = format_url("/StopPoint", **params) result = pan.http.get_json(url) result = pan.AttrDict(result) return [{ "color": get_stop_color(stop.modes), "description": get_stop_description(stop), "id": stop.id, "line_summary": get_line_summary(stop), "name": stop.commonName, "x": float(stop.lon), "y": float(stop.lat), } for stop in result.stopPoints]
def find_departures(stops): """Return a list of departures from `stops`.""" stops = ", ".join('"{}"'.format(x) for x in stops) body = format_graphql("find_departures", ids=stops) url = URL.format(region=REGION) result = pan.http.post_json(url, body, headers=HEADERS) result = pan.AttrDict(result) def departures(): for stop in result.data.stops: for departure in stop.stoptimesWithoutPatterns: yield stop, departure return pan.util.sorted_departures([{ "destination": parse_headsign(departure.trip.tripHeadsign), "line": parse_line_name(departure.trip.route), "realtime": bool(departure.realtime), "scheduled_time": parse_scheduled_time(departure), "stop": stop.gtfsId, "time": parse_time(departure), "x": float(stop.lon), "y": float(stop.lat), } for stop, departure in departures()])
def get_line_summary(stop): """Return a summary of lines that use `stop`.""" lines = pan.util.sorted_unique_lines([ pan.AttrDict({ "name": parse_line_name(pattern.route), "destination": parse_headsign(pattern.headsign), }) for pattern in stop.patterns ]) return "\n".join("{} → {}".format(x.name, x.destination) for x in lines[:3])
def _split_option(self, option, create=False): """Split dotted option to dictionary and option name.""" root = self for section in option.split(".")[:-1]: if create and not section in root: # Create missing hierarchies. root[section] = pan.AttrDict() root = root[section] name = option.split(".")[-1] return root, name
def add(self, name): """Add `name` as a new favorite and return key.""" key = str(uuid.uuid4()) self._favorites.append(pan.AttrDict(key=key, provider=pan.conf.provider, name=name, stops=[], ignore_lines=[])) self._update_meta(key) return key
def list_networks(): """Return a list of supported city bike networks.""" url = "https://api.citybik.es/v2/networks?fields=id,location,name" networks = pan.http.get_json(url) networks = pan.AttrDict(networks) return [ dict( city=network.location.city, country=network.location.country, id=network.id, name=network.name, x=network.location.longitude, y=network.location.latitude, ) for network in networks.networks ]
def find_nearby_stops(x, y): """Return a list of stops near given coordinates.""" body = format_graphql("find_nearby_stops", x=x, y=y) url = URL.format(region=REGION) result = pan.http.post_json(url, body, headers=HEADERS) result = pan.AttrDict(result) return [{ "color": get_stop_color(stop), "description": stop.desc or _("Stop"), "id": stop.gtfsId, "line_summary": get_line_summary(stop), "name": format_stop_name(stop), "x": float(stop.lon), "y": float(stop.lat), } for stop in [x.node.stop for x in result.data.stopsByRadius.edges]]
def list_stations(network): """Return a list of bike stations and their occupancy.""" url = "https://api.digitransit.fi/routing/v1/routers/hsl/bike_rental" stations = pan.http.get_json(url, headers=HEADERS) stations = pan.AttrDict(stations) return [ dict( empty_slots=station.spacesAvailable, free_bikes=station.bikesAvailable, id=station.id, name=station.name, x=station.x, y=station.y, ) for station in stations.stations ]
def list_stations(network): """Return a list of bike stations and their occupancy.""" url = "https://api.citybik.es/v2/networks/{}?fields=stations".format( network) stations = pan.http.get_json(url) stations = pan.AttrDict(stations) return [ dict( empty_slots=station.empty_slots, free_bikes=station.free_bikes, id=station.id, name=parse_station_name(station), x=station.longitude, y=station.latitude, ) for station in stations.network.stations ]
def find_stops(query, x, y): """Return a list of stops matching `query`.""" query = re.sub('["{}]', "", query) body = format_graphql("find_stops", query=query) url = URL.format(region=REGION) result = pan.http.post_json(url, body, headers=HEADERS) result = pan.AttrDict(result) return [{ "color": get_stop_color(stop), "description": stop.desc or _("Stop"), "id": stop.gtfsId, "line_summary": get_line_summary(stop), "name": format_stop_name(stop), "x": float(stop.lon), "y": float(stop.lat), } for stop in result.data.stops]
def find_stops(query, x, y): """Return a list of stops matching `query`.""" # XXX: We cannot seem to get a list of lines without # needing to do separate API calls for each stop. query = urllib.parse.quote(query) path = "/StopPoint/Search/{}".format(query) url = format_url(path, maxResults="50", includeHubs="false") result = pan.http.get_json(url) result = pan.AttrDict(result) return [{ "color": get_stop_color(match.modes), "description": get_stop_description(match), "id": match.id, "line_summary": "", "name": match.name, "x": float(match.lon), "y": float(match.lat), } for match in result.matches]
def _update(self, values, root=None, defaults=None, path=()): """Load values of options after validation.""" if root is None: root = self if defaults is None: defaults = DEFAULTS for name, value in values.items(): if isinstance(value, dict): self._update(value, root.setdefault(name, pan.AttrDict()), defaults.setdefault(name, {}), path + (name, )) continue try: if name in defaults: # Be liberal, but careful in what to accept. value = self._coerce(value, defaults[name]) root[name] = copy.deepcopy(value) except Exception as error: full_name = ".".join(path + (name, )) print("Discarding bad option-value pair {}, {}: {}".format( repr(full_name), repr(value), str(error)), file=sys.stderr)
def find_lines(stops): """Return a list of lines that use `stops`.""" stops = ", ".join('"{}"'.format(x) for x in stops) body = format_graphql("find_lines", ids=stops) url = URL.format(region=REGION) result = pan.http.post_json(url, body, headers=HEADERS) result = pan.AttrDict(result) def patterns(): for stop in result.data.stops: for pattern in stop.patterns: yield pattern return pan.util.sorted_unique_lines([{ "color": COLORS.get(pattern.route.mode, COLORS.BUS), "destination": parse_headsign(pattern.headsign), "id": pattern.route.gtfsId, "name": parse_line_name(pattern.route), } for pattern in patterns()])
https://api.tfl.gov.uk/swagger/ui/ https://tfl.gov.uk/plan-a-journey/ """ import datetime import pan import re import urllib.parse COLORS = pan.AttrDict({ "bus": "#ed192d", "cable-car": "#ed192d", "coach": "#ed192d", "dlr": "#244ba6", "national-rail": "#244ba6", "overground": "#244ba6", "replacement-bus": "#ed192d", "river-bus": "#289ee0", "river-tour": "#289ee0", "tflrail": "#244ba6", "tram": "#59c134", "tube": "#244ba6", }) DESTINATION_SUFFIXES = [ "dlr station", "rail station", "tram stop", "underground station", ] MODE_COLOR_ORDER = [
def get_line_summary(stop): """Return a list of lines that use `stop`.""" line = lambda x: pan.AttrDict(name=x.name, destination="") lines = pan.util.sorted_unique_lines(map(line, stop.lines)) return ", ".join(x.name for x in lines[:10])
http://digitransit.fi/en/developers/services-and-apis/1-routing-api/ http://dev.hsl.fi/graphql/console/ """ import functools import os import pan import re from pan.i18n import _ COLORS = pan.AttrDict({ "AIRPLANE": "#ed145d", "BUS": "#007ac9", "FERRY": "#00b9e4", "RAIL": "#8c4799", "SUBWAY": "#ff6319", "TRAM": "#00985f", "WALK": "#888888", }) HEADERS = {"Content-Type": "application/graphql"} URL = "http://api.digitransit.fi/routing/v1/routers/{region}/index/graphql" # Overriden by region-specific implementations. REGION = None def find_departures(stops): """Return a list of departures from `stops`.""" stops = ", ".join('"{}"'.format(x) for x in stops)