feat: vvspy removel - uv - tests - #43
Conversation
There was a problem hiding this comment.
Pull request overview
This PR migrates the service away from the third-party vvspy client and requirements.txt to a small in-repo VVS EFA client built on the Python standard library, while also adopting uv for dependency management and adding a full unittest suite around parsing and response shaping.
Changes:
- Replace
vvspy-based trip lookup withservice.vvs_client+ shared shaping helpers, updating v1/v2 services accordingly. - Add comprehensive unittests + JSON fixtures for parser, shared helpers, and v1/v2 shaping behavior.
- Switch dependency/build workflow to
uv(pyproject.toml,uv.lock, Dockerfile updates) and update docs/platform targets.
Reviewed changes
Copilot reviewed 16 out of 20 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Adds the committed uv lockfile for reproducible dependency resolution. |
pyproject.toml |
Defines project metadata and runtime dependencies for uv-managed installs. |
.python-version |
Pins Python 3.13 for consistent local/dev and uv interpreter selection. |
requirements.txt |
Removes legacy pip requirements pinning (replaced by pyproject.toml + uv.lock). |
Dockerfile |
Updates to a two-stage build using the uv builder image and copies a prebuilt venv into runtime. |
.dockerignore |
Prevents shipping local venvs/uv cache into the Docker build context. |
.github/workflows/docker.yml |
Drops linux/arm/v7 from the published image platforms. |
README.md |
Updates docs for direct EFA usage, uv workflows, and fixes *_planed → *_planned in examples. |
.gitignore |
Removes ignoring of .python-version and documents why it’s committed. |
service/vvs_client.py |
New standard-library HTTP client + parser producing immutable value objects (Stop, Leg, Trip). |
service/_shared.py |
New pure helpers for timestamp formatting and shaping predicates used by v1/v2. |
service/v1.py |
Reimplements v1 shaping using the new client/helpers (single-leg filtering). |
service/v2.py |
Reimplements v2 shaping for multi-leg journeys, stripping walking legs and incomplete legs. |
app.py |
Refactors Flask entrypoint, configuration, and response envelopes; wires to new v1/v2 services. |
tests/test_vvs_client.py |
Tests parser + URL builder/station-id normalization. |
tests/test_shared.py |
Tests _shared helper behavior (formatting/predicates/minutes math). |
tests/test_v1.py |
Tests v1 filtering and shaping behavior, including partial-payload robustness. |
tests/test_v2.py |
Tests v2 filtering/shaping behavior including walking-leg stripping and partial-payload robustness. |
tests/fixtures/trip_response.json |
Adds a canned multi-journey payload fixture used across tests. |
tests/__init__.py |
Adds tests package marker. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Exposes :func:`find_trips`, which queries the VVS EFA endpoint and | ||
| returns only those journeys that consist of exactly one leg -- i.e. | ||
| no interchange, no walking transfer. Each returned trip is shaped as | ||
| a JSON-serialisable ``dict`` suitable for the ``/api/v1/`` endpoint. |
| def _force_json_content_type(response: Response) -> Response: | ||
| """Ensure every response advertises ``application/json``. | ||
|
|
||
| Flask's :func:`jsonify` already sets this header, but the hook | ||
| guarantees the behaviour even for custom responses added in the | ||
| future. | ||
| """ | ||
| response.headers["Content-Type"] = "application/json" | ||
| return response |
Removed redundant phrase about third-party VVS client.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 20 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
service/v1.py:6
- The module docstring claims v1 returns “no walking transfer”, but the implementation and tests allow single-leg walking-only trips (line_number/number can be None). This makes the documentation inaccurate for API consumers.
Exposes :func:`find_trips`, which queries the VVS EFA endpoint and
returns only those journeys that consist of exactly one leg -- i.e.
no interchange, no walking transfer. Each returned trip is shaped as
a JSON-serialisable ``dict`` suitable for the ``/api/v1/`` endpoint.
app.py:137
- This hook forcibly sets
Content-Type: application/jsonfor all responses, including default Flask 404/405 HTML error pages, which makes the declared content type inaccurate. Either return JSON for those errors or avoid overriding an already-set content type.
@app.after_request
def _force_json_content_type(response: Response) -> Response:
"""Ensure every response advertises ``application/json``.
Flask's :func:`jsonify` already sets this header, but the hook
guarantees the behaviour even for custom responses added in the
future.
"""
response.headers["Content-Type"] = "application/json"
return response
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 21 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
service/v1.py:6
- The module docstring claims v1 returns only single-leg journeys with “no walking transfer”, but the implementation intentionally allows single-leg walk-only trips (line_number is None) as confirmed by tests (tests/test_v1.py). This docstring is misleading for API consumers and future maintainers.
Exposes :func:`find_trips`, which queries the VVS EFA endpoint and
returns only those journeys that consist of exactly one leg -- i.e.
no interchange, no walking transfer. Each returned trip is shaped as
a JSON-serialisable ``dict`` suitable for the ``/api/v1/`` endpoint.
No description provided.