thailint 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
src/.ai/layout.yaml ADDED
@@ -0,0 +1,48 @@
1
+ file-placement:
2
+ directories:
3
+ .ai:
4
+ allow:
5
+ - .*\\.(md|yaml|yml)$
6
+ .roadmap:
7
+ allow:
8
+ - .*\\.md$
9
+ docs:
10
+ allow:
11
+ - .*\\.(md|rst|txt|py)$
12
+ deny:
13
+ - ^(?!.*\\.(md|rst|txt|py)$).*
14
+ src:
15
+ allow:
16
+ - .*\\.py$
17
+ deny:
18
+ - test_.*\\.py$
19
+ - .*_test\\.py$
20
+ tests:
21
+ allow:
22
+ - test_.*\\.py$
23
+ - .*_test\\.py$
24
+ - conftest\\.py$
25
+ - __init__\\.py$
26
+ deny:
27
+ - ^(?!test_|.*_test\\.py|conftest\\.py|__init__\\.py).*\\.py$
28
+ global_patterns:
29
+ deny:
30
+ - message: Python files should be in src/, tests/, scripts/, docs/, .ai/, or .roadmap/
31
+ directories
32
+ pattern: ^(?!src/|tests/|scripts/|docs/|\\.ai/|\\.roadmap/).*\\.py$
33
+ ignore:
34
+ - __pycache__/
35
+ - '*.pyc'
36
+ - .git/
37
+ - .venv/
38
+ - venv/
39
+ - .pytest_cache/
40
+ - .mypy_cache/
41
+ - .ruff_cache/
42
+ - htmlcov/
43
+ - '*.egg-info/'
44
+ - dist/
45
+ - build/
46
+ nesting:
47
+ enabled: true
48
+ max_nesting_depth: 3
src/__init__.py ADDED
@@ -0,0 +1,49 @@
1
+ """
2
+ Purpose: Package initialization and version definition for CLI application
3
+
4
+ Scope: Package-level exports and metadata
5
+
6
+ Overview: Initializes the CLI application package, defines version number using semantic versioning,
7
+ and exports the public API. Provides single source of truth for version information used by
8
+ setup tools, CLI help text, and documentation. Exports main CLI entry point, high-level Linter
9
+ class for library usage, configuration utilities, and direct linter imports for advanced usage.
10
+ Includes nesting depth linter exports for convenient access to nesting analysis functionality.
11
+
12
+ Dependencies: None (minimal imports for package initialization)
13
+
14
+ Exports: __version__, Linter (high-level API), cli (CLI entry point), load_config, save_config,
15
+ ConfigError, Orchestrator (advanced usage), file_placement_lint, nesting_lint, NestingDepthRule
16
+
17
+ Interfaces: Package version string, Linter class API, CLI command group, configuration functions
18
+ """
19
+
20
+ __version__ = "0.1.0"
21
+
22
+ # High-level Library API (primary interface)
23
+ from src.api import Linter
24
+
25
+ # CLI interface
26
+ from src.cli import cli
27
+ from src.config import ConfigError, load_config, save_config
28
+
29
+ # Advanced/direct imports (backwards compatibility)
30
+ from src.linters.file_placement import lint as file_placement_lint
31
+ from src.linters.nesting import NestingDepthRule
32
+ from src.linters.nesting import lint as nesting_lint
33
+ from src.orchestrator.core import Orchestrator
34
+
35
+ __all__ = [
36
+ "__version__",
37
+ # Primary Library API
38
+ "Linter",
39
+ # CLI
40
+ "cli",
41
+ "load_config",
42
+ "save_config",
43
+ "ConfigError",
44
+ # Advanced/direct usage (backwards compatibility)
45
+ "Orchestrator",
46
+ "file_placement_lint",
47
+ "nesting_lint",
48
+ "NestingDepthRule",
49
+ ]
src/api.py ADDED
@@ -0,0 +1,118 @@
1
+ """
2
+ Purpose: High-level Library API providing clean programmatic interface for thailint
3
+
4
+ Scope: Public API for library usage without CLI, supporting configuration and linting operations
5
+
6
+ Overview: Provides high-level Linter class that serves as the primary entry point for using
7
+ thailint as a library in other Python applications. Wraps the Orchestrator with a clean,
8
+ user-friendly API that handles configuration loading, path normalization, rule filtering,
9
+ and violation collection. Supports initialization with config files or project roots,
10
+ autodiscovery of .thailint.yaml/.thailint.json in project directory, and flexible linting
11
+ with optional rule filtering. Designed for embedding in editors, CI/CD pipelines, testing
12
+ frameworks, and automation tools. Maintains backwards compatibility with existing direct
13
+ imports while providing improved ergonomics for library users.
14
+
15
+ Dependencies: pathlib for path handling, Orchestrator from orchestrator.core for linting engine,
16
+ LinterConfigLoader from linter_config.loader for configuration, Violation from core.types
17
+
18
+ Exports: Linter class as primary library API
19
+
20
+ Interfaces: Linter(config_file=None, project_root=None) initialization,
21
+ lint(path, rules=None) -> list[Violation] method
22
+
23
+ Implementation: Thin wrapper around Orchestrator with enhanced configuration handling,
24
+ path normalization (str/Path support), rule filtering by name, and graceful error handling
25
+ """
26
+
27
+ from pathlib import Path
28
+
29
+ from src.core.types import Violation
30
+ from src.linter_config.loader import LinterConfigLoader
31
+ from src.orchestrator.core import Orchestrator
32
+
33
+
34
+ class Linter:
35
+ """High-level linter API for programmatic usage.
36
+
37
+ Provides clean interface for using thailint as a library without CLI.
38
+ Supports configuration files, project root detection, and rule filtering.
39
+
40
+ Example:
41
+ >>> from src import Linter
42
+ >>> linter = Linter(config_file='.thailint.yaml')
43
+ >>> violations = linter.lint('src/', rules=['file-placement'])
44
+ """
45
+
46
+ def __init__(
47
+ self,
48
+ config_file: str | Path | None = None,
49
+ project_root: str | Path | None = None,
50
+ ):
51
+ """Initialize linter with configuration.
52
+
53
+ Args:
54
+ config_file: Path to config file (.thailint.yaml or .thailint.json).
55
+ If not provided, will autodiscover in project_root.
56
+ project_root: Root directory of project. Defaults to current directory.
57
+ """
58
+ self.project_root = Path(project_root) if project_root else Path.cwd()
59
+ self.config_loader = LinterConfigLoader()
60
+
61
+ config_path = self._resolve_config_path(config_file)
62
+ self.config = self.config_loader.load(config_path)
63
+ self.orchestrator = Orchestrator(project_root=self.project_root)
64
+
65
+ def _resolve_config_path(self, config_file: str | Path | None) -> Path:
66
+ """Resolve configuration file path."""
67
+ if config_file:
68
+ return Path(config_file)
69
+
70
+ yaml_path = self.project_root / ".thailint.yaml"
71
+ if yaml_path.exists():
72
+ return yaml_path
73
+ return self.project_root / ".thailint.json"
74
+
75
+ def lint(
76
+ self,
77
+ path: str | Path,
78
+ rules: list[str] | None = None,
79
+ ) -> list[Violation]:
80
+ """Lint a file or directory.
81
+
82
+ Args:
83
+ path: Path to file or directory to lint. Accepts string or Path.
84
+ rules: Optional list of rule names to run. If None, runs all rules.
85
+ Example: ['file-placement']
86
+
87
+ Returns:
88
+ List of violations found.
89
+
90
+ Example:
91
+ >>> linter = Linter()
92
+ >>> violations = linter.lint('src/', rules=['file-placement'])
93
+ >>> for v in violations:
94
+ ... print(f"{v.file_path}: {v.message}")
95
+ """
96
+ path_obj = Path(path) if isinstance(path, str) else path
97
+
98
+ if not path_obj.exists():
99
+ return []
100
+
101
+ violations = self._lint_path(path_obj)
102
+ return self._filter_violations(violations, rules)
103
+
104
+ def _lint_path(self, path_obj: Path) -> list[Violation]:
105
+ """Lint a path (file or directory)."""
106
+ if path_obj.is_file():
107
+ return self.orchestrator.lint_file(path_obj)
108
+ if path_obj.is_dir():
109
+ return self.orchestrator.lint_directory(path_obj, recursive=True)
110
+ return []
111
+
112
+ def _filter_violations(
113
+ self, violations: list[Violation], rules: list[str] | None
114
+ ) -> list[Violation]:
115
+ """Filter violations by rule names."""
116
+ if rules:
117
+ return [v for v in violations if v.rule_id in rules]
118
+ return violations