Skip to main content

pygtfsie

A GTFS static and GTFS-Realtime engine: ingest a feed archive into SQLite, resolve every stop event to an absolute instant, and answer departure queries.

This is the engine half of a pair. The Home Assistant integration built on it lives in ha-gtfsie. Nothing here imports Home Assistant, and a CI job fails the build if anything ever does.

Why it is a separate package

The great majority of the logic in a transit-departure integration is not integration logic. It is date arithmetic, CSV tolerance, protobuf decoding and SQL -- none of which needs an event loop, a config entry or a pinned Home Assistant version to be exercised.

Splitting the engine out means its tests run on bare pytest across every supported Python in well under a second, so the parts most likely to be wrong are also the cheapest to check. The integration keeps the parts that genuinely need Home Assistant: config entries, coordinators, entities and services.

Design rules

Three rules account for most of what this library does differently, and each exists because the alternative has a known, reported failure mode.

Time is resolved at ingest, never at query time. Every (trip, stop time, service date) becomes an absolute UTC epoch integer when the feed is loaded. No SQL statement contains date(), datetime(), strftime() or 'now'. SQLite evaluates those in C against the process timezone in UTC, which no Python-level clock control can reach -- so a suite that fakes the clock still gets real dates from the database, and the disagreement surfaces as departures on the wrong day.

The service day is anchored at local noon minus twelve hours. Not midnight. Local midnight does not exist on spring-forward days in Cairo, Havana, Asunción and around 70 other zone-dates in the current decade, and it happens twice on the corresponding fall-back days. Anchoring there yields a silently shifted instant rather than an error. Noon has never been moved by any jurisdiction.

Nothing reads the current time except the caller. Every query takes a now_utc argument. scripts/time-sweep.sh runs the whole suite at six instants in six timezones and fails if the results differ, which is what keeps the rule from decaying.

Layout

pygtfsie/
  const.py          GTFS enumerations, route type names and icons
  exceptions.py     one hierarchy, so a consumer can catch the library
  helpers/
    tz.py           the only place timezone reasoning exists
    text.py         the only place str() is called on a raw feed value
    geo.py          bounding boxes and great-circle distance
    logthrottle.py  rate limiting for repeated messages

Later phases add store/ (schema, connections, queries), ingest/ (download, CSV, calendar expansion, materialisation) and realtime/ (protobuf and SIRI decoding, trip matching).

Install

pip install pygtfsie              # engine only
pip install pygtfsie[realtime]    # adds gtfs-realtime-bindings and protobuf

Realtime support is an extra because a consumer that only needs the static timetable should not pull in protobuf.

Development

python3 -m venv .venv
./.venv/bin/pip install -e ".[dev]"
./.venv/bin/python -m pytest -q

Before pushing anything that touches date handling:

./.venv/bin/python -m ruff check pygtfsie tests
./.venv/bin/python -m ruff format --check pygtfsie tests
scripts/time-sweep.sh              # needs libfaketime

Branching

master is the release branch and is what tags are cut from. Work happens on topic branches merged back into master.

Pipeline

The GitLab pipeline has three stages:

  • lint -- ruff check and ruff format --check, plus a grep gate that fails if any module under pygtfsie/ imports Home Assistant.
  • test -- pytest on Python 3.11, 3.12, 3.13 and 3.14.
  • publish -- builds and uploads to PyPI on a vMAJOR.MINOR.PATCH tag using PyPI Trusted Publishing (OIDC), so no API token is stored anywhere. The job is when: manual: tagging never publishes on its own.

Licence

Mozilla Public License 2.0. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pygtfsie-0.1.0.tar.gz (106.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pygtfsie-0.1.0-py3-none-any.whl (70.9 kB view details)

Uploaded Python 3

File details

Details for the file pygtfsie-0.1.0.tar.gz.

File metadata

  • Download URL: pygtfsie-0.1.0.tar.gz
  • Upload date:
  • Size: 106.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.15

File hashes

Hashes for pygtfsie-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9dcb7a2747892b2e09d98a9097a461f808edb2b78359822f7c00896fce3abc1b
MD5 12ff9054e521e7f56bf7e7557b94f02b
BLAKE2b-256 bb04ac40e82f3e6624b805a343b1da717799f4399743fb00a541bc0c40584e53

See more details on using hashes here.

File details

Details for the file pygtfsie-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pygtfsie-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 70.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.15

File hashes

Hashes for pygtfsie-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ca0f9c59b593bb90463f473f1928a56daf82829872139e92ba5a009f5e2f9bc9
MD5 3d08c84151d10b523e4c04b33c96e9c9
BLAKE2b-256 5b507907110de7c3a22748ad901f3c0d9d9ed4e9e8ab8ce888001a9375e7f25b

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page