refactor: drop typer, build the CLI directly on click#499
Conversation
typer >=0.26 vendors click and is incompatible with gto's click-based CLI machinery (see #497). gto only used typer's signature-based param declarations; all the custom UX (grouped help, aliases, examples, error funnel) was already hand-written click code. Re-express command params as click decorators and remove the typer dependency and pin. - commands, options, defaults, flags, help texts, exit codes: unchanged - top-level `gto --help` output is byte-identical - subcommand help switches from typer's rich boxes to click's plain format; argument help is preserved via GtoArgument + an "Arguments" help section (click has no native argument help) - GtoGroup.list_commands keeps definition order (click sorts alphabetically by default) - drop dead option definitions left over from removed commands (--rev, --all, --expected, --type, --path, --description, --custom, --table, --commit, --push-commit, --branch, arg_version, arg_stage, option_version, option_to_version, GTOGroupSection) - click>=8.2 floor: CliRunner without mix_stderr, kebab-case naming Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…paths
Manual output review of every command against pre-migration gto (typer
0.25.1): byte-identical on all success paths; only usage-error
decoration differs (click's plain "Error:" line instead of typer's
rich box, and the hint suggests --help instead of -h).
Review fixes:
- deprecate: version/stage annotated Optional[str] (they can be None)
- remove the "Manage artifact enrichments" help section: no command
has used it since the enrichment commands were removed
- drop redundant parens in the error-funnel echo
Coverage: gto/cli.py 85% -> 97% (+23 tests). Newly covered: the
promote alias resolution, subcommand help ("Arguments" section),
Examples epilog rendering, --version/-v/--traceback/--tb flags,
click-exception passthrough, --simple/--sort validation errors,
assign version-without-ref and bare-HEAD branches, deprecate
unassign/full-artifact branches, all --json output modes, parse-tag
--key, multi-event refs, show --ref mismatch, print-state, doctor
with broken config, unknown command. Remaining uncovered lines are
defensive fallbacks, completion-mode returns, and __main__.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Post-migration review round (commit 98e8f04): Manual output review of every command — ran the full command surface (~40 invocations: register/assign/promote/deprecate flows, all show/history/check-ref/stages output modes, parse-tag, print-state, doctor, plus error paths) under both the pre-migration build (main @ 21f6a8a, typer 0.25.1) and this branch, and diffed normalized outputs. Byte-identical on every success path. Only differences are in usage-error decoration: click's plain Coverage — Critical review fixes — |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Refactors gto’s CLI implementation to remove the typer dependency and define the CLI directly using click, aligning with the mitigation plan from #497 and reducing exposure to typer’s release changes.
Changes:
- Replaced the Typer-based CLI with a Click-based
app(click.Group), including custom help formatting (Arguments section, Examples epilog) and command ordering/alias handling. - Updated tests to use
click.testing.CliRunnerand to validate new/maintained CLI behaviors (version flag, aliasing, help rendering, exception pass-through). - Updated
pyproject.tomldependencies to droptyperand requireclick>=8.2,<9.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
gto/cli.py |
Rebuilds the CLI on Click (group/commands/options/arguments), preserves help structure via custom formatter/argument class, and keeps unified error handling + aliases. |
pyproject.toml |
Removes typer and bumps Click lower bound to 8.2. |
tests/conftest.py |
Switches runner infrastructure to Click’s CliRunner. |
tests/test_cli.py |
Updates fixtures for Click command discovery and adds/adjusts CLI behavior tests (help rendering, version flag, aliases, exception behavior). |
tests/test_config.py |
Migrates from Typer’s runner to Click’s runner for help invocation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| deprecated: bool, | ||
| assignments_per_version: int, | ||
| versions_per_stage: int, | ||
| sort: str, |
There was a problem hiding this comment.
Agreed — fixed in #503 (the PR merged before this could land here): params now annotated to match the callback return types (Optional[bool] / VersionSort), and the # type: ignore comments those wrong annotations forced are gone. mypy passes without any ignores.
| ref: str, | ||
| version: Optional[str], | ||
| message: Optional[str], | ||
| simple: str, |
There was a problem hiding this comment.
Agreed — fixed in #503 (the PR merged before this could land here): params now annotated to match the callback return types (Optional[bool] / VersionSort), and the # type: ignore comments those wrong annotations forced are gone. mypy passes without any ignores.
| version: Optional[str], | ||
| stage: str, | ||
| message: Optional[str], | ||
| simple: str, |
There was a problem hiding this comment.
Agreed — fixed in #503 (the PR merged before this could land here): params now annotated to match the callback return types (Optional[bool] / VersionSort), and the # type: ignore comments those wrong annotations forced are gone. mypy passes without any ignores.
| stage: Optional[str], | ||
| ref: Optional[str], | ||
| message: Optional[str], | ||
| simple: str, |
There was a problem hiding this comment.
Agreed — fixed in #503 (the PR merged before this could land here): params now annotated to match the callback return types (Optional[bool] / VersionSort), and the # type: ignore comments those wrong annotations forced are gone. mypy passes without any ignores.
Follow-up to #499, addressing [Copilot's post-merge review comments](#499 (review)): `callback_simple` normalizes `--simple` to `None|bool` and `callback_sort` returns `VersionSort`, but the command params were annotated `str` (carried over from the typer version). Annotate them truthfully and drop the five `# type: ignore` comments that the wrong annotations forced. `api.assign`'s `simple` accepts `None` ("auto") at runtime, so it becomes `Optional[bool]` too. No behavior change — mypy now passes without any ignores; full suite (188) green. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Follow-up to #497 — implements the mitigation plan from the typer discussion there: remove typer entirely instead of migrating to its vendored-click API. Net: -1 dependency, -1 pin, net -7 lines, and immunity to typer's release churn.
Why dropping typer (not migrating to typer ≥0.26)
gto only used typer's thin core — declaring command params via function signatures. Everything that defines the CLI's actual behavior (sectioned help, command aliases, "Examples:" epilogs, the unified error funnel) was already hand-written click code. So the migration is mechanical: re-express ~10 command signatures as click decorators, delete the typer layer.
What changed
Argument/Optiondefaults to@click.option/@click.argumentdecorators. Flags, defaults, help texts, callbacks, exit codes: unchanged.appis now aclick.Group(samegto.cli:appentry point).typer.Exit/typer.colors/typer.BadParameter→ click equivalents.GtoArgument(click.Argument)carries argument help (click has no native argument help) andGtoCliMixin.format_optionsrenders an "Arguments" section — sotest_commands_args_helpstill enforces help on every param.GtoGroup.list_commandsoverride keeps definition order (click sorts alphabetically by default).typer.testing.CliRunner→click.testing.CliRunner; theget_command_from_infofixture becomesapp.commands.values().--rev,--all,--expected,--type,--path,--description,--custom,--table,--commit,--push-commit,--branch,arg_version,arg_stage,option_version,option_to_version,GTOGroupSection).pyproject.toml: typer removed;click>=8.2,<9(8.2 floor forCliRunnerwithoutmix_stderrand kebab-case command naming).User-visible changes
gto --helpoutput is byte-identical to before.--helpswitches from typer's rich boxes to click's classic plain format (matching the top-level help style), with an added "Arguments" section preserving argument descriptions. Everything else — usage lines, option lists, defaults — carries over.Verification
pre-commit run --all-filesgreen (ruff, mypy 2.2.0, pylint 4.0.6).register,assign(viapromotealias),show(table +--json),check-ref,history --plain,deprecate; error paths verified — GTOException → ❌ message + exit 1, usage error → exit 2,-hworks on subcommands.🤖 Generated with Claude Code