Skip to content

Adding a new system to pybikes

You can scaffold a new bike share system by running

bash
$ python -m utils.scaffold example

================================================
Here is your 'Example' implementation

System: pybikes/example.py
Data: pybikes/data/example.json

Run tests by:
$ pytest -k Example

Visualize result:
$ make map! T_FLAGS+='-k Example'

Happy hacking :)
================================================

This is what you need to get started adding a new system to pybikes.

Pybikes acts as a bike share instance factory.

An instance represents a bike share system in a particular city or region.

A system is the implementation of a bike share system. It's the code and logic to access an endpoint and extract bike share information. One system can have many instances.

Instances are declared on json files and are stored in pybikes/data. It contains meta information about the instance in particular and the arguments to initialize the system.

Let's look through the example

Example is a subclass of BikeShareSystem. It is implemented in pybikes/example.py.

python
import json

from pybikes import BikeShareSystem, BikeShareStation, PyBikesScraper
from pybikes.base import Vehicle, VehicleTypes


class Example(BikeShareSystem):

    meta = {
        # Name of the company behind the system
        "company": ["Some company name"],
        # XXX add license if it applies
        "license": {
            "name": "Name of the license",
            "url": "https://link.to.license.example"
        }
    }

    def __init__(self, tag, meta, endpoint):
        super().__init__(tag, meta)
        self.endpoint = endpoint

    def update(self, scraper=None):
        scraper = scraper or PyBikesScraper()
        data = scraper.request(self.endpoint)
        data = json.loads(data)

        # XXX remove if system does not support stations
        self.stations = [
            BikeShareStation(
                name=st["name"],
                latitude=st["latitude"],
                longitude=st["longitude"],
                bikes=st["bikes"],
                free=st["free"],
                # Add more extra fields if available
                extra={
                    "uid": st["id"],
                    "online": st["online"],
                },
            ) for st in data["stations"]
        ]

        # XXX remove if system does not support vehicles
        self.vehicles = [
            Vehicle(
                latitude=vh["latitude"],
                longitude=vh["longitude"],
                system=self,
                vehicle_type=getattr(VehicleTypes, vh["type"]),
                extra={
                    "uid": vh["id"],
                    "online": vh["online"],
                }
            ) for vh in data["vehicles"]
        ]

Example instances are declared on a pybikes/data/example.json file.

json
{
  "class": "Example",
  "system": "example",
  "instances": [
    {
      "tag": "example-foo",
      "endpoint": "https://gist.githubusercontent.com/eskerda/919bb934b999f296ec189c4b33ef5d59/raw/6ad847524666a16104a0e750cf90ef06ece0d8b5/feed.json",
      "meta": {
        "name": "Some name",
        "city": "City or region of the system",
        "latitude": 1.1,
        "longitude": 1.1,
        "country": "Two letter country code"
      }
    }
  ]
}

When we call pybikes.get("example-foo"), the library will instantiate a Example object with the arguments declared in the data file.