diff --git a/pyproject.toml b/pyproject.toml index 43fd7bf51..e7204fe16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,8 +7,7 @@ readme = "README.md" requires-python = ">=3.12, <3.14" dependencies = [ "codegen-api-client", - "click>=8.1.7", - "rich-click>=1.8.5", + "typer>=0.12.5", "rich>=13.7.1", "hatch-vcs>=0.4.0", "hatchling>=1.25.0", diff --git a/src/codegen/cli/api/client.py b/src/codegen/cli/api/client.py index f4130970b..38fb8d4b6 100644 --- a/src/codegen/cli/api/client.py +++ b/src/codegen/cli/api/client.py @@ -5,6 +5,8 @@ from pydantic import BaseModel from rich import print as rprint +from codegen.cli.api.endpoints import IDENTIFY_ENDPOINT +from codegen.cli.api.schemas import IdentifyResponse from codegen.cli.env.global_env import global_env from codegen.cli.errors import InvalidTokenError, ServerError @@ -75,3 +77,7 @@ def _make_request( except requests.RequestException as e: msg = f"Network error: {e!s}" raise ServerError(msg) + + def identify(self) -> IdentifyResponse: + """Identify the current user with the authentication token.""" + return self._make_request("GET", IDENTIFY_ENDPOINT, None, IdentifyResponse) diff --git a/src/codegen/cli/auth/decorators.py b/src/codegen/cli/auth/decorators.py index b12cf35ed..b0cb36dc1 100644 --- a/src/codegen/cli/auth/decorators.py +++ b/src/codegen/cli/auth/decorators.py @@ -1,8 +1,9 @@ import functools +import inspect from collections.abc import Callable -import click import rich +import typer from codegen.cli.auth.login import login_routine from codegen.cli.auth.session import CodegenSession @@ -21,7 +22,7 @@ def wrapper(*args, **kwargs): # Check for valid session if session is None: pretty_print_error("There is currently no active session.\nPlease run 'codegen init' to initialize the project.") - raise click.Abort() + raise typer.Abort() if (token := get_current_token()) is None: rich.print("[yellow]Not authenticated. Let's get you logged in first![/yellow]\n") @@ -36,4 +37,10 @@ def wrapper(*args, **kwargs): return f(*args, session=session, **kwargs) + # Remove the session parameter from the wrapper's signature so Typer doesn't see it + sig = inspect.signature(f) + new_params = [param for name, param in sig.parameters.items() if name != 'session'] + new_sig = sig.replace(parameters=new_params) + wrapper.__signature__ = new_sig # type: ignore[attr-defined] + return wrapper diff --git a/src/codegen/cli/auth/login.py b/src/codegen/cli/auth/login.py index 3843dbad3..ab310d855 100644 --- a/src/codegen/cli/auth/login.py +++ b/src/codegen/cli/auth/login.py @@ -1,7 +1,7 @@ import webbrowser import rich -import rich_click as click +import typer from codegen.cli.api.webapp_routes import USER_SECRETS_ROUTE from codegen.cli.auth.token_manager import TokenManager @@ -19,7 +19,7 @@ def login_routine(token: str | None = None) -> str: str: The authenticated token Raises: - click.ClickException: If login fails + typer.Exit: If login fails """ # Try environment variable first @@ -29,11 +29,11 @@ def login_routine(token: str | None = None) -> str: if not token: rich.print(f"Opening {USER_SECRETS_ROUTE} to get your authentication token...") webbrowser.open_new(USER_SECRETS_ROUTE) - token = click.prompt("Please enter your authentication token from the browser", hide_input=False) + token = typer.prompt("Please enter your authentication token from the browser", hide_input=False) if not token: - msg = "Token must be provided via CODEGEN_USER_ACCESS_TOKEN environment variable or manual input" - raise click.ClickException(msg) + rich.print("[red]Error:[/red] Token must be provided via CODEGEN_USER_ACCESS_TOKEN environment variable or manual input") + raise typer.Exit(1) # Validate and store token try: @@ -44,5 +44,5 @@ def login_routine(token: str | None = None) -> str: rich.print("To opt out, set [green]telemetry_enabled = false[/green] in [cyan]~/.config/codegen-sh/analytics.json[/cyan] ✨") return token except AuthError as e: - msg = f"Error: {e!s}" - raise click.ClickException(msg) + rich.print(f"[red]Error:[/red] {e!s}") + raise typer.Exit(1) diff --git a/src/codegen/cli/auth/session.py b/src/codegen/cli/auth/session.py index aab6addb3..65c0407d8 100644 --- a/src/codegen/cli/auth/session.py +++ b/src/codegen/cli/auth/session.py @@ -1,7 +1,7 @@ from pathlib import Path -import click import rich +import typer from github import BadCredentialsException from github.MainClass import Github @@ -24,14 +24,14 @@ class CodegenSession: def __init__(self, repo_path: Path, git_token: str | None = None) -> None: if not repo_path.exists(): rich.print(f"\n[bold red]Error:[/bold red] Path to git repo does not exist at {repo_path}") - raise click.Abort() + raise typer.Abort() # Check if it's a valid git repository try: LocalGitRepo(repo_path=repo_path) except Exception: rich.print(f"\n[bold red]Error:[/bold red] Path {repo_path} is not a valid git repository") - raise click.Abort() + raise typer.Abort() self.repo_path = repo_path self.local_git = LocalGitRepo(repo_path=repo_path) @@ -82,12 +82,12 @@ def _validate(self) -> None: rich.print(format_command("git remote add origin ")) try: - if git_token is not None: + if git_token is not None and self.local_git.full_name is not None: Github(login_or_token=git_token).get_repo(self.local_git.full_name) except BadCredentialsException: rich.print(format_command(f"\n[bold red]Error:[/bold red] Invalid GitHub token={git_token} for repo={self.local_git.full_name}")) rich.print("[white]Please provide a valid GitHub token for this repository.[/white]") - raise click.Abort() + raise typer.Abort() def __str__(self) -> str: - return f"CodegenSession(user={self.config.repository.user_name}, repo={self.config.repository.repo_name})" + return f"CodegenSession(user={self.config.repository.user_name}, repo={self.config.repository.name})" diff --git a/src/codegen/cli/cli.py b/src/codegen/cli/cli.py index f5879fa08..49837b649 100644 --- a/src/codegen/cli/cli.py +++ b/src/codegen/cli/cli.py @@ -1,34 +1,53 @@ -import rich_click as click +import typer from rich.traceback import install -# Removed reference to non-existent agent module +# Import config command (still a Typer app) from codegen.cli.commands.config.main import config_command -from codegen.cli.commands.init.main import init_command -from codegen.cli.commands.login.main import login_command -from codegen.cli.commands.logout.main import logout_command -from codegen.cli.commands.profile.main import profile_command -from codegen.cli.commands.style_debug.main import style_debug_command -from codegen.cli.commands.update.main import update_command +from codegen import __version__ install(show_locals=True) -@click.group(name="codegen") -@click.version_option(prog_name="codegen", message="%(version)s") -def main(): +def version_callback(value: bool): + """Print version and exit.""" + if value: + print(__version__) + raise typer.Exit() + +# Create the main Typer app +main = typer.Typer( + name="codegen", + help="Codegen CLI - Transform your code with AI.", + rich_markup_mode="rich" +) + +# Import the actual command functions +from codegen.cli.commands.init.main import init +from codegen.cli.commands.login.main import login +from codegen.cli.commands.logout.main import logout +from codegen.cli.commands.profile.main import profile +from codegen.cli.commands.style_debug.main import style_debug +from codegen.cli.commands.update.main import update + +# Add individual commands to the main app +main.command("init", help="Initialize or update the Codegen folder.")(init) +main.command("login", help="Store authentication token.")(login) +main.command("logout", help="Clear stored authentication token.")(logout) +main.command("profile", help="Display information about the currently authenticated user.")(profile) +main.command("style-debug", help="Debug command to visualize CLI styling (spinners, etc).")(style_debug) +main.command("update", help="Update Codegen to the latest or specified version")(update) + +# Config is a group, so add it as a typer +main.add_typer(config_command, name="config") + + +@main.callback() +def main_callback( + version: bool = typer.Option(False, "--version", callback=version_callback, is_eager=True, help="Show version and exit") +): """Codegen CLI - Transform your code with AI.""" pass -# Add commands to the main group -main.add_command(init_command) -main.add_command(logout_command) -main.add_command(login_command) -main.add_command(profile_command) -main.add_command(style_debug_command) -main.add_command(update_command) -main.add_command(config_command) - - if __name__ == "__main__": main() diff --git a/src/codegen/cli/commands/config/main.py b/src/codegen/cli/commands/config/main.py index b4ec3f3d7..f3b40d943 100644 --- a/src/codegen/cli/commands/config/main.py +++ b/src/codegen/cli/commands/config/main.py @@ -1,22 +1,19 @@ import logging import rich -import rich_click as click +import typer from rich.table import Table from codegen.configs.constants import ENV_FILENAME, GLOBAL_ENV_FILE from codegen.configs.user_config import UserConfig from codegen.shared.path import get_git_root_path - -@click.group(name="config") -def config_command(): - """Manage codegen configuration.""" - pass +# Create a Typer app for the config command +config_command = typer.Typer(help="Manage codegen configuration.") @config_command.command(name="list") -def list_command(): +def list_config(): """List current configuration values.""" def flatten_dict(data: dict, prefix: str = "") -> dict: @@ -80,8 +77,7 @@ def flatten_dict(data: dict, prefix: str = "") -> dict: @config_command.command(name="get") -@click.argument("key") -def get_command(key: str): +def get_config(key: str = typer.Argument(..., help="Configuration key to get")): """Get a configuration value.""" config = _get_user_config() if not config.has_key(key): @@ -94,9 +90,10 @@ def get_command(key: str): @config_command.command(name="set") -@click.argument("key") -@click.argument("value") -def set_command(key: str, value: str): +def set_config( + key: str = typer.Argument(..., help="Configuration key to set"), + value: str = typer.Argument(..., help="Configuration value to set") +): """Set a configuration value and write to .env""" config = _get_user_config() if not config.has_key(key): diff --git a/src/codegen/cli/commands/init/main.py b/src/codegen/cli/commands/init/main.py index b4934f0cb..699cfed26 100644 --- a/src/codegen/cli/commands/init/main.py +++ b/src/codegen/cli/commands/init/main.py @@ -1,33 +1,38 @@ import sys from pathlib import Path +from typing import Optional import rich -import rich_click as click +import typer from codegen.cli.auth.session import CodegenSession from codegen.cli.rich.codeblocks import format_command from codegen.shared.path import get_git_root_path - -@click.command(name="init") -@click.option("--path", type=str, help="Path within a git repository. Defaults to the current directory.") -@click.option("--token", type=str, help="Access token for the git repository. Required for full functionality.") -@click.option("--language", type=click.Choice(["python", "typescript"], case_sensitive=False), help="Override automatic language detection") -@click.option("--fetch-docs", is_flag=True, help="Fetch docs and examples (requires auth)") -def init_command(path: str | None = None, token: str | None = None, language: str | None = None, fetch_docs: bool = False): +def init( + path: Optional[str] = typer.Option(None, help="Path within a git repository. Defaults to the current directory."), + token: Optional[str] = typer.Option(None, help="Access token for the git repository. Required for full functionality."), + language: Optional[str] = typer.Option(None, help="Override automatic language detection (python or typescript)"), + fetch_docs: bool = typer.Option(False, "--fetch-docs", help="Fetch docs and examples (requires auth)") +): """Initialize or update the Codegen folder.""" + # Validate language option + if language and language.lower() not in ["python", "typescript"]: + rich.print(f"[bold red]Error:[/bold red] Invalid language '{language}'. Must be 'python' or 'typescript'.") + raise typer.Exit(1) + # Print a message if not in a git repo - path = Path.cwd() if path is None else Path(path) - repo_path = get_git_root_path(path) + current_path = Path.cwd() if path is None else Path(path) + repo_path = get_git_root_path(current_path) rich.print(f"Found git repository at: {repo_path}") if repo_path is None: - rich.print(f"\n[bold red]Error:[/bold red] Path={path} is not in a git repository") + rich.print(f"\n[bold red]Error:[/bold red] Path={current_path} is not in a git repository") rich.print("[white]Please run this command from within a git repository.[/white]") rich.print("\n[dim]To initialize a new git repository:[/dim]") rich.print(format_command("git init")) rich.print(format_command("codegen init")) - sys.exit(1) + raise typer.Exit(1) session = CodegenSession(repo_path=repo_path, git_token=token) if language: diff --git a/src/codegen/cli/commands/login/main.py b/src/codegen/cli/commands/login/main.py index 27448df42..a5355847f 100644 --- a/src/codegen/cli/commands/login/main.py +++ b/src/codegen/cli/commands/login/main.py @@ -1,16 +1,15 @@ -import rich_click as click +from typing import Optional +import typer +import rich from codegen.cli.auth.login import login_routine from codegen.cli.auth.token_manager import get_current_token - -@click.command(name="login") -@click.option("--token", required=False, help="API token for authentication") -def login_command(token: str): +def login(token: Optional[str] = typer.Option(None, help="API token for authentication")): """Store authentication token.""" # Check if already authenticated if get_current_token(): - msg = "Already authenticated. Use 'codegen logout' to clear the token." - raise click.ClickException(msg) + rich.print("[yellow]Warning:[/yellow] Already authenticated. Use 'codegen logout' to clear the token.") + raise typer.Exit(1) login_routine(token) diff --git a/src/codegen/cli/commands/logout/main.py b/src/codegen/cli/commands/logout/main.py index 93216bea0..e551a722a 100644 --- a/src/codegen/cli/commands/logout/main.py +++ b/src/codegen/cli/commands/logout/main.py @@ -1,11 +1,9 @@ import rich -import rich_click as click +import typer from codegen.cli.auth.token_manager import TokenManager - -@click.command(name="logout") -def logout_command(): +def logout(): """Clear stored authentication token.""" token_manager = TokenManager() token_manager.clear_token() diff --git a/src/codegen/cli/commands/profile/main.py b/src/codegen/cli/commands/profile/main.py index 75a8d86de..b1116340c 100644 --- a/src/codegen/cli/commands/profile/main.py +++ b/src/codegen/cli/commands/profile/main.py @@ -1,5 +1,5 @@ import rich -import rich_click as click +import typer from rich import box from rich.panel import Panel @@ -13,16 +13,14 @@ def requires_init(func): """Simple stub decorator that does nothing.""" return func - -@click.command(name="profile") @requires_auth @requires_init -def profile_command(session: CodegenSession): +def profile(session: CodegenSession): """Display information about the currently authenticated user.""" repo_config = session.config.repository rich.print( Panel( - f"[cyan]Name:[/cyan] {repo_config.user_name}\n[cyan]Email:[/cyan] {repo_config.user_email}\n[cyan]Repo:[/cyan] {repo_config.repo_name}", + f"[cyan]Name:[/cyan] {repo_config.user_name}\n[cyan]Email:[/cyan] {repo_config.user_email}\n[cyan]Repo:[/cyan] {repo_config.name}", title="🔑 [bold]Current Profile[/bold]", border_style="cyan", box=box.ROUNDED, diff --git a/src/codegen/cli/commands/style_debug/main.py b/src/codegen/cli/commands/style_debug/main.py index 642c16f86..e73514b2d 100644 --- a/src/codegen/cli/commands/style_debug/main.py +++ b/src/codegen/cli/commands/style_debug/main.py @@ -2,14 +2,11 @@ import time -import rich_click as click +import typer from codegen.cli.rich.spinners import create_spinner - -@click.command(name="style-debug") -@click.option("--text", default="Loading...", help="Text to show in the spinner") -def style_debug_command(text: str): +def style_debug(text: str = typer.Option("Loading...", help="Text to show in the spinner")): """Debug command to visualize CLI styling (spinners, etc).""" try: with create_spinner(text) as status: diff --git a/src/codegen/cli/commands/update/main.py b/src/codegen/cli/commands/update/main.py index 83b64fd98..6f3903dcf 100644 --- a/src/codegen/cli/commands/update/main.py +++ b/src/codegen/cli/commands/update/main.py @@ -1,10 +1,11 @@ import subprocess import sys from importlib.metadata import distribution +from typing import Optional import requests import rich -import rich_click as click +import typer from packaging.version import Version import codegen @@ -30,24 +31,18 @@ def install_package(package: str, *args: str) -> None: subprocess.check_call([sys.executable, "-m", "pip", "install", package, *args]) -@click.command(name="update") -@click.option( - "--list", - "-l", - "list_", - is_flag=True, - help="List all supported versions of the codegen", -) -@click.option("--version", "-v", type=str, help="Update to a specific version of the codegen") -def update_command(list_: bool = False, version: str | None = None): +def update( + list_: bool = typer.Option(False, "--list", "-l", help="List all supported versions of the codegen"), + version: Optional[str] = typer.Option(None, "--version", "-v", help="Update to a specific version of the codegen") +): """Update Codegen to the latest or specified version --list: List all supported versions of the codegen --version: Update to a specific version of the codegen """ if list_ and version: - msg = "Cannot specify both --list and --version" - raise click.ClickException(msg) + rich.print("[red]Error:[/red] Cannot specify both --list and --version") + raise typer.Exit(1) package_info = distribution(codegen.__package__) current_version = Version(package_info.version) diff --git a/src/codegen/cli/errors.py b/src/codegen/cli/errors.py index f2a9061cb..a4f0fd536 100644 --- a/src/codegen/cli/errors.py +++ b/src/codegen/cli/errors.py @@ -2,7 +2,7 @@ import functools import rich -import rich_click as click +import typer from rich.panel import Panel @@ -55,6 +55,6 @@ def wrapper(*args, **kwargs): return f(*args, **kwargs) except AuthError: rich.print(Panel("[red]Authentication Error:[/red] Please run 'codegen login' first.", title="Codegen Error", border_style="red")) - raise click.Abort() + raise typer.Abort() return wrapper diff --git a/src/codegen/cli/mcp/server.py b/src/codegen/cli/mcp/server.py index 219b939f6..cdb76c20f 100644 --- a/src/codegen/cli/mcp/server.py +++ b/src/codegen/cli/mcp/server.py @@ -79,12 +79,8 @@ def improve_codemod( ctx: Context, ) -> str: """Improve the codemod.""" - try: - client = RestAPI() - response = client.improve_codemod(codemod_source, task, concerns, context, language) - return response.codemod_source - except Exception as e: - return f"Error: {e}" + # TODO: Implement improve_codemod functionality + return f"Error: improve_codemod functionality not yet implemented" if __name__ == "__main__": diff --git a/src/codegen/cli/utils/codemod_manager.py b/src/codegen/cli/utils/codemod_manager.py index 34803bf0d..06ee6871d 100644 --- a/src/codegen/cli/utils/codemod_manager.py +++ b/src/codegen/cli/utils/codemod_manager.py @@ -1,7 +1,8 @@ import builtins from pathlib import Path -import rich_click as click +import rich +import typer from codegen.cli.utils.function_finder import DecoratedFunction, find_codegen_functions @@ -39,7 +40,7 @@ def get_codemod(cls, name: str, start_path: Path | None = None) -> DecoratedFunc The validated DecoratedFunction Raises: - click.ClickException: If codemod can't be found or loaded + typer.Exit: If codemod can't be found or loaded """ # First try to find the codemod codemod = cls.get(name, start_path) @@ -47,11 +48,14 @@ def get_codemod(cls, name: str, start_path: Path | None = None) -> DecoratedFunc # If not found, check if any codemods exist all_codemods = cls.list(start_path) if not all_codemods: - raise click.ClickException("No codemods found. Create one with:\n" + " codegen create my-codemod") + rich.print("[red]Error:[/red] No codemods found. Create one with:") + rich.print(" codegen create my-codemod") + raise typer.Exit(1) else: available = "\n ".join(f"- {c.name}" for c in all_codemods) - msg = f"Codemod '{name}' not found. Available codemods:\n {available}" - raise click.ClickException(msg) + rich.print(f"[red]Error:[/red] Codemod '{name}' not found. Available codemods:") + rich.print(f" {available}") + raise typer.Exit(1) # Verify we can import it try: @@ -59,8 +63,8 @@ def get_codemod(cls, name: str, start_path: Path | None = None) -> DecoratedFunc codemod.validate() return codemod except Exception as e: - msg = f"Error loading codemod '{name}': {e!s}" - raise click.ClickException(msg) + rich.print(f"[red]Error:[/red] Error loading codemod '{name}': {e!s}") + raise typer.Exit(1) @classmethod def list(cls, start_path: Path | None = None) -> builtins.list[DecoratedFunction]: diff --git a/src/codegen/cli/utils/codemods.py b/src/codegen/cli/utils/codemods.py index cf4914ced..c704d9629 100644 --- a/src/codegen/cli/utils/codemods.py +++ b/src/codegen/cli/utils/codemods.py @@ -15,11 +15,13 @@ class Codemod: def get_url(self) -> str: """Get the URL for this codemod.""" + if self.config is None: + return "" return generate_webapp_url(path=f"codemod/{self.config.codemod_id}") def relative_path(self) -> str: """Get the relative path to this codemod.""" - return self.path.relative_to(Path.cwd()) + return str(self.path.relative_to(Path.cwd())) def get_current_source(self) -> str: """Get the current source code for this codemod.""" diff --git a/src/codegen/cli/utils/function_finder.py b/src/codegen/cli/utils/function_finder.py index bf5938b98..b62c9b46e 100644 --- a/src/codegen/cli/utils/function_finder.py +++ b/src/codegen/cli/utils/function_finder.py @@ -86,6 +86,7 @@ def validate(self) -> None: class CodegenFunctionVisitor(ast.NodeVisitor): def __init__(self): self.functions: list[DecoratedFunction] = [] + self.file_content: str = "" def get_function_name(self, node: ast.Call) -> str: keywords = {k.arg: k.value for k in node.keywords} @@ -104,7 +105,11 @@ def get_subdirectories(self, node: ast.Call) -> list[str] | None: def get_language(self, node: ast.Call) -> ProgrammingLanguage | None: keywords = {k.arg: k.value for k in node.keywords} if "language" in keywords: - return ProgrammingLanguage(keywords["language"].attr) + lang_node = keywords["language"] + if hasattr(lang_node, 'attr'): + return ProgrammingLanguage(lang_node.attr) + else: + return ProgrammingLanguage(ast.literal_eval(lang_node)) if len(node.args) > 2: return ast.literal_eval(node.args[2]) return None @@ -259,6 +264,8 @@ def _extract_arguments_type_schema(func: DecoratedFunction) -> dict | None: """Extracts the arguments type schema from a DecoratedFunction object.""" try: spec = importlib.util.spec_from_file_location("module", func.filepath) + if spec is None or spec.loader is None: + return None module = importlib.util.module_from_spec(spec) fn_arguments_param_type = None diff --git a/src/codegen/cli/utils/json_schema.py b/src/codegen/cli/utils/json_schema.py index d34ae6583..1e228bdca 100644 --- a/src/codegen/cli/utils/json_schema.py +++ b/src/codegen/cli/utils/json_schema.py @@ -1,6 +1,7 @@ import json from pathlib import Path from tempfile import TemporaryDirectory +from typing import Any from datamodel_code_generator import DataModelType, InputFileType, generate from pydantic import BaseModel @@ -14,7 +15,7 @@ def get_schema(model: BaseModel) -> dict: def validate_json(schema: dict, json_data: str) -> bool: json_schema = json.dumps(schema) - exec_scope = {} + exec_scope: dict[str, Any] = {} model_name = schema["title"] with TemporaryDirectory() as temporary_directory_name: temporary_directory = Path(temporary_directory_name) @@ -31,6 +32,8 @@ def validate_json(schema: dict, json_data: str) -> bool: exec(output.read_text(), exec_scope, exec_scope) print(f"exec_scope: {exec_scope}") model = exec_scope.get(model_name) + if model is None: + return False try: model.model_validate_json(json_data) return True diff --git a/src/codegen/cli/utils/schema.py b/src/codegen/cli/utils/schema.py index 7f82c470b..aa1a777a0 100644 --- a/src/codegen/cli/utils/schema.py +++ b/src/codegen/cli/utils/schema.py @@ -1,16 +1,26 @@ -from typing import Self +from typing import Any, Self from pydantic import BaseModel class SafeBaseModel(BaseModel): @classmethod - def model_validate(cls, data: dict) -> "Self": + def model_validate( + cls, + obj: Any, + *, + strict: bool | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None + ) -> "Self": try: - return super().model_validate(data) + return super().model_validate(obj, strict=strict, from_attributes=from_attributes, context=context, by_alias=by_alias, by_name=by_name) except Exception as e: print(e) - return None + # Return a default instance instead of None to maintain compatibility + return cls() def __str__(self) -> str: return self.model_dump_json(indent=4) diff --git a/uv.lock b/uv.lock index 3780239b2..482d5896b 100644 --- a/uv.lock +++ b/uv.lock @@ -408,7 +408,6 @@ wheels = [ name = "codegen" source = { editable = "." } dependencies = [ - { name = "click" }, { name = "codegen-api-client" }, { name = "codeowners" }, { name = "colorlog" }, @@ -427,8 +426,8 @@ dependencies = [ { name = "python-dotenv" }, { name = "requests" }, { name = "rich" }, - { name = "rich-click" }, { name = "sentry-sdk" }, + { name = "typer" }, { name = "unidiff" }, ] @@ -470,7 +469,6 @@ dev = [ [package.metadata] requires-dist = [ - { name = "click", specifier = ">=8.1.7" }, { name = "codegen-api-client" }, { name = "codeowners", specifier = ">=0.6.0" }, { name = "colorlog", specifier = ">=6.9.0" }, @@ -489,8 +487,8 @@ requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.1" }, { name = "requests", specifier = ">=2.32.3" }, { name = "rich", specifier = ">=13.7.1" }, - { name = "rich-click", specifier = ">=1.8.5" }, { name = "sentry-sdk", specifier = "==2.29.1" }, + { name = "typer", specifier = ">=0.12.5" }, { name = "unidiff", specifier = ">=0.7.5" }, ] provides-extras = ["types"]