Skip to content
This repository has been archived by the owner on Jul 25, 2020. It is now read-only.

Getters

david edited this page Apr 28, 2019 · 1 revision

The following guidelines define how the Getter functions must be coded to be compatible with PyBuses.

Stop Getters

  • Stop Getters should connect to a valid data source to fetch the stop info from.
  • Stop Getters receive as parameter the Stop ID of the Stop to search, as int.
  • If a Stop is found, the getter must return a valid PyBuses Stop data object, with all the available info completed (at least stopid and name).
  • If a Stop is not found, but it might exist (i.e. is not registered in our database but could be on a remote API), the getter must raise the StopNotFound exception.
  • If a Stop is not found, and the getter is sure about that stop does not physically exist (i.e. this data is queried to an official API), it must raise the StopNotExist exception.
  • If the data source is not available or have some problems or errors, the getter must raise the StopGetterUnavailable exception.
  • Depending on the kind of data source used by the getter, Stop Getters can be classified on:
    • Online Getters receive information from a trusted, updated source, like an official API.
    • Offline Getters receive information from a source that can be outdated, like a local database.
    • When a Stop is not found on a Offline getter, it might exist and be found on a Online getter.
    • Offline Getters are useful to limit the ammount of requests made to the API that provides Stop information.
    • The information retrieved by an Online Getter can be saved through a Stop Setter to a local storage, and then used by an Offline Getter.
  • Stop Getters are stored on PyBuses as an OrderedDict, with the format { StopGetter : online(True/False) }. Ordered Dicts are like common dictionaries, but their entries are ordered like on a list or tuple.
  • PyBuses can return a list of Stop Getters, sorted by the order in which they were defined on PyBuses. The list can be filtered by Online or Offline getters, but also returning all the defined getters, in which case the Online getters are returned first on the list (following the same sorting order).
    • Example: Having 2 Online Getters (ON1, ON2) and 2 Offline Getters (OF1, OF2), and having them defined with the order OF1, ON2, OF2, ON1; When asking PyBuses to return them, the order will be:
      • When asking to return ALL of them: ON2, ON1, OF1, OF2
      • When asking to return Online getters only: ON2, ON1
      • When asking to return Offline getters only: OF1, OF2

Example: Online Stop Getter

On this example, the Getter function use requests.get() to ask a remote API for the Stop to find. The Stop is returned as a JSON.

import requests
import json
from pybuses import Stop, StopNotExist, StopGetterUnavailable


def my_online_stop_getter(stopid: int) -> Stop:
    try:
        # Let's imagine we use Requests to ask an API for the Stop
        result = requests.get("https://example_bus_api.org/api/stop/" + str(stopid))
        
        if result.status_code == 404:
            # This API returns a status code of 404 when the Stop does not exist
            raise StopNotExist()
        elif result.status_code != 200:
            raise StopGetterUnavailable("Status Code = " + str(result.status_code))
        
        # This API returns a JSON
        data = json.loads(result.text)
        
        # The JSON returned by the API looks like this:
        # {
        #     "id": "1234",
        #     "name": "",
        #     "location": "46.81064,133.38931"
        # }
        
        lat, lon = None, None
        if "location" in data.keys():
            lat, lon = data["location"].split(",")
        
        return Stop(
            stopid=data["stopid"],
            name=data["name"],
            lat=lat,
            lon=lon
        )
    
    except (requests.exceptions.RequestException, KeyError) as ex:
        # Catch possible exceptions returned by Requests on the API caller function
        raise StopGetterUnavailable(ex)

Example: Offline Stop Getter (from a file)

On this example, we have saved one file per Stop, with all the info on it, using #### as separator.

from pybuses import Stop, StopNotFound, StopGetterUnavailable

def get_stop_from_file(stopid: int) -> Stop:
    try:
        with open(f"{stopid}.txt", "r") as file:
            data = file.read().strip().split("####")
            
            lat, lon = None, None
            try:
                lat, lon = data[2], data[3]
            except IndexError:
                pass
            
            return Stop(
                stopid=int(data[0]),
                name=data[1],
                lat=lat,
                lon=lon
            )
    
    except FileNotFoundError:
        raise StopNotFound()
    
    except (IOError, IndexError, ValueError) as ex:
        raise StopGetterUnavailable(ex)

Bus Getters

  • Bus Getters should connect to a trusted API to retrieve the list of buses arriving to a Stop, in real time, showing their lines, routes and time remaining until arrival, in minutes.
  • Unlike Stop Getters, Bus Getters are not classified on Online or Offline getters.
  • A bus getter can be called when a user wants to get the bus schedule for a certain stop.
  • Bus getters receive as parameter the Stop ID of the Stop to get the buses of, as int.
  • If buses are found, a list of Bus objects is returned. It is not required to sort this list of buses (by time or any other sorting method desired), they get sorted by PyBuses.
  • If no buses are found, but nothing was wrong, an empty list is returned.
  • If the Stop does not exist, the setter must throw the StopNotExist() or StopNotFound() exception/s, depending on the Online/Offline nature of this Getter. However, it is recommended to search the Stop first and make sure it exists.
  • If some error happened when fetching the list of buses, the getter must throw the BusGetterUnavailable() exception.

Example: Bus Getter

import requests
import json
from typing import List
from pybuses import Bus, StopNotExist, BusGetterUnavailable


def my_online_bus_getter(stopid: int) -> List[Bus]:
    try:
        # Let's imagine we use Requests to ask an API for the Stop
        result = requests.get("https://example_bus_api.org/api/buses/" + str(stopid))
        
        if result.status_code == 404:
            # This API returns a status code of 404 when the Stop does not exist
            raise StopNotExist()
        elif result.status_code != 200:
            raise BusGetterUnavailable("Status Code = " + str(result.status_code))
        
        # This API returns a JSON
        data = json.loads(result.text)
        
        # The JSON returned by the API looks like this:
        # {
        #     "buses": [
        #         {
        #             "line": "12A",
        #             "route": "University - Beach",
        #             "time": 0
        #         },
        #         {
        #             "line": "C7",
        #             "line": "King's Landing",
        #             "time": 2
        #         },
        #     ]
        # }
        
        buses = list()
        for bus_data in data["buses"]:
            buses.append(Bus(
                line=bus_data["line"],
                route=bus_data["route"],
                time=bus_data["time"]
            ))
        
        return buses
    
    except (requests.exceptions.RequestException, KeyError) as ex:
        # Catch possible exceptions returned by Requests on the API caller function
        raise BusGetterUnavailable(ex)
Clone this wiki locally