From 56b0090a14ff4d4171088546af575f310db17938 Mon Sep 17 00:00:00 2001 From: Test User Date: Sun, 21 Jun 2026 12:15:05 +0200 Subject: [PATCH] refactor cli command registration --- src/openenv/cli/__main__.py | 56 +++++++++++++++++++++++-------------- tests/test_cli/test_main.py | 19 ++++++++++++- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/openenv/cli/__main__.py b/src/openenv/cli/__main__.py index b80e5b9fd9..9ab279afdc 100644 --- a/src/openenv/cli/__main__.py +++ b/src/openenv/cli/__main__.py @@ -12,6 +12,7 @@ """ import sys +from collections.abc import Callable import typer from openenv.cli.commands import ( @@ -25,6 +26,9 @@ validate, ) +CommandCallback = Callable[..., object] +CommandSpec = tuple[str, str, CommandCallback] + # Create the main CLI app app = typer.Typer( name="openenv", @@ -32,34 +36,44 @@ no_args_is_help=True, ) -# Register commands -app.command(name="init", help="Initialize a new OpenEnv environment")(init.init) -app.command(name="build", help="Build Docker images for OpenEnv environments")( - build.build +_COMMANDS_BEFORE_SKILLS: tuple[CommandSpec, ...] = ( + ("init", "Initialize a new OpenEnv environment", init.init), + ("build", "Build Docker images for OpenEnv environments", build.build), + ( + "validate", + "Validate environment structure and deployment readiness", + validate.validate, + ), + ( + "push", + "Push an OpenEnv environment to Hugging Face Spaces or custom registry", + push.push, + ), + ("serve", "Serve environments locally (TODO: Phase 4)", serve.serve), + ("fork", "Fork (duplicate) a Hugging Face Space to your account", fork.fork), ) -app.command( - name="validate", help="Validate environment structure and deployment readiness" -)(validate.validate) -app.command( - name="push", - help="Push an OpenEnv environment to Hugging Face Spaces or custom registry", -)(push.push) -app.command(name="serve", help="Serve environments locally (TODO: Phase 4)")( - serve.serve +_COMMANDS_AFTER_SKILLS: tuple[CommandSpec, ...] = ( + ( + "collect", + "Collect rollouts from a deployed OpenEnv environment", + collect.collect, + ), ) -app.command( - name="fork", - help="Fork (duplicate) a Hugging Face Space to your account", -)(fork.fork) + + +def _register_commands(commands: tuple[CommandSpec, ...]) -> None: + """Register top-level Typer commands.""" + for name, help_text, callback in commands: + app.command(name=name, help=help_text)(callback) + + +_register_commands(_COMMANDS_BEFORE_SKILLS) app.add_typer( skills.app, name="skills", help="Manage OpenEnv skills for AI assistants", ) -app.command( - name="collect", - help="Collect rollouts from a deployed OpenEnv environment", -)(collect.collect) +_register_commands(_COMMANDS_AFTER_SKILLS) # Entry point for setuptools diff --git a/tests/test_cli/test_main.py b/tests/test_cli/test_main.py index 67c4b0d673..b73cab4b8b 100644 --- a/tests/test_cli/test_main.py +++ b/tests/test_cli/test_main.py @@ -9,13 +9,30 @@ from unittest.mock import patch import pytest -from openenv.cli.__main__ import main +from openenv.cli.__main__ import app, main from typer.testing import CliRunner runner = CliRunner() +def test_cli_registers_expected_commands() -> None: + """Test that the top-level CLI commands are registered.""" + command_names = [command.name for command in app.registered_commands] + group_names = [group.name for group in app.registered_groups] + + assert command_names == [ + "init", + "build", + "validate", + "push", + "serve", + "fork", + "collect", + ] + assert group_names == ["skills"] + + def test_main_handles_keyboard_interrupt() -> None: """Test that main handles KeyboardInterrupt gracefully.""" with patch("openenv.cli.__main__.app") as mock_app: