Fix CI fallout from the samples submodule move, pin the ruff rule set, update deps - #39
Conversation
The "Samples moved to submodule" commit deleted samples/ but nothing was
updated to read from gpxsamples/, leaving 14 failures and 13 collection
errors. Sample data is now split by size and role:
* gpxsamples/ (submodule) - the large .gpx inputs
* samples/ (this repo) - the small golden .txt outputs and
default-config.json, which the docs include
tests/conftest.py owns both paths and fails collection with an actionable
message when the submodule was never initialized, instead of a pile of
FileNotFoundErrors.
Also make the suite independent of the invoking environment: use
sys.executable rather than whatever "python" resolves to on PATH, and
absolute sample paths rather than cwd-relative ones.
samples/default-config.json had drifted from the code (it still carried a
"\Dinner" typo fixed since), so --dump-config is now regenerated by
--generate and asserted by a test to keep the documented config honest.
The golden .txt files regenerate byte-identical, confirming no behavior
change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xk6gQpcHHxmQ4KBUjYhKr9
actions/checkout does not fetch submodules by default, so the test job had no GPX inputs to run against. Only the test job needs them; lint and the GAE deploy do not. Add a "make submodules" target that the test targets depend on, so a local checkout populates itself, and exclude gpxsamples/ from the GAE upload. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xk6gQpcHHxmQ4KBUjYhKr9
Ruff's implicit default rule set grows with every release, so the project was effectively linting against a moving target -- ruff 0.16 turned up 28 violations that no code change introduced. Declare the rule set explicitly in [tool.ruff.lint] (E, W, F, I, UP, B, C4, SIM, RUF, ignoring E501) so a routine ruff upgrade stops breaking the build, and fix everything it flags: import ordering, __all__ sorting, deprecated typing.Tuple/List aliases, subprocess argument style, and leaked file handles in the tests. Tell isort that "conftest" is the suite's own shared-helper module rather than a third-party package. Add version floors for the lint and test tooling so CI resolves the versions these rules were checked against, and drop .flake8, which has been dead since ruff replaced flake8. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xk6gQpcHHxmQ4KBUjYhKr9
Brings requirements.txt, which is what Google App Engine installs from, back in line with the current release. Every other runtime dependency floor already matches its latest version. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xk6gQpcHHxmQ4KBUjYhKr9
The .gpx inputs shown in the usage examples now live in the gpxsamples submodule. The included output fixtures are unchanged and still resolve from samples/, so Read the Docs builds without needing the submodule. Also record the samples/ vs gpxsamples/ split and the conftest helpers in CLAUDE.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xk6gQpcHHxmQ4KBUjYhKr9
Reviewer's GuideWire tests/docs to the new gpxsamples submodule, stabilise linting with a pinned Ruff ruleset, and refresh tooling/deps while keeping CLI golden outputs and default-config fixtures in-repo and aligned with the current CLI behavior. Sequence diagram for CI test job checking out submodules and running testssequenceDiagram
participant GH as GitHubActions
participant CO as actions_checkout@v7
participant GHAPI as GitHub
participant UV as setup_uv@v9_0_0
participant PY as pytest
GH->>CO: checkout repo<br/>submodules true<br/>token GPXSAMPLES_TOKEN || github.token
CO->>GHAPI: clone gpxtable repo
CO->>GHAPI: clone gpxsamples submodule
GH->>UV: setup-uv with python 3_12
GH->>PY: run pytest (tests use gpxsamples and samples via conftest)
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
CI status:
|
Picks up the pending dependabot update (#38) across all three jobs that use it: lint, test, and the PyPI publish build. v9.0.0 is a major release solely because it flips the "prune-cache" default from true to false, to reduce load on PyPI's infrastructure. The new default is the intended behavior, so it is taken as-is; the only effect here is a somewhat larger Actions cache. Every Python dependency floor in pyproject.toml, requirements.txt, and docs/requirements.txt was checked against PyPI and already matches the current release, so no other bumps are outstanding. Dependabot's other open PR (#34, click >=8.4.2) is already carried by 66db4ce. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xk6gQpcHHxmQ4KBUjYhKr9
gpxsamples is a separate private repository. A workflow's default GITHUB_TOKEN is scoped to this repo alone, so it cannot clone it -- GitHub reports the refusal as "Repository not found", which reads like the repo is missing rather than unauthorized. Pass a GPXSAMPLES_TOKEN secret to actions/checkout in the test job. checkout applies its token to submodule fetches as well, so one token input covers both repos and no extra step is needed. The expression falls back to github.token when the secret is absent, so a fork still checks out the main repo (its test job will fail on the submodule, as before) rather than failing outright on the primary checkout. Requires a PAT with read access to both repos, stored as GPXSAMPLES_TOKEN in the repository's Actions secrets. Documented in CLAUDE.md alongside the release-please token. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xk6gQpcHHxmQ4KBUjYhKr9
|
Implemented option 2 in token: ${{ secrets.GPXSAMPLES_TOKEN || github.token }}
This job stays red until the secret exists. It needs a PAT with read access to both Two things to keep in mind with this approach: a fine-grained PAT expires, and CI will start failing this same way when it does; and secrets aren't exposed to pull requests from forks, so an outside contributor's
Generated by Claude Code |
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- The global
pytest_configurehook intests/conftest.pycurrently forces the presence of thegpxsamplessubmodule for every test run; if you wanttest_gpxtable.pyor other pure-unit tests to be runnable without the submodule (e.g. viamake test-unit), consider scoping this check to tests that actually usegpx_sample()(via marks, fixtures, or file-level imports) instead of failing the whole suite up front. - Given that
Makefiletargets liketest-unitand some docs describe unit tests as not needing GPX inputs, you might want to align this with the new submodule requirement by either droppingsubmodulesfrom those flows or documenting that all pytest invocations now requiregit submodule update --initso there’s no inconsistency in developer expectations.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The global `pytest_configure` hook in `tests/conftest.py` currently forces the presence of the `gpxsamples` submodule for every test run; if you want `test_gpxtable.py` or other pure-unit tests to be runnable without the submodule (e.g. via `make test-unit`), consider scoping this check to tests that actually use `gpx_sample()` (via marks, fixtures, or file-level imports) instead of failing the whole suite up front.
- Given that `Makefile` targets like `test-unit` and some docs describe unit tests as not needing GPX inputs, you might want to align this with the new submodule requirement by either dropping `submodules` from those flows or documenting that all pytest invocations now require `git submodule update --init` so there’s no inconsistency in developer expectations.
## Individual Comments
### Comment 1
<location path="Makefile" line_range="74-89" />
<code_context>
# ── CLI demos ────────────────────────────────────────────────────────────────
demo-route:
- gpxtable samples/basecamp-route.gpx
+ gpxtable gpxsamples/basecamp-route.gpx
demo-tracks:
- gpxtable --departure "07/30/2023 09:15:00" samples/basecamp-tracks.gpx
+ gpxtable --departure "07/30/2023 09:15:00" gpxsamples/basecamp-tracks.gpx
demo-basecamp:
- gpxtable samples/basecamp.gpx
+ gpxtable gpxsamples/basecamp.gpx
demo-config:
gpxtable --dump-config
demo-custom: /tmp/myconfig.json
- gpxtable --config /tmp/myconfig.json samples/basecamp-route.gpx
+ gpxtable --config /tmp/myconfig.json gpxsamples/basecamp-route.gpx
/tmp/myconfig.json:
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Demo targets now depend on gpxsamples but don’t ensure the submodule is initialized.
Since these `demo-*` targets now read from `gpxsamples/`, they will fail in a fresh clone if the submodule hasn’t been initialized. Please add `submodules` as a dependency for `demo-route`, `demo-tracks`, `demo-basecamp`, and `demo-custom` so they behave consistently with `test`/`generate-samples`.
```suggestion
# ── CLI demos ────────────────────────────────────────────────────────────────
demo-route: submodules
gpxtable gpxsamples/basecamp-route.gpx
demo-tracks: submodules
gpxtable --departure "07/30/2023 09:15:00" gpxsamples/basecamp-tracks.gpx
demo-basecamp: submodules
gpxtable gpxsamples/basecamp.gpx
demo-config:
gpxtable --dump-config
demo-custom: submodules /tmp/myconfig.json
gpxtable --config /tmp/myconfig.json gpxsamples/basecamp-route.gpx
```
</issue_to_address>
### Comment 2
<location path=".github/workflows/python-app.yml" line_range="26-28" />
<code_context>
- uses: actions/checkout@v7
- - uses: astral-sh/setup-uv@v8.2.0
+ - uses: astral-sh/setup-uv@v9.0.0
with:
enable-cache: true
python-version: "3.12"
</code_context>
<issue_to_address>
**issue:** Fetching a private submodule in CI may still break for forks, even with the token fallback.
Because forks don’t have `GPXSAMPLES_TOKEN` and can’t use their default `github.token` to pull your private `gpxsamples` submodule, `actions/checkout` will still fail when `submodules: true` is set. To keep fork CI usable, consider enabling submodules only for the main repo (e.g., via `github.repository_owner`) or making tests gracefully skip submodule-dependent cases when the GPX inputs aren’t available.
</issue_to_address>
### Comment 3
<location path="samples/basecamp-route.txt" line_range="11" />
<code_context>
+| Peet's Coffee Northgate Mall | 0 | | 09:15 | Restaurant
+| Nicasio Square | 12 | | 09:39 | Restroom (+0:15)
+| Pat's International | 65 | L | 11:41 | Restaurant (+1:00)
+| 76 Gureneville | 65/65 | G | 12:41 | Gas Station (+0:15)
+| Willy's America | 79 | | 13:23 | Scenic Area (+0:05)
+| 76 Bodega Bay | 67/132 | G | 15:14 | Gas Station (+0:15)
</code_context>
<issue_to_address>
**issue (typo):** Typo in place name: "Gureneville" vs "Guerneville" used elsewhere.
In `samples/basecamp.txt` the waypoint is spelled "76 Guerneville", so this entry in `samples/basecamp-route.txt` is likely incorrect. Please align the spelling to keep the fixtures consistent.
```suggestion
| 76 Guerneville | 65/65 | G | 12:41 | Gas Station (+0:15)
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
The demo-* targets read GPX inputs from gpxsamples/, so they failed on a fresh clone where the submodule had never been initialized. Give them the same "submodules" prerequisite the test targets already have. demo-config is left alone -- --dump-config reads no sample data. test-unit gets the prerequisite too. Its tests build GPX objects in memory and need no inputs, but conftest's submodule check is global, so every pytest invocation requires the submodule regardless. Aligning the target removes the mismatch between what the Makefile implied and what pytest actually enforces. Document why that check is global rather than scoped to the tests that call gpx_sample(): skipping those tests when inputs are missing would let a broken checkout look like a passing run, which is precisely how the sample move went unnoticed in the first place. Raised in review by sourcery-ai on #39. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xk6gQpcHHxmQ4KBUjYhKr9
Summary
CI was red on two independent counts. This fixes both and refreshes dependencies.
1. The samples submodule move left the repo dangling.
dd6cc4adeletedsamples/in favour of thegpxsamplessubmodule, but nothing was repointed — the test suite, docs, Makefile, and.gcloudignoreall still referencedsamples/. The suite was at 14 failures + 13 collection errors, andactions/checkoutdoesn't fetch submodules by default, so CI had no GPX inputs at all.The move also stranded six files that were not copied into the submodule: the golden
.txtCLI outputs anddefault-config.json. Those are small text fixtures the docsliteralinclude, so they're restored here rather than pushed into the submodule. Sample data is now split by role:gpxsamples/(submodule).gpxinputssamples/(this repo).txtoutputs +default-config.jsontests/conftest.pyowns both paths and fails collection with an actionable message when the submodule was never initialized, rather than emitting a wall ofFileNotFoundError. Read the Docs still builds without the submodule, since everyliteralincludetarget is back in-repo.2. Ruff was linting against a moving target. The project had no
[tool.ruff]config, so it inherited ruff's implicit default rule set — which grows with every release. Ruff 0.16 turned up 28 violations that no code change introduced. The rule set is now declared explicitly, so a routine ruff upgrade no longer breaks the build on its own.Changes
test:— repoint the suite atgpxsamples/via newtests/conftest.pyhelpers. Usesys.executableinstead of whateverpythonresolves to onPATH, and absolute sample paths instead of cwd-relative ones, so the suite no longer depends on how it was invoked.ci:—submodules: trueon the test job's checkout (lint and the GAE deploy don't need it). Newmake submodulestarget that the test targets depend on;gpxsamples/excluded from the GAE upload.chore(lint):— pin[tool.ruff.lint]toE, W, F, I, UP, B, C4, SIM, RUF(ignoringE501) and fix all 28 findings: import ordering,__all__sorting, deprecatedtyping.Tuple/List, subprocess argument style, and leaked file handles in the tests. Drop.flake8, dead since ruff replaced flake8.build(deps):— bump theclickfloor to 8.4.2 inrequirements.txt(what GAE installs from). Every other runtime floor already matched its latest release; added floors for the lint/test tooling so CI resolves the versions these rules were checked against.docs:— usage examples now invokegpxsamples/*.gpx;CLAUDE.mdrecords the directory split.Incidental fix
samples/default-config.jsonhad silently drifted from the code — it still carried a\Dinnerregex typo that the classifier fixed at some point, so the published docs showed a config the program no longer produces.--dump-configis now regenerated by--generateand asserted by a test, so it can't drift again.Verification
The five golden
.txtfiles regenerate byte-identical, which confirms none of this changed program behavior —default-config.jsonis the only regenerated file that differs.Generated by Claude Code
Summary by Sourcery
Repoint tests, docs, and tooling to use the new gpxsamples submodule for GPX inputs while restoring and validating in-repo CLI output fixtures, and pin lint/test tooling to stable configurations so CI remains green across upgrades.
Bug Fixes:
Enhancements:
Build:
CI:
Documentation:
Tests:
Chores: