gtfs-hub 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. gtfs_hub-0.1.0/.gitignore +10 -0
  2. gtfs_hub-0.1.0/CHANGELOG.md +14 -0
  3. gtfs_hub-0.1.0/LICENSE +21 -0
  4. gtfs_hub-0.1.0/PKG-INFO +146 -0
  5. gtfs_hub-0.1.0/README.md +120 -0
  6. gtfs_hub-0.1.0/pyproject.toml +75 -0
  7. gtfs_hub-0.1.0/scripts/check_agnostic.py +28 -0
  8. gtfs_hub-0.1.0/src/gtfs_hub/__init__.py +91 -0
  9. gtfs_hub-0.1.0/src/gtfs_hub/catalogue.py +290 -0
  10. gtfs_hub-0.1.0/src/gtfs_hub/departures.py +272 -0
  11. gtfs_hub-0.1.0/src/gtfs_hub/discovery.py +33 -0
  12. gtfs_hub-0.1.0/src/gtfs_hub/download.py +44 -0
  13. gtfs_hub-0.1.0/src/gtfs_hub/errors.py +29 -0
  14. gtfs_hub-0.1.0/src/gtfs_hub/generic.py +52 -0
  15. gtfs_hub-0.1.0/src/gtfs_hub/hub.py +432 -0
  16. gtfs_hub-0.1.0/src/gtfs_hub/importer.py +538 -0
  17. gtfs_hub-0.1.0/src/gtfs_hub/models.py +220 -0
  18. gtfs_hub-0.1.0/src/gtfs_hub/provider.py +106 -0
  19. gtfs_hub-0.1.0/src/gtfs_hub/py.typed +0 -0
  20. gtfs_hub-0.1.0/src/gtfs_hub/realtime.py +155 -0
  21. gtfs_hub-0.1.0/src/gtfs_hub/schema.py +152 -0
  22. gtfs_hub-0.1.0/src/gtfs_hub/shapes.py +91 -0
  23. gtfs_hub-0.1.0/src/gtfs_hub/snapshots.py +32 -0
  24. gtfs_hub-0.1.0/src/gtfs_hub/text.py +11 -0
  25. gtfs_hub-0.1.0/tests/conftest.py +132 -0
  26. gtfs_hub-0.1.0/tests/test_catalogue.py +220 -0
  27. gtfs_hub-0.1.0/tests/test_contract.py +123 -0
  28. gtfs_hub-0.1.0/tests/test_departures.py +225 -0
  29. gtfs_hub-0.1.0/tests/test_generic.py +49 -0
  30. gtfs_hub-0.1.0/tests/test_import.py +371 -0
  31. gtfs_hub-0.1.0/tests/test_package.py +5 -0
  32. gtfs_hub-0.1.0/tests/test_readme.py +52 -0
  33. gtfs_hub-0.1.0/tests/test_realtime.py +385 -0
  34. gtfs_hub-0.1.0/tests/test_shapes.py +314 -0
  35. gtfs_hub-0.1.0/tests/test_snapshots.py +397 -0
  36. gtfs_hub-0.1.0/tests/test_vehicles.py +174 -0
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ .mypy_cache/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ .DS_Store
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ All notable changes are listed here. Versions follow [Semantic Versioning](https://semver.org/); below 1.0, a breaking change to the API, the provider contract or the database schema bumps the minor version.
4
+
5
+ ## 0.1.0 - 2026-11-11
6
+
7
+ First public release.
8
+
9
+ - Local SQLite copy of a GTFS schedule, sized by the selected lines, with snapshots, coverage checks and safe rebuilds.
10
+ - Departures joined with GTFS Realtime trip updates, including night service past 24:00, cancellations and skipped stops.
11
+ - Vehicle positions of selected lines, and service alerts.
12
+ - Route shapes of selected lines, and locating a position on a shape.
13
+ - `GenericProvider` for plain URLs, and the `gtfs_hub.providers` entry point group for provider packages.
14
+ - Typed errors deriving from `GtfsError`.
gtfs_hub-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 grozycki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.5
2
+ Name: gtfs-hub
3
+ Version: 0.1.0
4
+ Summary: Provider-agnostic GTFS schedule library for low-memory hardware
5
+ Project-URL: Homepage, https://github.com/grozycki/gtfs-hub
6
+ Project-URL: Issues, https://github.com/grozycki/gtfs-hub/issues
7
+ Project-URL: Changelog, https://github.com/grozycki/gtfs-hub/blob/main/CHANGELOG.md
8
+ Author: grozycki
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: gtfs,gtfs-realtime,public-transport,timetable,transit
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Framework :: AsyncIO
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.13
23
+ Requires-Dist: aiohttp>=3.10
24
+ Requires-Dist: gtfs-realtime-bindings>=1.0
25
+ Description-Content-Type: text/markdown
26
+
27
+ # gtfs-hub
28
+
29
+ Provider-agnostic GTFS schedule library for low-memory hardware. It keeps a local SQLite copy of a schedule, sized by the lines you select rather than by the size of the feed.
30
+
31
+ Requires Python 3.13 or newer.
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install gtfs-hub
37
+ ```
38
+
39
+ Versions follow [Semantic Versioning](https://semver.org/); below 1.0, a breaking change to the API, the provider contract or the database schema bumps the minor version. See the [changelog](CHANGELOG.md).
40
+
41
+ ## Usage
42
+
43
+ Any standard source works from plain URLs, through `GenericProvider`. Pass your own `aiohttp` session: the library never creates one.
44
+
45
+ ```python
46
+ from pathlib import Path
47
+
48
+ from aiohttp import ClientSession
49
+
50
+ from gtfs_hub import GenericProvider, GtfsHub, LineKey
51
+
52
+
53
+ async def main(url: str, database: Path) -> None:
54
+ async with ClientSession() as session:
55
+ hub = GtfsHub(GenericProvider([url]), database, session)
56
+
57
+ # The first sync with no lines fills the searchable catalogue.
58
+ await hub.async_sync([])
59
+ lines = await hub.async_search_lines("11")
60
+
61
+ # Timetables are stored only for selected lines.
62
+ selection = [line.key for line in lines]
63
+ await hub.async_sync(selection)
64
+
65
+ for key in selection:
66
+ stops = await hub.async_stops_of_line(key)
67
+ print(LineKey(key.route_type, key.short_name), [stop.name for stop in stops])
68
+ ```
69
+
70
+ Call `async_sync` with the full selection whenever the source may have changed or the selection did. Lines that are new are imported, lines that are gone are removed, and unchanged files are not downloaded. On failure it raises a `GtfsError`, and the previous database stays in use. The database is a cache, so it is safe to delete: the next sync rebuilds it.
71
+
72
+ ## Departures
73
+
74
+ Fetch realtime once per poll, and pass it to each departures call. A failed fetch only means passing `None`: the schedule still answers.
75
+
76
+ ```python
77
+ from gtfs_hub import GtfsError, GtfsHub
78
+
79
+
80
+ async def show_departures(hub: GtfsHub, stop_key: str) -> None:
81
+ try:
82
+ realtime = await hub.async_fetch_realtime()
83
+ except GtfsError:
84
+ realtime = None
85
+ for departure in await hub.async_departures(stop_key, realtime=realtime, limit=5):
86
+ print(departure.line.short_name, departure.headsign, departure.expected, departure.status)
87
+ ```
88
+
89
+ Departures cover the lines stored by the last sync, on every service date reaching the period, including night service past 24:00. Times are in UTC. `scheduled` is always set, while `predicted` and `delay` stay `None` without a usable update, so "no data" never reads as "on time". Stops a running trip has passed give no departure, and points where riders cannot board give none either. Realtime older than `max_age` (5 minutes by default) is ignored, and `RealtimeData.is_stale` tells a consumer so. When no snapshot covers today, `async_departures` raises `GtfsNoDataError`.
90
+
91
+ Trips in `frequencies.txt` are not supported and are left out, with a log line.
92
+
93
+ ## Shapes
94
+
95
+ When a source publishes `shapes.txt`, the paths of selected lines are stored with their timetables. `async_line_shapes(key, service_date=None)` returns each distinct path of a line, with its points in order, its direction and the most common headsign of its trips. With a service date, only the snapshot serving that date counts, so other days' variants stay out. A broken `shapes.txt` costs only the paths, never the timetables. Vehicles carry the `shape` of their trip.
96
+
97
+ `locate(shape, latitude, longitude, after=None)` places a position on a path: metres along it, metres off it, and the bearing of the path there. A position more than 60 m off has no location. Pass the previous `along` of the same trip as `after`, so a path that runs one street both ways resolves to the pass ahead; without it, such a position has no location rather than a guess.
98
+
99
+ ## Generic provider
100
+
101
+ | Argument | Meaning |
102
+ |---|---|
103
+ | `schedule_urls` | One or more ZIP files, each treated as one snapshot |
104
+ | `trip_updates_url`, `vehicle_positions_url`, `alerts_url` | Optional realtime endpoints |
105
+ | `headers` | Optional headers for realtime requests |
106
+ | `stop_key` | `stop_id` by default, or `stop_code` when that is the stable field |
107
+ | `name`, `attribution` | Display name, and the licence text consumers must show |
108
+
109
+ It reports no capabilities and no vehicle identity until a source has been surveyed.
110
+
111
+ ## Keys
112
+
113
+ - **Lines** are `LineKey(route_type, short_name)`. Store this, never a `route_id`.
114
+ - **Stops** are the value of the provider's `stop_key` field. One key can resolve to several `stop_id` values.
115
+ - `Line.url` and `Stop.url` carry `route_url` and `stop_url` when the source fills them.
116
+ - Empty results from `async_resolve_line` and `async_resolve_stop` mean the key is in no current snapshot.
117
+
118
+ ## Coverage
119
+
120
+ `async_snapshot_for(date)` picks the newest snapshot for a service date. `async_missing_dates(start, end)` reports dates no snapshot covers, which differ from dates without service.
121
+
122
+ ## Errors
123
+
124
+ | Error | Meaning |
125
+ |---|---|
126
+ | `GtfsConnectionError` | Temporary failure: retry later |
127
+ | `GtfsRateLimitError` | Slow down, with `retry_after` in seconds when known |
128
+ | `GtfsAuthError` | The source rejected the credentials |
129
+ | `GtfsFeedError` | Bad or unusable data |
130
+ | `GtfsNoDataError` | No usable database yet: run a sync |
131
+
132
+ All derive from `GtfsError`.
133
+
134
+ ## Writing a provider
135
+
136
+ A package is needed only when finding or reading the data takes code. Subclass `BaseProvider`, implement `async_list_static_feeds`, and register a factory in the `gtfs_hub.providers` entry point group, with the provider key as its name.
137
+
138
+ ## Development
139
+
140
+ ```bash
141
+ uv sync
142
+ ```
143
+
144
+ ```bash
145
+ uv run pytest
146
+ ```
@@ -0,0 +1,120 @@
1
+ # gtfs-hub
2
+
3
+ Provider-agnostic GTFS schedule library for low-memory hardware. It keeps a local SQLite copy of a schedule, sized by the lines you select rather than by the size of the feed.
4
+
5
+ Requires Python 3.13 or newer.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install gtfs-hub
11
+ ```
12
+
13
+ Versions follow [Semantic Versioning](https://semver.org/); below 1.0, a breaking change to the API, the provider contract or the database schema bumps the minor version. See the [changelog](CHANGELOG.md).
14
+
15
+ ## Usage
16
+
17
+ Any standard source works from plain URLs, through `GenericProvider`. Pass your own `aiohttp` session: the library never creates one.
18
+
19
+ ```python
20
+ from pathlib import Path
21
+
22
+ from aiohttp import ClientSession
23
+
24
+ from gtfs_hub import GenericProvider, GtfsHub, LineKey
25
+
26
+
27
+ async def main(url: str, database: Path) -> None:
28
+ async with ClientSession() as session:
29
+ hub = GtfsHub(GenericProvider([url]), database, session)
30
+
31
+ # The first sync with no lines fills the searchable catalogue.
32
+ await hub.async_sync([])
33
+ lines = await hub.async_search_lines("11")
34
+
35
+ # Timetables are stored only for selected lines.
36
+ selection = [line.key for line in lines]
37
+ await hub.async_sync(selection)
38
+
39
+ for key in selection:
40
+ stops = await hub.async_stops_of_line(key)
41
+ print(LineKey(key.route_type, key.short_name), [stop.name for stop in stops])
42
+ ```
43
+
44
+ Call `async_sync` with the full selection whenever the source may have changed or the selection did. Lines that are new are imported, lines that are gone are removed, and unchanged files are not downloaded. On failure it raises a `GtfsError`, and the previous database stays in use. The database is a cache, so it is safe to delete: the next sync rebuilds it.
45
+
46
+ ## Departures
47
+
48
+ Fetch realtime once per poll, and pass it to each departures call. A failed fetch only means passing `None`: the schedule still answers.
49
+
50
+ ```python
51
+ from gtfs_hub import GtfsError, GtfsHub
52
+
53
+
54
+ async def show_departures(hub: GtfsHub, stop_key: str) -> None:
55
+ try:
56
+ realtime = await hub.async_fetch_realtime()
57
+ except GtfsError:
58
+ realtime = None
59
+ for departure in await hub.async_departures(stop_key, realtime=realtime, limit=5):
60
+ print(departure.line.short_name, departure.headsign, departure.expected, departure.status)
61
+ ```
62
+
63
+ Departures cover the lines stored by the last sync, on every service date reaching the period, including night service past 24:00. Times are in UTC. `scheduled` is always set, while `predicted` and `delay` stay `None` without a usable update, so "no data" never reads as "on time". Stops a running trip has passed give no departure, and points where riders cannot board give none either. Realtime older than `max_age` (5 minutes by default) is ignored, and `RealtimeData.is_stale` tells a consumer so. When no snapshot covers today, `async_departures` raises `GtfsNoDataError`.
64
+
65
+ Trips in `frequencies.txt` are not supported and are left out, with a log line.
66
+
67
+ ## Shapes
68
+
69
+ When a source publishes `shapes.txt`, the paths of selected lines are stored with their timetables. `async_line_shapes(key, service_date=None)` returns each distinct path of a line, with its points in order, its direction and the most common headsign of its trips. With a service date, only the snapshot serving that date counts, so other days' variants stay out. A broken `shapes.txt` costs only the paths, never the timetables. Vehicles carry the `shape` of their trip.
70
+
71
+ `locate(shape, latitude, longitude, after=None)` places a position on a path: metres along it, metres off it, and the bearing of the path there. A position more than 60 m off has no location. Pass the previous `along` of the same trip as `after`, so a path that runs one street both ways resolves to the pass ahead; without it, such a position has no location rather than a guess.
72
+
73
+ ## Generic provider
74
+
75
+ | Argument | Meaning |
76
+ |---|---|
77
+ | `schedule_urls` | One or more ZIP files, each treated as one snapshot |
78
+ | `trip_updates_url`, `vehicle_positions_url`, `alerts_url` | Optional realtime endpoints |
79
+ | `headers` | Optional headers for realtime requests |
80
+ | `stop_key` | `stop_id` by default, or `stop_code` when that is the stable field |
81
+ | `name`, `attribution` | Display name, and the licence text consumers must show |
82
+
83
+ It reports no capabilities and no vehicle identity until a source has been surveyed.
84
+
85
+ ## Keys
86
+
87
+ - **Lines** are `LineKey(route_type, short_name)`. Store this, never a `route_id`.
88
+ - **Stops** are the value of the provider's `stop_key` field. One key can resolve to several `stop_id` values.
89
+ - `Line.url` and `Stop.url` carry `route_url` and `stop_url` when the source fills them.
90
+ - Empty results from `async_resolve_line` and `async_resolve_stop` mean the key is in no current snapshot.
91
+
92
+ ## Coverage
93
+
94
+ `async_snapshot_for(date)` picks the newest snapshot for a service date. `async_missing_dates(start, end)` reports dates no snapshot covers, which differ from dates without service.
95
+
96
+ ## Errors
97
+
98
+ | Error | Meaning |
99
+ |---|---|
100
+ | `GtfsConnectionError` | Temporary failure: retry later |
101
+ | `GtfsRateLimitError` | Slow down, with `retry_after` in seconds when known |
102
+ | `GtfsAuthError` | The source rejected the credentials |
103
+ | `GtfsFeedError` | Bad or unusable data |
104
+ | `GtfsNoDataError` | No usable database yet: run a sync |
105
+
106
+ All derive from `GtfsError`.
107
+
108
+ ## Writing a provider
109
+
110
+ A package is needed only when finding or reading the data takes code. Subclass `BaseProvider`, implement `async_list_static_feeds`, and register a factory in the `gtfs_hub.providers` entry point group, with the provider key as its name.
111
+
112
+ ## Development
113
+
114
+ ```bash
115
+ uv sync
116
+ ```
117
+
118
+ ```bash
119
+ uv run pytest
120
+ ```
@@ -0,0 +1,75 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.25"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "gtfs-hub"
7
+ version = "0.1.0"
8
+ description = "Provider-agnostic GTFS schedule library for low-memory hardware"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.13"
12
+ authors = [{ name = "grozycki" }]
13
+ keywords = ["gtfs", "gtfs-realtime", "public-transport", "transit", "timetable"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Framework :: AsyncIO",
17
+ "Intended Audience :: Developers",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Programming Language :: Python :: 3.14",
23
+ "Topic :: Software Development :: Libraries",
24
+ "Typing :: Typed",
25
+ ]
26
+ dependencies = ["aiohttp>=3.10", "gtfs-realtime-bindings>=1.0"]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/grozycki/gtfs-hub"
30
+ Issues = "https://github.com/grozycki/gtfs-hub/issues"
31
+ Changelog = "https://github.com/grozycki/gtfs-hub/blob/main/CHANGELOG.md"
32
+
33
+ [dependency-groups]
34
+ dev = [
35
+ "mypy>=1.13",
36
+ "pytest>=8.3",
37
+ "pytest-asyncio>=0.24",
38
+ "ruff>=0.8",
39
+ "types-protobuf>=5.0",
40
+ ]
41
+
42
+ [tool.hatch.build.targets.wheel]
43
+ packages = ["src/gtfs_hub"]
44
+
45
+ [tool.hatch.build.targets.sdist]
46
+ include = ["src", "tests", "scripts", "README.md", "CHANGELOG.md", "LICENSE"]
47
+
48
+ [tool.pytest.ini_options]
49
+ asyncio_mode = "auto"
50
+ asyncio_default_fixture_loop_scope = "function"
51
+ testpaths = ["tests"]
52
+
53
+ [tool.ruff]
54
+ line-length = 100
55
+ src = ["src", "tests"]
56
+
57
+ [tool.ruff.lint]
58
+ select = ["E", "F", "I", "UP", "B", "SIM", "RUF", "ANN", "TC", "PYI"]
59
+
60
+ [tool.mypy]
61
+ strict = true
62
+ files = ["src", "scripts", "tests"]
63
+ warn_unreachable = true
64
+ disallow_any_explicit = true
65
+ disallow_any_unimported = true
66
+ enable_error_code = [
67
+ "deprecated",
68
+ "explicit-override",
69
+ "ignore-without-code",
70
+ "possibly-undefined",
71
+ "redundant-expr",
72
+ "redundant-self",
73
+ "truthy-bool",
74
+ "unused-awaitable",
75
+ ]
@@ -0,0 +1,28 @@
1
+ """Fail when the core package mentions a specific agency."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ FORBIDDEN = ("gzm", "ztm", "metropolia", "transportgzm", "otwartedane")
7
+
8
+
9
+ def find_violations(root: Path) -> list[str]:
10
+ """Return one line per forbidden term found under root."""
11
+ violations = []
12
+ for path in sorted(root.rglob("*.py")):
13
+ text = path.read_text(encoding="utf-8")
14
+ for number, line in enumerate(text.splitlines(), start=1):
15
+ lowered = line.lower()
16
+ violations += [f"{path}:{number}: {term}" for term in FORBIDDEN if term in lowered]
17
+ return violations
18
+
19
+
20
+ def main() -> int:
21
+ root = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("src/gtfs_hub")
22
+ violations = find_violations(root)
23
+ print("\n".join(violations) or f"{root}: no agency names")
24
+ return 1 if violations else 0
25
+
26
+
27
+ if __name__ == "__main__":
28
+ raise SystemExit(main())
@@ -0,0 +1,91 @@
1
+ """Provider-agnostic GTFS schedule library."""
2
+
3
+ from .discovery import (
4
+ async_create_provider,
5
+ async_list_provider_keys,
6
+ create_provider,
7
+ list_provider_keys,
8
+ )
9
+ from .download import raise_for_status
10
+ from .errors import (
11
+ GtfsAuthError,
12
+ GtfsConnectionError,
13
+ GtfsError,
14
+ GtfsFeedError,
15
+ GtfsNoDataError,
16
+ GtfsRateLimitError,
17
+ )
18
+ from .generic import GenericProvider
19
+ from .hub import GtfsHub
20
+ from .models import (
21
+ Capabilities,
22
+ Departure,
23
+ DepartureStatus,
24
+ Line,
25
+ LineKey,
26
+ Livery,
27
+ RealtimeEndpoints,
28
+ ResolvedId,
29
+ Shape,
30
+ ShapeId,
31
+ ShapeLocation,
32
+ Snapshot,
33
+ StaticFeedRef,
34
+ Stop,
35
+ StopChoice,
36
+ StopKey,
37
+ StopKeyField,
38
+ SyncResult,
39
+ TripDelay,
40
+ TripId,
41
+ Vehicle,
42
+ VehicleClass,
43
+ VehicleKey,
44
+ )
45
+ from .provider import BaseProvider, Provider, TableReader
46
+ from .realtime import RealtimeData
47
+ from .shapes import locate
48
+
49
+ __all__ = [
50
+ "BaseProvider",
51
+ "Capabilities",
52
+ "Departure",
53
+ "DepartureStatus",
54
+ "GenericProvider",
55
+ "GtfsAuthError",
56
+ "GtfsConnectionError",
57
+ "GtfsError",
58
+ "GtfsFeedError",
59
+ "GtfsHub",
60
+ "GtfsNoDataError",
61
+ "GtfsRateLimitError",
62
+ "Line",
63
+ "LineKey",
64
+ "Livery",
65
+ "Provider",
66
+ "RealtimeData",
67
+ "RealtimeEndpoints",
68
+ "ResolvedId",
69
+ "Shape",
70
+ "ShapeId",
71
+ "ShapeLocation",
72
+ "Snapshot",
73
+ "StaticFeedRef",
74
+ "Stop",
75
+ "StopChoice",
76
+ "StopKey",
77
+ "StopKeyField",
78
+ "SyncResult",
79
+ "TableReader",
80
+ "TripDelay",
81
+ "TripId",
82
+ "Vehicle",
83
+ "VehicleClass",
84
+ "VehicleKey",
85
+ "async_create_provider",
86
+ "async_list_provider_keys",
87
+ "create_provider",
88
+ "list_provider_keys",
89
+ "locate",
90
+ "raise_for_status",
91
+ ]