From dafdb1819661a7ae3c25949d7fa8adfdfee6ab2a Mon Sep 17 00:00:00 2001 From: Paul Fremantle Date: Sun, 30 Aug 2026 09:37:48 +0100 Subject: [PATCH 1/2] fix: resolve UsageError from the installed typer's Click MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit typer 0.25+ vendors its own copy of Click and no longer depends on the click package, so `import click` in cli.py broke every fresh install: `uv tool install bambox` produced a CLI that died with ModuleNotFoundError: No module named 'click'. Declaring click as a dependency would not be enough — typer raises its vendored typer._click UsageError, which is a different class from the standalone click.UsageError, so main()'s handler would silently stop matching and usage errors would traceback instead of exiting 2. Resolve UsageError from typer's vendored Click, falling back to the click package for typer < 0.25, and assert the hierarchy in a test so it cannot drift again. Also refreshes the stale version pin in uv.lock. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011aB9rCzbxyCrr7ZcXEN7g5 --- changes/+typer-vendored-click.bugfix | 1 + src/bambox/cli.py | 8 ++++++-- tests/test_cli.py | 20 ++++++++++++++++++++ uv.lock | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 changes/+typer-vendored-click.bugfix diff --git a/changes/+typer-vendored-click.bugfix b/changes/+typer-vendored-click.bugfix new file mode 100644 index 0000000..7a3b576 --- /dev/null +++ b/changes/+typer-vendored-click.bugfix @@ -0,0 +1 @@ +Fix `uv tool install bambox` / `pip install bambox` producing a CLI that crashed with `ModuleNotFoundError: No module named 'click'` on typer 0.25+, which vendors its own copy of Click. diff --git a/src/bambox/cli.py b/src/bambox/cli.py index eaefba5..3832fdb 100644 --- a/src/bambox/cli.py +++ b/src/bambox/cli.py @@ -7,10 +7,14 @@ from pathlib import Path from typing import Annotated, Optional -import click import typer from rich.markup import escape +try: # typer >= 0.25 vendors its own copy of Click + from typer._click.exceptions import UsageError +except ImportError: # typer < 0.25 depends on the click package + from click.exceptions import UsageError # type: ignore[assignment] + from bambox import ui from bambox.cura import ( PRINTER_MODEL_IDS, @@ -453,6 +457,6 @@ def validate( def main(argv: list[str] | None = None) -> None: try: app(argv, standalone_mode=False) - except click.UsageError as exc: + except UsageError as exc: ui.error(str(exc)) sys.exit(2) diff --git a/tests/test_cli.py b/tests/test_cli.py index c65c382..f20dcce 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -421,3 +421,23 @@ def test_no_command_shows_help(self, capsys: pytest.CaptureFixture[str]) -> None def test_no_command_with_flag_only(self) -> None: with pytest.raises(SystemExit, match="2"): main(["--nonexistent-flag"]) + + +# --------------------------------------------------------------------------- +# Entry point exception handling +# --------------------------------------------------------------------------- + + +class TestUsageErrorHandling: + def test_usage_error_matches_installed_typer(self) -> None: + """main() must catch the UsageError class the installed typer raises. + + typer >= 0.25 vendors its own copy of Click, so importing + ``click.UsageError`` from the standalone package would silently stop + matching (and the click package is no longer installed at all). + """ + import typer + + from bambox.cli import UsageError + + assert issubclass(typer.BadParameter, UsageError) diff --git a/uv.lock b/uv.lock index d66a012..8872935 100644 --- a/uv.lock +++ b/uv.lock @@ -13,7 +13,7 @@ wheels = [ [[package]] name = "bambox" -version = "0.4.7" +version = "0.6.1" source = { editable = "." } dependencies = [ { name = "rich" }, From bd3ead62e09883e6c57553aa97806b8d4f9ac31e Mon Sep 17 00:00:00 2001 From: Paul Fremantle Date: Sun, 30 Aug 2026 09:38:11 +0100 Subject: [PATCH 2/2] misc: number changelog fragment for #272 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_011aB9rCzbxyCrr7ZcXEN7g5 --- changes/{+typer-vendored-click.bugfix => 272.bugfix} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changes/{+typer-vendored-click.bugfix => 272.bugfix} (100%) diff --git a/changes/+typer-vendored-click.bugfix b/changes/272.bugfix similarity index 100% rename from changes/+typer-vendored-click.bugfix rename to changes/272.bugfix