Source code for ats_linter.cli

"""Copyright (c) 2023 Aydin Abdi.

CLI for the Automated Test Schema Linter (ATS Linter).
Modern, typed, and Pythonic using Typer.
"""

import sys
from typing import Annotated

import typer
from colorama import just_fix_windows_console
from loguru import logger

from ats_linter.linter import ATSTestCasesFactory, ATSTestCasesLinter
from ats_linter.parallel_process import FileProcessorCocurrent

# Force loguru to always colorize output, even in Docker
logger.remove()
logger.add(sys.stderr, colorize=True)

app = typer.Typer(help="ATS Linter: Lint your test files for docstring compliance.")


def _process_files(files_to_process: list[str]) -> list:
    """Process files and extract test cases."""
    test_cases = []
    for file_path in files_to_process:
        try:
            file_processor = FileProcessorCocurrent(file_path)
            for module in file_processor:
                logger.debug(f"Module: {getattr(module, 'file_path', repr(module))}")
                for test_class in module.test_classes:
                    logger.debug(f"  TestClass: {test_class.name}")
                    test_cases.extend(test_class.test_cases)
                test_cases.extend(module.test_cases)
        except Exception as e:
            logger.error(f"Error parsing file {file_path}: {e}")
            raise typer.Exit(code=1) from e
    return test_cases


[docs] @app.command() def main( files: Annotated[ list[str], typer.Argument(help="Files or directories to lint (default: tests/ directory)"), ] = None, debug: Annotated[ bool, typer.Option("--debug", help="Enable debug logging") ] = False, ) -> None: """Lint test files for docstring compliance. Args: files: Files or directories to lint (default: tests/ directory) debug: Enable debug logging """ just_fix_windows_console() # Configure logging if debug: logger.remove() logger.add(sys.stderr, level="DEBUG", colorize=True) else: logger.remove() logger.add(sys.stderr, level="INFO", colorize=True) # Determine files to process files_to_process = files if files else ["tests/"] logger.debug(f"Linting files: {files_to_process}") # Process files and extract test cases test_cases = _process_files(files_to_process) if not test_cases: logger.warning("No test cases found to lint.") raise typer.Exit(code=0) # Run linter ats_cases = ATSTestCasesFactory(test_cases).ats_test_cases linter = ATSTestCasesLinter(ats_cases) status = linter.lint() # Report results if status: logger.opt(colors=True).success( "\n<green><b>Automated Test Schema Linter: PASSED</b></green>" ) raise typer.Exit(code=0) else: logger.opt(colors=True).error( "\n<red><b>Automated Test Schema Linter: FAILED</b></red>" ) raise typer.Exit(code=1)
[docs] def run() -> None: """Entry point for the CLI.""" app()
if __name__ == "__main__": run()