Skip to content

fix(help): resolve version without raising when metadata is absent (#191)#196

Merged
robcohen merged 3 commits into
mainfrom
fix/191-resilient-version-lookup
Jul 2, 2026
Merged

fix(help): resolve version without raising when metadata is absent (#191)#196
robcohen merged 3 commits into
mainfrom
fix/191-resilient-version-lookup

Conversation

@robcohen

Copy link
Copy Markdown
Member

Summary

Fixes #191 — the Help page returns HTTP 500 (PackageNotFoundError: No package metadata was found for rustfava) on packaged installs (e.g. the .deb).

Root cause

help_page called importlib.metadata.version("rustfava") with no fallback. Packaged builds (PyInstaller sidecar, .deb) ship the source without *.dist-info metadata, so the lookup raises PackageNotFoundError and the view 500s. The same unguarded lookup existed in __init__.py, and cli.py carried a stale hard-coded "0.1.11" fallback.

Fix

Centralize one resilient resolver, rustfava._resolve_version, surfaced via the package __version__:

  1. importlib.metadata.version (installed wheels)
  2. setuptools_scm-generated _version.py (built artifacts)
  3. "unknown" sentinel — never raises

application.py and cli.py now both consume rustfava.__version__, removing the duplicated logic and the stale literal. setuptools_scm is configured with version_file = "src/rustfava/_version.py" (gitignored) so built artifacts that lack dist-info still report the true version instead of unknown.

🤖 Generated with Claude Code

@robcohen

Copy link
Copy Markdown
Member Author

Deep review — crash fix is solid; addressed the packaged-version gap (f5034e7).

The runtime fix is correct: no import cycle (cli.py's top-level from rustfava import __version__ runs after __init__ is fully initialized), click.version_option gets a plain str, the _version fallback path and broad except are justified ("never raise"), and existing test_version/test_help_pages still pass.

Gap the review caught: the version_file machinery was inert for the very build that motivated #191. The PyInstaller/.deb job runs no setuptools build, so _version.py was never generated and no dist-info was bundled → the frozen binary would report "unknown". The crash is fixed regardless, but the version display wasn't.

Fix (f5034e7): the PyInstaller spec now generates rustfava/_version.py at build time — from RUSTFAVA_VERSION (settable from the release tag) or setuptools_scm on a full checkout — and adds it to hiddenimports. Degrades gracefully to "unknown" when neither source is present (no regression).

Remaining one-liner follow-up: the release workflow should export RUSTFAVA_VERSION="${GITHUB_REF#refs/tags/v}" into the build-sidecar PyInstaller step so CI-built .deb/dmg binaries show the real version. I deferred that edit to avoid conflicting with the in-flight #197, which currently owns the build-sidecar region of desktop-release.yml — best landed right after #197 merges.

@robcohen

Copy link
Copy Markdown
Member Author

Follow-up resolved: the RUSTFAVA_VERSION CI wiring is now in #197 (commit 2f4e65a), so once both PRs land the packaged binary reports the real version end-to-end. No further follow-up needed; either PR alone degrades gracefully to "unknown".

@robcohen robcohen force-pushed the fix/191-resilient-version-lookup branch from f5034e7 to caa9464 Compare July 2, 2026 18:55
robcohen added a commit that referenced this pull request Jul 2, 2026
…ches

Completes #196 for current main:

- _resolve_version bound the name `version` twice (importlib's function, then
  the _version.py string) — runtime-correct but mypy-illegal; use distinct
  names and drop a stale type-ignore.
- tests/test_version_resolution.py covers every branch: metadata present,
  metadata missing -> setuptools_scm _version.py, nothing available ->
  "unknown" sentinel, and the module __getattr__.
- omit the setuptools_scm-GENERATED src/rustfava/_version.py from coverage:
  the new version_file config makes builds emit it locally, and a generated
  file's unexecuted branches were failing the 100% gate.

566 passed, coverage 100.00%, mypy clean.
@robcohen

robcohen commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

Brought this up to date and fixed the CI failures — three layers:

  1. Stale base: the branch predated the v0.19.0 saga; rebased onto current main, which cleared the test-job failures outright.
  2. mypy: _resolve_version bound the name version twice (importlib's function, then _version.py's string) — runtime-correct but type-illegal. Renamed to metadata_version/scm_version; dropped a stale type: ignore.
  3. Coverage gate: the fallback branches were untested (__init__.py at 63%), and separately the setuptools_scm-generated src/rustfava/_version.py (a side effect of this PR's version_file config) was being measured — a generated file's unexecuted branches failed the 100% gate. Added tests/test_version_resolution.py covering every branch (metadata / scm-file / sentinel / __getattr__) and omitted the generated file from coverage.

Local: 566 passed, coverage 100.00%, mypy clean, pinned ruff clean.

robcohen and others added 3 commits July 2, 2026 19:02
)

`help_page` called `importlib.metadata.version("rustfava")` unguarded. In
packaged builds that ship the source without dist-info metadata (PyInstaller
sidecar, the .deb package) this raises `PackageNotFoundError`, so the Help
page 500s.

Centralize a resilient resolver in `rustfava._resolve_version`, used via the
package `__version__`:
  1. importlib.metadata (installed wheels)
  2. setuptools_scm-generated `_version.py` (built artifacts)
  3. "unknown" sentinel instead of raising

`application.py` and `cli.py` now both consume `rustfava.__version__`,
removing the duplicated lookup and the stale hard-coded "0.1.11" fallback in
cli.py. `setuptools_scm` is configured to emit `_version.py` (gitignored) so
built artifacts without dist-info still report the real version.

Fixes #191

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rsion (#191)

The frozen sidecar/.deb ships no dist-info metadata, so
importlib.metadata.version() fails and rustfava falls back to
rustfava._version. Generate that module at build time — from the
RUSTFAVA_VERSION env (settable from the release tag) or setuptools_scm on a
full checkout — and add it to hiddenimports so it is bundled. Without this
the packaged binary reports "unknown"; the runtime crash fix still holds
either way. Degrades gracefully (falls back to "unknown") when neither
source is available.
…ches

Completes #196 for current main:

- _resolve_version bound the name `version` twice (importlib's function, then
  the _version.py string) — runtime-correct but mypy-illegal; use distinct
  names and drop a stale type-ignore.
- tests/test_version_resolution.py covers every branch: metadata present,
  metadata missing -> setuptools_scm _version.py, nothing available ->
  "unknown" sentinel, and the module __getattr__.
- omit the setuptools_scm-GENERATED src/rustfava/_version.py from coverage:
  the new version_file config makes builds emit it locally, and a generated
  file's unexecuted branches were failing the 100% gate.

566 passed, coverage 100.00%, mypy clean.
@robcohen robcohen force-pushed the fix/191-resilient-version-lookup branch from 353798b to bcdbd24 Compare July 2, 2026 19:02
@robcohen robcohen merged commit 9711e27 into main Jul 2, 2026
30 checks passed
@robcohen robcohen deleted the fix/191-resilient-version-lookup branch July 2, 2026 19:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Help: No package metadata was found for rustfava

1 participant