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 checkandruff format --check, plus a grep gate that fails if any module underpygtfsie/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.PATCHtag using PyPI Trusted Publishing (OIDC), so no API token is stored anywhere. The job iswhen: 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9dcb7a2747892b2e09d98a9097a461f808edb2b78359822f7c00896fce3abc1b
|
|
| MD5 |
12ff9054e521e7f56bf7e7557b94f02b
|
|
| BLAKE2b-256 |
bb04ac40e82f3e6624b805a343b1da717799f4399743fb00a541bc0c40584e53
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca0f9c59b593bb90463f473f1928a56daf82829872139e92ba5a009f5e2f9bc9
|
|
| MD5 |
3d08c84151d10b523e4c04b33c96e9c9
|
|
| BLAKE2b-256 |
5b507907110de7c3a22748ad901f3c0d9d9ed4e9e8ab8ce888001a9375e7f25b
|