Skip to content

feat(cli): add sm package-update to bump simple_module_* deps - #101

Merged
antosubash merged 1 commit into
mainfrom
feature/crazy-roentgen-72081e
May 2, 2026
Merged

antosubash merged 1 commit into
mainfrom
feature/crazy-roentgen-72081e

Conversation

@antosubash

Copy link
Copy Markdown
Owner

Summary

Adds a new sm package-update CLI command that walks the project's pyproject.toml (and any [tool.uv.workspace] members), finds dependencies whose distribution name starts with simple_module_ / simple-module-, queries PyPI for the latest non-yanked release, and rewrites each constraint to name>=<latest>.

  • Deps backed by [tool.uv.sources] (workspace = true, path, git, url) are left untouched — those aren't installed from PyPI.
  • Pre-releases are skipped by default (--include-pre opts in).
  • --dry-run shows the planned changes without writing.
  • PyPI lookups run in parallel via ThreadPoolExecutor; for a project with ~10 sm packages this is ~100ms instead of ~1s.
  • Mutation uses tomlkit so existing formatting (comments, ordering, quoting) is preserved.
  • After applying, the command prints a per-file change/skip summary and reminds the user to run uv sync.

Why

The host scaffolds dependencies like simple_module_core>=1.0,<2.0 and there's currently no convenient way to bump them all at once when new framework / module releases land on PyPI. This gives users one command to do it.

Notes for reviewers

  • No new CLI deps. framework/cli/tests/test_no_framework_deps.py constrains the CLI package to typer + tomlkit. That's why version comparison uses a tiny custom _version_key helper instead of packaging.version.Version — the latter would break the invariant. The custom helper handles standard release versions correctly; ambiguous ordering between letter-suffixed pre-releases only matters under --include-pre, which is opt-in.
  • PEP 508 parsing. _dep_name mirrors the more robust _parse_requirement_name in scripts/bump_version.py (handles markers ;, extras […], all PEP 440 ops). Logic is duplicated rather than imported because scripts/ isn't packaged with the CLI wheel.
  • Test seam. run_update() is the importable entry point (accepts a fetcher injection); package_update() is the thin Typer wrapper. Keeps the --help output clean and tests deterministic without hitting the network.

Test plan

  • uv run pytest framework/cli/tests/ — 94/94 passing (8 new tests).
  • uv run ruff check + ruff format --check + ty check clean.
  • uv run sm package-update --help renders cleanly with three flags.
  • Manual smoke test against a scaffolded host with live PyPI (recommended before merging).

Walks the project's pyproject.toml and any [tool.uv.workspace] members,
finds dependencies whose name starts with simple_module_ / simple-module-,
queries PyPI for the latest non-yanked release, and rewrites each constraint
to `name>=<latest>`. Deps backed by [tool.uv.sources] (workspace, path, git,
url) are skipped — they aren't installed from PyPI.

Flags: --path, --dry-run, --include-pre. PyPI lookups run in parallel via
ThreadPoolExecutor so a project with ~10 deps takes ~100ms instead of ~1s.
Mutation uses tomlkit so existing formatting is preserved.

The CLI's no-extra-deps invariant (test_no_framework_deps.py pins it to
typer + tomlkit) means we use a small custom version-key helper instead of
pulling in `packaging`.
@antosubash
antosubash merged commit bb551b0 into main May 2, 2026
10 checks passed
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.

1 participant