diff --git a/changes/272.bugfix b/changes/272.bugfix new file mode 100644 index 0000000..7a3b576 --- /dev/null +++ b/changes/272.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" },