caltrain-api 1.0.1__tar.gz → 1.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 (42) hide show
  1. caltrain_api-1.1.0/.github/workflows/publish.yml +73 -0
  2. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/.gitignore +3 -0
  3. caltrain_api-1.1.0/.readthedocs.yaml +22 -0
  4. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/PKG-INFO +17 -1
  5. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/README.md +10 -0
  6. caltrain_api-1.1.0/docs/api.rst +88 -0
  7. caltrain_api-1.1.0/docs/conf.py +82 -0
  8. caltrain_api-1.1.0/docs/index.md +26 -0
  9. caltrain_api-1.1.0/docs/overview.md +5 -0
  10. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/pyproject.toml +8 -1
  11. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/__init__.py +9 -2
  12. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/corridor.py +1 -1
  13. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/models.py +6 -3
  14. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/realtime.py +1 -0
  15. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/schedule.py +6 -1
  16. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/uv.lock +698 -3
  17. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/.python-version +0 -0
  18. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/LICENSE +0 -0
  19. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/docs/data-findings.md +0 -0
  20. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/_feedcache.py +0 -0
  21. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/api.py +0 -0
  22. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/describe.py +0 -0
  23. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/errors.py +0 -0
  24. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/src/caltrain_api/py.typed +0 -0
  25. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/__init__.py +0 -0
  26. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/conftest.py +0 -0
  27. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/fixtures/caltrain-gtfs-20261113.zip +0 -0
  28. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/fixtures/servicealerts-20261113-1145.pb +0 -0
  29. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/fixtures/siri-vm-20261113-1145.json +0 -0
  30. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/integration/__init__.py +0 -0
  31. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/integration/test_live.py +0 -0
  32. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/unit/__init__.py +0 -0
  33. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/unit/test_api.py +0 -0
  34. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/unit/test_corridor.py +0 -0
  35. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/unit/test_describe.py +0 -0
  36. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/unit/test_journeys.py +0 -0
  37. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/unit/test_realtime.py +0 -0
  38. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/unit/test_schedule.py +0 -0
  39. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tests/unit/test_schedule_load.py +0 -0
  40. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tools/one-off-explore-realtime.py +0 -0
  41. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tools/one-off-explore-static-gtfs.py +0 -0
  42. {caltrain_api-1.0.1 → caltrain_api-1.1.0}/tools/one-off-measure-report-lag.py +0 -0
