diff --git a/pyicloud/cli/app.py b/pyicloud/cli/app.py index 9bb5ae39..9052954a 100644 --- a/pyicloud/cli/app.py +++ b/pyicloud/cli/app.py @@ -2,6 +2,9 @@ from __future__ import annotations +from importlib.metadata import PackageNotFoundError +from importlib.metadata import version as package_version + import typer from pyicloud.cli.commands.account import app as account_app @@ -21,6 +24,23 @@ ) +def _installed_version() -> str: + """Return the installed pyicloud package version.""" + + try: + return package_version("pyicloud") + except PackageNotFoundError: + return "unknown" + + +def _version_callback(value: bool) -> None: + """Print the installed pyicloud version and exit.""" + + if value: + typer.echo(_installed_version()) + raise typer.Exit() + + def _group_root(ctx: typer.Context) -> None: """Show mounted group help when invoked without a subcommand.""" @@ -29,6 +49,19 @@ def _group_root(ctx: typer.Context) -> None: raise typer.Exit() +@app.callback() +def root_callback( + version: bool = typer.Option( + False, + "--version", + help="Show the installed pyicloud version and exit.", + callback=_version_callback, + is_eager=True, + ), +) -> None: + """Handle root CLI options before subcommand dispatch.""" + + app.add_typer( account_app, name="account", invoke_without_command=True, callback=_group_root ) diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py index 964a107b..f87d10c9 100644 --- a/tests/test_cmdline.py +++ b/tests/test_cmdline.py @@ -525,6 +525,16 @@ def test_root_help() -> None: assert command in text +def test_root_version_prints_installed_package_version() -> None: + """The root --version flag should print the installed pyicloud version.""" + + with patch.object(cli_module, "_installed_version", return_value="9.9.9"): + result = _runner().invoke(app, ["--version"]) + + assert result.exit_code == 0 + assert result.stdout.strip() == "9.9.9" + + def test_group_help() -> None: """Each command group should expose help."""