diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1638328..7ab11ea 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: check-yaml - id: check-toml @@ -11,13 +11,13 @@ repos: - id: detect-private-key - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.2 + rev: v0.16.4 hooks: - id: ruff args: ["--fix"] - id: ruff-format - repo: https://github.com/commitizen-tools/commitizen - rev: v4.8.3 + rev: v4.18.0 hooks: - id: commitizen diff --git a/cmdc/cli.py b/cmdc/cli.py index 1394709..88c12c4 100644 --- a/cmdc/cli.py +++ b/cmdc/cli.py @@ -1,6 +1,5 @@ import sys from pathlib import Path -from typing import List, Optional import typer from rich.console import Console @@ -69,12 +68,12 @@ def main( "--list-ignore", help="Display the full list of ignore patterns in a detailed view.", ), - add_ignore: Optional[List[str]] = typer.Option( + add_ignore: list[str] | None = typer.Option( None, "--add-ignore", help="Add new patterns to the ignore list in the configuration.", ), - directory: Optional[Path] = typer.Argument( + directory: Path | None = typer.Argument( None, exists=True, file_okay=False, @@ -89,19 +88,19 @@ def main( "-o", help="Output mode: 'console' or a filename to save the extracted content.", ), - filters: Optional[List[str]] = typer.Option( + filters: list[str] | None = typer.Option( None, "--filters", "-f", help="Filter files by extension (e.g., .py .js).", ), - recursive: Optional[bool] = typer.Option( + recursive: bool | None = typer.Option( None, "--recursive", "-r", help="Recursively traverse subdirectories.", ), - ignore: Optional[List[str]] = typer.Option( + ignore: list[str] | None = typer.Option( None, "--ignore", "-i", @@ -112,19 +111,19 @@ def main( "--non-interactive", help="Select all matching files without prompting.", ), - use_gitignore: Optional[bool] = typer.Option( + use_gitignore: bool | None = typer.Option( None, "--use-gitignore/--no-gitignore", help="Whether to use .gitignore files in scanned directories (overrides config).", ), - depth: Optional[int] = typer.Option( + depth: int | None = typer.Option( None, "--depth", "-d", help="Maximum depth for subdirectory exploration. " "Overrides config setting if provided and recursive mode is not used.", ), - encoding_model: Optional[str] = typer.Option( + encoding_model: str | None = typer.Option( "o200k_base", "--encoding-model", help="Token encoding model to use for token counting (overrides config).", diff --git a/cmdc/config_manager.py b/cmdc/config_manager.py index c25833a..00391a9 100644 --- a/cmdc/config_manager.py +++ b/cmdc/config_manager.py @@ -1,6 +1,5 @@ import os from pathlib import Path -from typing import List, Optional import toml import typer @@ -45,7 +44,7 @@ def ensure_config_dir(self) -> None: self.config_dir.mkdir(parents=True, exist_ok=True) @staticmethod - def get_default_ignore_patterns() -> List[str]: + def get_default_ignore_patterns() -> list[str]: """Return the default list of ignore patterns.""" return [ ".git", @@ -119,8 +118,7 @@ def interactive_config(self) -> dict: ).execute() try: default_depth = int(default_depth_str) - if default_depth < 1: - default_depth = 1 + default_depth = max(default_depth, 1) except ValueError: default_depth = 1 @@ -261,7 +259,7 @@ def get_env_config() -> dict: return env_config @staticmethod - def get_gitignore_patterns(directory: Path) -> List[str]: + def get_gitignore_patterns(directory: Path) -> list[str]: """ Parse .gitignore file in the given directory and return valid ignore patterns. Skips comments and empty lines. @@ -296,7 +294,7 @@ def get_gitignore_patterns(directory: Path) -> List[str]: return patterns - def load_config(self, directory: Optional[Path] = None) -> dict: + def load_config(self, directory: Path | None = None) -> dict: """ Load configuration using a layered approach: 1. Start with defaults @@ -357,9 +355,7 @@ def handle_config(self, force: bool) -> None: ) except Exception as e: console.print( - Panel( - f"[red]Error saving configuration:[/red]\n{str(e)}", title="Error" - ) + Panel(f"[red]Error saving configuration:[/red]\n{e!s}", title="Error") ) raise typer.Exit(1) @@ -447,7 +443,7 @@ def display_ignore_patterns(self) -> None: ) console.print() - def add_ignore_patterns(self, new_patterns: List[str]) -> None: + def add_ignore_patterns(self, new_patterns: list[str]) -> None: """Add new patterns to the ignore list in the configuration.""" self.ensure_config_dir() diff --git a/cmdc/file_browser.py b/cmdc/file_browser.py index 033e05b..5c42d84 100644 --- a/cmdc/file_browser.py +++ b/cmdc/file_browser.py @@ -1,7 +1,7 @@ import fnmatch import os +from collections.abc import Iterable from pathlib import Path -from typing import Iterable, List, Optional, Tuple import typer from InquirerPy import inquirer @@ -43,9 +43,9 @@ def __init__( self, directory: Path, recursive: bool, - filters: List[str], - ignore_patterns: List[str], - depth: Optional[int] = None, + filters: list[str], + ignore_patterns: list[str], + depth: int | None = None, encoding_model: str = "o200k_base", ): self.directory = directory @@ -62,7 +62,7 @@ def _extract_relative(display_str: str) -> str: """ return display_str.split(" [")[0] - def _transform_selection(self, selected: List[str], token_counts: dict) -> str: + def _transform_selection(self, selected: list[str], token_counts: dict) -> str: """ Transform the selection display to show file count and total token count. """ @@ -152,7 +152,7 @@ def walk_valid_paths(self) -> Iterable[Path]: except PermissionError: pass - def get_files(self) -> List[Path]: + def get_files(self) -> list[Path]: """ Retrieve a list of files from the directory that match the filters and do not match the ignore patterns. @@ -176,7 +176,7 @@ def build_tree(self) -> Tree: style_file=lambda x: f"[green]{x}[/green]", ) - def scan_and_select_files(self, non_interactive: bool) -> Tuple[List[str], int]: + def scan_and_select_files(self, non_interactive: bool) -> tuple[list[str], int]: """ Scan the directory and prompt the user to select files (unless in non-interactive mode). Returns: diff --git a/cmdc/output_handler.py b/cmdc/output_handler.py index 972885f..4aa1252 100644 --- a/cmdc/output_handler.py +++ b/cmdc/output_handler.py @@ -1,13 +1,12 @@ import fnmatch +from collections.abc import Iterable from pathlib import Path -from typing import List, Iterable import pyperclip import typer from rich.console import Console from rich.panel import Panel - console = Console() @@ -23,7 +22,7 @@ def __init__( directory: Path, copy_to_clipboard: bool, print_to_console: bool = False, - ignore_patterns: List[str] = None, + ignore_patterns: list[str] = None, ): self.directory = directory self.copy_to_clipboard = copy_to_clipboard @@ -90,7 +89,7 @@ def build_xml_tree(directory, indent=" "): return xml_output - def create_summary_section(self, selected_files: List[str]) -> str: + def create_summary_section(self, selected_files: list[str]) -> str: """Create a summary section with the list of files and directory tree.""" summary = "\n" @@ -109,7 +108,7 @@ def create_summary_section(self, selected_files: List[str]) -> str: summary += "\n" return summary - def process_output(self, selected_files: List[str], output_mode: str) -> tuple: + def process_output(self, selected_files: list[str], output_mode: str) -> tuple: """ Process and output the selected files' contents. """ diff --git a/cmdc/utils.py b/cmdc/utils.py index a35d255..de658bc 100644 --- a/cmdc/utils.py +++ b/cmdc/utils.py @@ -1,6 +1,6 @@ import os +from collections.abc import Callable, Iterable from pathlib import Path -from typing import Callable, Dict, Iterable, List import tiktoken from rich.tree import Tree @@ -17,8 +17,8 @@ def clear_console() -> None: def _add_paths_to_tree( current_dir: Path, current_tree: Tree, - paths_by_parent: Dict[Path, List[Path]], - valid_paths: List[Path], + paths_by_parent: dict[Path, list[Path]], + valid_paths: list[Path], file_filter: Callable[[Path], bool], style_directory: Callable[[str], str], style_file: Callable[[str], str], @@ -77,7 +77,7 @@ def build_directory_tree( valid_paths = list(walk_function()) # Create a mapping of parent directories to their children - paths_by_parent: Dict[Path, List[Path]] = {} + paths_by_parent: dict[Path, list[Path]] = {} for path in valid_paths: if path == directory: continue