@@ -0,0 +1,73 @@
1
+ # Publish caltrain-api to PyPI when a version tag (vX.Y.Z) is pushed.
2
+ #
3
+ # Uses PyPI Trusted Publishing (OIDC): PyPI is configured to trust this
4
+ # repository + workflow + environment, so no API token is stored anywhere.
5
+ # PyPI side: https://pypi.org/manage/project/caltrain-api/settings/publishing/
6
+ # owner: jsinnott, repository: caltrain-api, workflow: publish.yml, environment: pypi
7
+ #
8
+ # Release flow (unchanged from before, minus the manual upload):
9
+ # bump version in pyproject.toml + src/caltrain_api/__init__.py, update the
10
+ # README changelog, commit, then: git tag vX.Y.Z && git push origin vX.Y.Z
11
+
12
+ name: Publish to PyPI
13
+
14
+ on:
15
+ push:
16
+ tags: ["v*"]
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ test:
23
+ name: Test (Python ${{ matrix.python }})
24
+ runs-on: ubuntu-latest
25
+ strategy:
26
+ matrix:
27
+ python: ["3.11", "3.14"] # oldest supported and newest
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ - uses: astral-sh/setup-uv@v6
31
+ with:
32
+ python-version: ${{ matrix.python }}
33
+ - run: uv sync --extra dev
34
+ - run: uv run pytest -q tests/unit
35
+ - run: uv run mypy --strict src
36
+
37
+ build:
38
+ name: Build and check distributions
39
+ needs: test
40
+ runs-on: ubuntu-latest
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+ - uses: astral-sh/setup-uv@v6
44
+ - name: Tag must match package version
45
+ run: |
46
+ version=$(grep -m1 '^version = ' pyproject.toml | cut -d'"' -f2)
47
+ init_version=$(grep -m1 '^__version__ = ' src/caltrain_api/__init__.py | cut -d'"' -f2)
48
+ echo "tag=$GITHUB_REF_NAME pyproject=$version __init__=$init_version"
49
+ test "$GITHUB_REF_NAME" = "v$version" || { echo "::error::tag $GITHUB_REF_NAME != v$version"; exit 1; }
50
+ test "$version" = "$init_version" || { echo "::error::__version__ $init_version != $version"; exit 1; }
51
+ - run: uv build
52
+ - run: uvx twine check --strict dist/*
53
+ - uses: actions/upload-artifact@v4
54
+ with:
55
+ name: dist
56
+ path: dist/
57
+ if-no-files-found: error
58
+
59
+ publish:
60
+ name: Publish to PyPI
61
+ needs: build
62
+ runs-on: ubuntu-latest
63
+ environment:
64
+ name: pypi
65
+ url: https://pypi.org/project/caltrain-api/
66
+ permissions:
67
+ id-token: write # required for Trusted Publishing; nothing else gets it
68
+ steps:
69
+ - uses: actions/download-artifact@v4
70
+ with:
71
+ name: dist
72
+ path: dist/
73
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -30,3 +30,6 @@ Thumbs.db
30
30
 
31
31
  # Personal project notes for Claude Code (not part of the published project)
32
32
  CLAUDE.md
33
+
34
+ # Sphinx build output
35
+ docs/_build/
@@ -0,0 +1,22 @@
1
+ # Read the Docs configuration: https://docs.readthedocs.io/en/stable/config-file/v2.html
2
+ # Published at https://caltrain-api.readthedocs.io/
3
+ # "latest" follows master; "stable" and per-version builds follow vX.Y.Z tags.
4
+ version: 2
5
+
6
+ build:
7
+ os: ubuntu-24.04
8
+ tools:
9
+ python: "3.13"
10
+
11
+ sphinx:
12
+ configuration: docs/conf.py
13
+ # Same strictness as local builds: nitpicky is set in conf.py, so any
14
+ # warning (including a broken cross-reference) fails the build.
15
+ fail_on_warning: true
16
+
17
+ python:
18
+ install:
19
+ - method: pip
20
+ path: .
21
+ extra_requirements:
22
+ - docs
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: caltrain-api
3
- Version: 1.0.1
3
+ Version: 1.1.0
4
4
  Summary: Caltrain schedules and train positions (lat/lon, milepost, and plain-English) from GTFS and 511 real-time data.
5
5
  Project-URL: Homepage, https://github.com/jsinnott/caltrain-api
6
6
  Project-URL: Repository, https://github.com/jsinnott/caltrain-api
7
7
  Project-URL: Issues, https://github.com/jsinnott/caltrain-api/issues
8
+ Project-URL: Documentation, https://caltrain-api.readthedocs.io/
8
9
  Project-URL: Changelog, https://github.com/jsinnott/caltrain-api#changelog
9
10
  Author-email: Joe Sinnott <joe@jsinnott.net>
10
11
  License-Expression: MIT
@@ -31,12 +32,19 @@ Provides-Extra: dev
31
32
  Requires-Dist: mypy>=1.10; extra == 'dev'
32
33
  Requires-Dist: pytest>=8; extra == 'dev'
33
34
  Requires-Dist: types-protobuf; extra == 'dev'
35
+ Provides-Extra: docs
36
+ Requires-Dist: autodoc-pydantic>=2; extra == 'docs'
37
+ Requires-Dist: furo; extra == 'docs'
38
+ Requires-Dist: myst-parser; extra == 'docs'
39
+ Requires-Dist: sphinx<9,>=7; extra == 'docs'
34
40
  Description-Content-Type: text/markdown
35
41
 
36
42
  # caltrain-api
37
43
 
38
44
  Caltrain schedules and train positions -- latitude/longitude, milepost from SF 4th & King, and plain-English descriptions ("approaching Redwood City") -- from Caltrain's static GTFS and 511.org real-time data.
39
45
 
46
+ **Documentation:** https://caltrain-api.readthedocs.io/ (usage guide and full API reference).
47
+
40
48
  ## Install
41
49
 
42
50
  ```bash
@@ -103,10 +111,18 @@ CALTRAIN_511_API_KEY=... .venv/bin/pytest -s tests/integration # live; ~2 511
103
111
  .venv/bin/mypy --strict src
104
112
  ```
105
113
 
114
+ API docs (Sphinx, published by Read the Docs; warnings fail the build):
115
+
116
+ ```bash
117
+ uv sync --extra docs
118
+ .venv/bin/sphinx-build -W --keep-going -b html docs docs/_build/html && open docs/_build/html/index.html
119
+ ```
120
+
106
121
  Unit tests use a pinned GTFS feed and a captured 511 response (2026-11-13 11:45 PT) in `tests/fixtures/`. `tools/one-off-*.py` are survey/measurement scripts for the live data sources.
107
122
 
108
123
  ## Changelog
109
124
 
125
+ - 1.1.0 -- API documentation: Sphinx docs published at https://caltrain-api.readthedocs.io/ (`docs` extra; strict build). `ExpectedCall` is now exported from `caltrain_api` (it was already part of `TrainObservation`). Docstrings added for previously undocumented members. First release published by the GitHub Actions Trusted Publishing workflow.
110
126
  - 1.0.1 -- Packaging for PyPI: LICENSE file, project URLs, classifiers, `py.typed` marker (type checkers now use the library's annotations), README links that work on PyPI. No code changes.
111
127
  - 1.0.0 -- Stable release: the public API (everything exported from `caltrain_api`) is now covered by semantic versioning. No code changes from 0.2.1.
112
128
  - 0.2.1 -- Fix: a train waiting at its origin could be placed miles down the line, because 511 reports its equipment (often finishing a previous run) before departure. Reports no longer constrain estimates before departure, and WAITING/ARRIVED apply only near the origin/destination.
@@ -2,6 +2,8 @@
2
2
 
3
3
  Caltrain schedules and train positions -- latitude/longitude, milepost from SF 4th & King, and plain-English descriptions ("approaching Redwood City") -- from Caltrain's static GTFS and 511.org real-time data.
4
4
 
5
+ **Documentation:** https://caltrain-api.readthedocs.io/ (usage guide and full API reference).
6
+
5
7
  ## Install
6
8
 
7
9
  ```bash
@@ -68,10 +70,18 @@ CALTRAIN_511_API_KEY=... .venv/bin/pytest -s tests/integration # live; ~2 511
68
70
  .venv/bin/mypy --strict src
69
71
  ```
70
72
 
73
+ API docs (Sphinx, published by Read the Docs; warnings fail the build):
74
+
75
+ ```bash
76
+ uv sync --extra docs
77
+ .venv/bin/sphinx-build -W --keep-going -b html docs docs/_build/html && open docs/_build/html/index.html
78
+ ```
79
+
71
80
  Unit tests use a pinned GTFS feed and a captured 511 response (2026-11-13 11:45 PT) in `tests/fixtures/`. `tools/one-off-*.py` are survey/measurement scripts for the live data sources.
72
81
 
73
82
  ## Changelog
74
83
 
84
+ - 1.1.0 -- API documentation: Sphinx docs published at https://caltrain-api.readthedocs.io/ (`docs` extra; strict build). `ExpectedCall` is now exported from `caltrain_api` (it was already part of `TrainObservation`). Docstrings added for previously undocumented members. First release published by the GitHub Actions Trusted Publishing workflow.
75
85
  - 1.0.1 -- Packaging for PyPI: LICENSE file, project URLs, classifiers, `py.typed` marker (type checkers now use the library's annotations), README links that work on PyPI. No code changes.
76
86
  - 1.0.0 -- Stable release: the public API (everything exported from `caltrain_api`) is now covered by semantic versioning. No code changes from 0.2.1.
77
87
  - 0.2.1 -- Fix: a train waiting at its origin could be placed miles down the line, because 511 reports its equipment (often finishing a previous run) before departure. Reports no longer constrain estimates before departure, and WAITING/ARRIVED apply only near the origin/destination.
@@ -0,0 +1,88 @@
1
+ API reference
2
+ =============
3
+
4
+ Everything here is importable directly from ``caltrain_api`` and is covered by
5
+ semantic versioning.
6
+
7
+ .. currentmodule:: caltrain_api
8
+
9
+ Facade
10
+ ------
11
+
12
+ Most applications need only :class:`CaltrainAPI`: it combines the timetable
13
+ with real-time data and returns immutable snapshots.
14
+
15
+ .. autoclass:: CaltrainAPI
16
+
17
+ Trains and positions
18
+ --------------------
19
+
20
+ .. autopydantic_model:: Train
21
+ .. autopydantic_model:: TrainPosition
22
+ .. autopydantic_model:: Stop
23
+ .. autopydantic_model:: Departure
24
+ .. autopydantic_model:: Journey
25
+ .. autopydantic_model:: Alert
26
+
27
+ Stations and track
28
+ ------------------
29
+
30
+ .. autopydantic_model:: Station
31
+ .. autopydantic_model:: TrackLocation
32
+ .. autoclass:: Corridor
33
+
34
+ Enumerations
35
+ ------------
36
+
37
+ .. autoclass:: Direction
38
+ :members:
39
+ :undoc-members:
40
+ .. autoclass:: ServiceType
41
+ :members:
42
+ :undoc-members:
43
+ .. autoclass:: PositionSource
44
+ :members:
45
+ :undoc-members:
46
+ .. autoclass:: Relation
47
+ :members:
48
+ :undoc-members:
49
+ .. autoclass:: TrainStatus
50
+ :members:
51
+ :undoc-members:
52
+
53
+ Timetable
54
+ ---------
55
+
56
+ :class:`Schedule` works without an API key or (after the first download)
57
+ network access. :class:`CaltrainAPI` builds on it; use it directly for
58
+ timetable-only applications.
59
+
60
+ .. autoclass:: Schedule
61
+
62
+ Descriptions
63
+ ------------
64
+
65
+ .. autopydantic_model:: DescriptionPolicy
66
+
67
+ Real-time sources
68
+ -----------------
69
+
70
+ The default source is :class:`SiriRealtimeSource`. Implement
71
+ :class:`RealtimeSource` to plug in another feed.
72
+
73
+ .. autoclass:: RealtimeSource
74
+ .. autoclass:: SiriRealtimeSource
75
+ .. autopydantic_model:: RealtimeSnapshot
76
+ .. autopydantic_model:: TrainObservation
77
+ .. autopydantic_model:: ExpectedCall
78
+
79
+ Errors
80
+ ------
81
+
82
+ .. autoexception:: CaltrainError
83
+ .. autoexception:: ScheduleUnavailableError
84
+ .. autoexception:: RealtimeUnavailableError
85
+ .. autoexception:: RateLimitedError
86
+ .. autoexception:: UnknownStationError
87
+ .. autoexception:: UnknownTrainError
88
+ .. autoexception:: OffCorridorError
@@ -0,0 +1,82 @@
1
+ """Sphinx configuration for caltrain-api.
2
+
3
+ Published by Read the Docs (see .readthedocs.yaml). Build locally with the
4
+ same strictness -- any warning, including a broken cross-reference, fails:
5
+
6
+ uv sync --extra docs
7
+ .venv/bin/sphinx-build -W --keep-going -b html docs docs/_build/html
8
+ """
9
+
10
+ from importlib.metadata import version as _version
11
+
12
+ project = "caltrain-api"
13
+ author = "Joe Sinnott"
14
+ copyright = "2026, Joe Sinnott"
15
+ release = _version("caltrain-api")
16
+ version = release
17
+
18
+ extensions = [
19
+ "sphinx.ext.autodoc",
20
+ "sphinx.ext.napoleon", # Google-style Args:/Returns:/Raises: sections
21
+ "sphinx.ext.intersphinx", # links to Python / pydantic / httpx docs
22
+ "sphinx.ext.viewcode", # "[source]" links
23
+ "myst_parser", # Markdown pages (README, data findings)
24
+ "sphinxcontrib.autodoc_pydantic",
25
+ ]
26
+
27
+ exclude_patterns = ["_build"]
28
+ nitpicky = True # warn on every unresolvable reference (local and Read the Docs alike)
29
+ source_suffix = {".rst": "restructuredtext", ".md": "markdown"}
30
+
31
+ # -- autodoc -------------------------------------------------------------------
32
+ autodoc_member_order = "bysource"
33
+ autodoc_typehints = "signature"
34
+ autodoc_class_signature = "separated"
35
+ autodoc_default_options = {"members": True, "show-inheritance": True}
36
+ napoleon_google_docstring = True
37
+ napoleon_numpy_docstring = False
38
+ napoleon_use_rtype = False
39
+
40
+ # Pydantic models: list fields with their descriptions; hide JSON schema,
41
+ # config and validator noise that callers don't need.
42
+ autodoc_pydantic_model_show_json = False
43
+ autodoc_pydantic_model_show_config_summary = False
44
+ autodoc_pydantic_model_show_validator_summary = False
45
+ autodoc_pydantic_model_show_validator_members = False
46
+ autodoc_pydantic_model_show_field_summary = False
47
+ autodoc_pydantic_model_member_order = "bysource"
48
+ autodoc_pydantic_field_list_validators = False
49
+ autodoc_pydantic_field_show_constraints = True
50
+
51
+ intersphinx_mapping = {
52
+ "python": ("https://docs.python.org/3", None),
53
+ "pydantic": ("https://docs.pydantic.dev/latest", None),
54
+ # httpx's docs are MkDocs, with no Sphinx inventory to link against.
55
+ }
56
+
57
+ # Names in rendered type annotations that have no link target. They still
58
+ # display; this just stops the strict (-n) build from failing on them.
59
+ nitpick_ignore = [
60
+ ("py:class", "httpx.Client"),
61
+ ("py:class", "AwareDatetime"), # pydantic.AwareDatetime, rendered unqualified
62
+ ("py:class", "date"), # datetime.date, rendered unqualified
63
+ ("py:class", "timedelta"), # datetime.timedelta, rendered unqualified
64
+ ]
65
+
66
+
67
+ def _hide_private_bases(app, name, obj, options, bases):
68
+ """Show the internal frozen-model base class as pydantic.BaseModel."""
69
+ from pydantic import BaseModel
70
+
71
+ bases[:] = [BaseModel if b.__name__ == "_Frozen" else b for b in bases]
72
+
73
+
74
+ def setup(app):
75
+ app.connect("autodoc-process-bases", _hide_private_bases)
76
+
77
+ # -- MyST ----------------------------------------------------------------------
78
+ myst_heading_anchors = 3
79
+
80
+ # -- HTML ----------------------------------------------------------------------
81
+ html_theme = "furo"
82
+ html_title = f"caltrain-api {release}"
@@ -0,0 +1,26 @@
1
+ # caltrain-api
2
+
3
+ Caltrain schedules and train positions for Python: where every train is (latitude/longitude, milepost from San Francisco 4th & King, and plain English like "approaching Redwood City"), where it should be, departures, point-to-point timetables, delays and service alerts -- from Caltrain's static GTFS feed and 511.org real-time data.
4
+
5
+ ```bash
6
+ pip install caltrain-api
7
+ ```
8
+
9
+ ```python
10
+ from caltrain_api import CaltrainAPI
11
+
12
+ api = CaltrainAPI(api_key="...") # a free 511.org key; omit for timetable-only
13
+ for train in api.get_active_trains():
14
+ print(train.number, train.position.milepost, train.position.description)
15
+ ```
16
+
17
+ Start with the {doc}`overview` (usage, positions, data handling), then the {doc}`api` for every class and method. {doc}`data-findings` records what the data sources actually provide and how that shaped the design.
18
+
19
+ ```{toctree}
20
+ :maxdepth: 2
21
+ :hidden:
22
+
23
+ overview
24
+ api
25
+ data-findings
26
+ ```
@@ -0,0 +1,5 @@
1
+ # Overview
2
+
3
+ ```{include} ../README.md
4
+ :start-after: "# caltrain-api"
5
+ ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "caltrain-api"
7
- version = "1.0.1"
7
+ version = "1.1.0"
8
8
  description = "Caltrain schedules and train positions (lat/lon, milepost, and plain-English) from GTFS and 511 real-time data."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -37,6 +37,7 @@ dependencies = [
37
37
  Homepage = "https://github.com/jsinnott/caltrain-api"
38
38
  Repository = "https://github.com/jsinnott/caltrain-api"
39
39
  Issues = "https://github.com/jsinnott/caltrain-api/issues"
40
+ Documentation = "https://caltrain-api.readthedocs.io/"
40
41
  Changelog = "https://github.com/jsinnott/caltrain-api#changelog"
41
42
 
42
43
  [project.optional-dependencies]
@@ -45,6 +46,12 @@ dev = [
45
46
  "mypy>=1.10",
46
47
  "types-protobuf",
47
48
  ]
49
+ docs = [
50
+ "sphinx>=7,<9", # autodoc-pydantic 2.2 drops model properties/methods under Sphinx 9
51
+ "furo",
52
+ "myst-parser",
53
+ "autodoc-pydantic>=2",
54
+ ]
48
55
 
49
56
  [tool.hatch.build.targets.wheel]
50
57
  packages = ["src/caltrain_api"]
@@ -4,7 +4,7 @@ Public API -- everything importable from ``caltrain_api`` directly is covered
4
4
  by semantic versioning; submodule internals are not.
5
5
  """
6
6
 
7
- __version__ = "1.0.1"
7
+ __version__ = "1.1.0"
8
8
 
9
9
  from .api import CaltrainAPI
10
10
  from .corridor import Corridor
@@ -33,7 +33,13 @@ from .models import (
33
33
  TrainPosition,
34
34
  TrainStatus,
35
35
  )
36
- from .realtime import RealtimeSnapshot, RealtimeSource, SiriRealtimeSource, TrainObservation
36
+ from .realtime import (
37
+ ExpectedCall,
38
+ RealtimeSnapshot,
39
+ RealtimeSource,
40
+ SiriRealtimeSource,
41
+ TrainObservation,
42
+ )
37
43
  from .schedule import Schedule
38
44
 
39
45
  __all__ = [
@@ -45,6 +51,7 @@ __all__ = [
45
51
  "Journey",
46
52
  "DescriptionPolicy",
47
53
  "Direction",
54
+ "ExpectedCall",
48
55
  "OffCorridorError",
49
56
  "PositionSource",
50
57
  "RateLimitedError",
@@ -92,7 +92,7 @@ class _Polyline:
92
92
  class Corridor:
93
93
  """The Caltrain line as a single measured polyline.
94
94
 
95
- Obtain one from :attr:`Schedule.corridor`; constructing directly is for tests.
95
+ Obtain one from :attr:`~caltrain_api.Schedule.corridor`; constructing directly is for tests.
96
96
  Immutable and safe to share between threads.
97
97
  """
98
98
 
@@ -151,12 +151,12 @@ class Stop(_Frozen):
151
151
 
152
152
  @property
153
153
  def arrival(self) -> datetime:
154
- """Best available arrival time: expected if known, else scheduled."""
154
+ """The best available arrival time (expected if known, else scheduled)."""
155
155
  return self.expected_arrival or self.scheduled_arrival
156
156
 
157
157
  @property
158
158
  def departure(self) -> datetime:
159
- """Best available departure time: expected if known, else scheduled."""
159
+ """The best available departure time (expected if known, else scheduled)."""
160
160
  return self.expected_departure or self.scheduled_departure
161
161
 
162
162
  @property
@@ -173,7 +173,7 @@ class TrainPosition(TrackLocation):
173
173
  A ``TrackLocation`` plus when, how we know, and how it relates to stations.
174
174
  ``station``/``previous_station``/``next_station`` refer to *physical*
175
175
  neighbors along the track, including stations the train does not stop at;
176
- use :attr:`Train.next_stop` for the next station it will serve.
176
+ use :attr:`~caltrain_api.Train.next_stop` for the next station it will serve.
177
177
  """
178
178
 
179
179
  source: PositionSource
@@ -263,10 +263,12 @@ class Train(_Frozen):
263
263
 
264
264
  @property
265
265
  def origin(self) -> Station:
266
+ """The station the trip starts from."""
266
267
  return self.stops[0].station
267
268
 
268
269
  @property
269
270
  def destination(self) -> Station:
271
+ """The station the trip ends at."""
270
272
  return self.stops[-1].station
271
273
 
272
274
  @property
@@ -315,6 +317,7 @@ class Journey(_Frozen):
315
317
 
316
318
  @property
317
319
  def scheduled_duration(self) -> timedelta:
320
+ """Timetable duration, origin departure to destination arrival."""
318
321
  return self.destination_stop.scheduled_arrival - self.origin_stop.scheduled_departure
319
322
 
320
323
  @property
@@ -290,6 +290,7 @@ class SiriRealtimeSource:
290
290
  return resp.content
291
291
 
292
292
  def fetch(self) -> RealtimeSnapshot:
293
+ """Fetch train data (and alerts, if due) from 511. See :meth:`RealtimeSource.fetch`."""
293
294
  now = self._clock()
294
295
  raw = self._get(self.VEHICLE_MONITORING_URL, "VehicleMonitoring", format="json")
295
296
  try:
@@ -451,14 +451,17 @@ class Schedule:
451
451
 
452
452
  @property
453
453
  def feed_version(self) -> str:
454
+ """The feed's ``feed_version`` from ``feed_info.txt`` (or ``"unknown"``)."""
454
455
  return self._feed_version
455
456
 
456
457
  @property
457
458
  def valid_from(self) -> date:
459
+ """First service date the feed covers (``feed_start_date``, else the calendar's earliest)."""
458
460
  return self._valid_from
459
461
 
460
462
  @property
461
463
  def valid_until(self) -> date:
464
+ """Last service date the feed covers; past it, :meth:`load` re-downloads."""
462
465
  return self._valid_until
463
466
 
464
467
  @property
@@ -468,10 +471,12 @@ class Schedule:
468
471
 
469
472
  @property
470
473
  def corridor(self) -> Corridor:
474
+ """The measured SF -> Gilroy track used for all mileposts."""
471
475
  return self._corridor
472
476
 
473
477
  @property
474
478
  def description_policy(self) -> DescriptionPolicy:
479
+ """Thresholds and wording used for position descriptions."""
475
480
  return self._policy
476
481
 
477
482
  # -- stations -----------------------------------------------------------
@@ -690,7 +695,7 @@ class Schedule:
690
695
  The relation is WAITING before the origin departure (by best-available
691
696
  times) and ARRIVED from the destination arrival on -- in both cases
692
697
  only within ``near_radius`` of that station -- and otherwise
693
- classified by :attr:`description_policy`.
698
+ classified by :attr:`~caltrain_api.Schedule.description_policy`.
694
699
 
695
700
  Args:
696
701
  stops: The train's stops (determine AT vs PASSING and WAITING/ARRIVED).