Source code for uv_start.router

import subprocess
from argparse import Namespace
from dataclasses import dataclass
from pathlib import Path

from rich import print as rprint
from rich.prompt import Prompt

from uv_start.config import clean_env
from uv_start.exceptions import ProjectCreationError


[docs] @dataclass class CommandDispatcher: """Dispatch commands based on argument pattern""" args: Namespace original_cwd: Path def __post_init__(self) -> None: self.project_path = self.original_cwd / self.args.project_name
[docs] def check_dir_exists(self) -> None: if self.project_path.exists(): raise ProjectCreationError( f"Cannot create project '{self.args.project_name}'\n" f"Directory already exists at: {self.original_cwd}\n\n" "Try using a different project name or remove the existing directory." )
[docs] def dispatch(self) -> None: """Route to appropriate command handler based on argument pattern""" if getattr(self.args, "data", False): self._create_data_project() return flags = self._get_project_flags() self._create_project(flags, workspace=self.args.workspace)
def _get_project_flags(self) -> list[str]: """Convert project type to uv flags""" match self.args.type: case "lib": return ["--lib"] case "app": return ["--app", "--package"] case "package": return ["--package"] case _: raise ValueError(f"Unknown project type: {self.args.type}") def _create_project( self, flags: list[str], workspace: bool = False ) -> None: """Create a new project with specified flags""" project_type = " ".join(flag.strip("-") for flag in flags) rprint( f"[green]Creating {project_type} project at {self.original_cwd}...[/green]" ) try: subprocess.run( [ "uv", "init", self.args.project_name, *flags, "--python", self.args.python, ], check=True, cwd=self.original_cwd, env=clean_env(), ) # Create tests directory tests_dir = self.project_path / "tests" tests_dir.mkdir(exist_ok=True) # Create an empty __init__.py in tests directory (tests_dir / "test_init.py").touch() with open(tests_dir / "test_init.py", "w") as f: f.write("def test_init():\n assert True\n") rprint( f"[green]✓[/green] Successfully created {project_type} project '[bold]{self.args.project_name}[/bold]'" ) if workspace: self._initialize_workspace() except subprocess.CalledProcessError as e: raise ProjectCreationError( f"Failed to create {project_type} project: {e}" ) from e def _initialize_workspace(self) -> None: """Initialize workspace configuration after project creation""" packages_path = self.project_path / "packages" packages_path.mkdir(exist_ok=True) rprint("[green]Initializing workspace...[/green]") common_utils = Prompt.ask( "Do you want to add common utilities?", choices=["y", "n"], default="n", ) if common_utils == "y": utils_name = Prompt.ask("Enter the name of the utils library: ") self._add_common_utils(utils_name) other_projects = Prompt.ask( "Do you want to add other projects?", choices=["y", "n"], default="n", ) if other_projects == "y": project_name = Prompt.ask("Enter the project-name: ") self._add_other_projects(project_name) def _add_common_utils(self, utils_name: str) -> None: """Add common utilities to the workspace""" try: subprocess.run( [ "uv", "init", utils_name, "--lib", ], check=True, cwd=self.project_path / "packages", env=clean_env(), ) subprocess.run( [ "uv", "add", f"./packages/{utils_name}", "--editable", ], check=True, cwd=self.project_path, env=clean_env(), ) rprint("[green]✓[/green] Successfully added common_utils'") except subprocess.CalledProcessError as e: raise ProjectCreationError( f"Failed to create common_utils: {e}" ) from e def _create_data_project(self) -> None: """Create a plain data analysis project with scientific Python stack.""" rprint( f"[green]Creating data analysis project at {self.original_cwd}...[/green]" ) try: subprocess.run( [ "uv", "init", self.args.project_name, "--python", self.args.python, ], check=True, cwd=self.original_cwd, env=clean_env(), ) subprocess.run( [ "uv", "add", "jupyter", "pandas", "matplotlib", "seaborn", ], check=True, cwd=self.project_path, env=clean_env(), ) rprint( f"[green]✓[/green] Successfully created data project '[bold]{self.args.project_name}[/bold]'" ) except subprocess.CalledProcessError as e: raise ProjectCreationError( f"Failed to create data project: {e}" ) from e def _add_other_projects(self, project_name: str) -> None: """Add other projects to the workspace""" try: subprocess.run( [ "uv", "init", project_name, "--package", "--app", ], check=True, cwd=self.project_path / "packages", env=clean_env(), ) subprocess.run( [ "uv", "add", f"./packages/{project_name}", "--editable", ], check=True, cwd=self.project_path, env=clean_env(), ) rprint(f"[green]✓[/green] Successfully created {project_name}") except subprocess.CalledProcessError as e: raise ProjectCreationError( f"Failed to create {project_name}: {e}" ) from e