Repository navigation
Conversation
`specify extension update` read the catalog version with `ext_info["version"]`, so an entry with no `version` raised KeyError, and a null or list value raised TypeError or AttributeError. Any of these aborted the command before the remaining installed extensions were checked. Read the value the way `specify workflow update` does, so these entries take the existing "Invalid catalog version ... (skipping)" path. Fixes github#5082
There was a problem hiding this comment.
🟡 Changes recommended
Numeric catalog versions now pass discovery but are rejected during download, offering updates that cannot complete.
1 open issue
What changed in this PR
Addresses #5082 by preventing missing or malformed catalog version fields from aborting Specify CLI extension update checks.
Changes:
- Reads catalog versions defensively and reuses the existing skip warning.
- Adds discovery and CLI regression coverage for malformed entries, continued checking, and unchanged installed state.
The PR’s reported before-and-after results were reviewed; project tests were not rerun here.
| File | Description |
|---|---|
tests/specify_cli/extensions/test_command_update.py |
Checks successful CLI completion, the skip warning, and unchanged registry state. |
tests/specify_cli/extensions/test_command_update_discovery.py |
Covers missing, null, and list versions while verifying discovery continues. |
src/specify_cli/extensions/_command_update_discovery.py |
Converts optional catalog version values to strings before parsing. |
Review effort: Max
|
Please address Copilot feedback |
…date A numeric catalog version such as `"version": 2` passed discovery once coerced with str(), but the download rejects non-string versions, so the update was offered and then always failed. Require a string and take the existing "Invalid catalog version ... (skipping)" path otherwise.
| if not isinstance(raw_catalog_version, str): | ||
| raise pkg_version.InvalidVersion(raw_catalog_version) |
|
Please address Copilot feedback |
|
Addressed in 7cef29a. Discovery now accepts a catalog |
|
Please address Copilot feedback |
|
The open Copilot thread at |
| if not isinstance(raw_catalog_version, str): | ||
| raise pkg_version.InvalidVersion(raw_catalog_version) |
|
Please address Copilot feedback. If not applicable, please explain why |
A catalog entry with "version": 2 was reported as "Invalid catalog version '2'", which reads as a rejected version string. Report a missing version and a non-string one separately, naming the received type as ExtensionManifest validation does.
|
Addressed in bfb786b. A missing catalog version now warns |


Description
discover_updatesread the catalog version withext_info["version"], so a catalog entry withoutversionmadespecify extension updateexit 1 withKeyError: 'version', and the installed extensions after it were never checked. Anullor list value crashed the same way, withTypeErrorandAttributeError.This PR accepts the catalog version only when it is a string. Anything else is skipped with a warning and the loop carries on. A missing version is reported as
Missing catalog version, and any other type (null, a list, or a number such as2) asInvalid catalog version: expected a string, got <type>, in the style ofExtensionManifestvalidation. An unparseable string keeps the existingInvalid catalog version '<value>'warning. Entries with a valid version behave as before. A number is rejected rather than converted: the download step passes the catalog's raw value tobuild_safe_download_path, which accepts only a string (_download_security.py:442), so a numeric version would be offered as an update that then fails to download.The issue's repro script, on
main(67e0f72), last traceback line only:With this PR:
The same script with
"version": 2onaaa:Fixes #5082
Testing
uv run specify --helpuv sync && uv run pytestNew tests:
test_discovery_skips_catalog_entry_without_valid_versionintests/specify_cli/extensions/test_command_update_discovery.py, for a missing,null, list, numeric and unparseableversion. The broken entry comes first, and the test checks the exact skip warning for each case and that the second extension's update is still found.test_update_skips_catalog_entry_without_versionintests/specify_cli/extensions/test_command_update.pyrunsspecify extension updatethrough the CLI and checks exit code 0, theMissing catalog versionwarning, and an unchanged registry.With only
src/reverted tomain, the 5 missing and wrong-type cases fail (KeyError,TypeError,AttributeError, exit code 1). With the fix, the 32 tests in those two files pass.Full suite on macOS, Python 3.14.6,
pytest -n 2as in CI: 12808 passed, 434 skipped, none failed.uvx ruff@0.15.0 check src testspasses, and so doesgit diff --check.AI Disclosure
AI disclosure: Claude Code (model: claude-opus-5-5, autonomous) reproduced the bug, wrote the fix and tests, ran the suite and lint, and drafted this description.