thailint 0.2.0__py3-none-any.whl → 0.5.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/cli.py +646 -36
- src/config.py +6 -2
- src/core/base.py +90 -5
- src/core/config_parser.py +31 -4
- src/linters/dry/block_filter.py +5 -2
- src/linters/dry/cache.py +46 -92
- src/linters/dry/config.py +17 -13
- src/linters/dry/duplicate_storage.py +17 -80
- src/linters/dry/file_analyzer.py +11 -48
- src/linters/dry/linter.py +5 -12
- src/linters/dry/python_analyzer.py +188 -37
- src/linters/dry/storage_initializer.py +9 -18
- src/linters/dry/token_hasher.py +63 -9
- src/linters/dry/typescript_analyzer.py +7 -5
- src/linters/dry/violation_filter.py +4 -1
- src/linters/file_header/__init__.py +24 -0
- src/linters/file_header/atemporal_detector.py +87 -0
- src/linters/file_header/config.py +66 -0
- src/linters/file_header/field_validator.py +69 -0
- src/linters/file_header/linter.py +313 -0
- src/linters/file_header/python_parser.py +86 -0
- src/linters/file_header/violation_builder.py +78 -0
- src/linters/file_placement/linter.py +15 -4
- src/linters/magic_numbers/__init__.py +48 -0
- src/linters/magic_numbers/config.py +82 -0
- src/linters/magic_numbers/context_analyzer.py +247 -0
- src/linters/magic_numbers/linter.py +516 -0
- src/linters/magic_numbers/python_analyzer.py +76 -0
- src/linters/magic_numbers/typescript_analyzer.py +218 -0
- src/linters/magic_numbers/violation_builder.py +98 -0
- src/linters/nesting/__init__.py +6 -2
- src/linters/nesting/config.py +6 -3
- src/linters/nesting/linter.py +8 -19
- src/linters/nesting/typescript_analyzer.py +1 -0
- src/linters/print_statements/__init__.py +53 -0
- src/linters/print_statements/config.py +83 -0
- src/linters/print_statements/linter.py +430 -0
- src/linters/print_statements/python_analyzer.py +155 -0
- src/linters/print_statements/typescript_analyzer.py +135 -0
- src/linters/print_statements/violation_builder.py +98 -0
- src/linters/srp/__init__.py +3 -3
- src/linters/srp/config.py +12 -6
- src/linters/srp/linter.py +33 -24
- src/orchestrator/core.py +12 -2
- src/templates/thailint_config_template.yaml +158 -0
- src/utils/project_root.py +135 -16
- {thailint-0.2.0.dist-info → thailint-0.5.0.dist-info}/METADATA +387 -81
- thailint-0.5.0.dist-info/RECORD +96 -0
- {thailint-0.2.0.dist-info → thailint-0.5.0.dist-info}/WHEEL +1 -1
- thailint-0.2.0.dist-info/RECORD +0 -75
- {thailint-0.2.0.dist-info → thailint-0.5.0.dist-info}/entry_points.txt +0 -0
- {thailint-0.2.0.dist-info → thailint-0.5.0.dist-info/licenses}/LICENSE +0 -0
src/utils/project_root.py
CHANGED
|
@@ -4,29 +4,52 @@ Purpose: Centralized project root detection for consistent file placement
|
|
|
4
4
|
Scope: Single source of truth for finding project root directory
|
|
5
5
|
|
|
6
6
|
Overview: Uses pyprojroot package to provide reliable project root detection across
|
|
7
|
-
different environments (development, CI/CD, user installations).
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
different environments (development, CI/CD, user installations). Falls back to
|
|
8
|
+
manual detection if pyprojroot is not available (e.g., in test environments).
|
|
9
|
+
Searches for standard project markers like .git, .thailint.yaml, and pyproject.toml.
|
|
10
10
|
|
|
11
|
-
Dependencies: pyprojroot
|
|
11
|
+
Dependencies: pyprojroot (optional, with manual fallback)
|
|
12
12
|
|
|
13
13
|
Exports: is_project_root(), get_project_root()
|
|
14
14
|
|
|
15
15
|
Interfaces: Path-based functions for checking and finding project roots
|
|
16
16
|
|
|
17
|
-
Implementation:
|
|
17
|
+
Implementation: pyprojroot delegation with manual fallback for test environments
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
from pathlib import Path
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
# Try to import pyprojroot, but don't fail if it's not available
|
|
23
|
+
try:
|
|
24
|
+
from pyprojroot import find_root
|
|
25
|
+
|
|
26
|
+
HAS_PYPROJROOT = True
|
|
27
|
+
except ImportError:
|
|
28
|
+
HAS_PYPROJROOT = False
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _has_marker(path: Path, marker_name: str, is_dir: bool = False) -> bool:
|
|
32
|
+
"""Check if a directory contains a specific marker.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
path: Directory path to check
|
|
36
|
+
marker_name: Name of marker file or directory
|
|
37
|
+
is_dir: True if marker is a directory, False if it's a file
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
True if marker exists, False otherwise
|
|
41
|
+
"""
|
|
42
|
+
marker_path = path / marker_name
|
|
43
|
+
if is_dir:
|
|
44
|
+
return marker_path.is_dir()
|
|
45
|
+
return marker_path.is_file()
|
|
23
46
|
|
|
24
47
|
|
|
25
48
|
def is_project_root(path: Path) -> bool:
|
|
26
49
|
"""Check if a directory is a project root.
|
|
27
50
|
|
|
28
|
-
Uses pyprojroot
|
|
29
|
-
|
|
51
|
+
Uses pyprojroot if available, otherwise checks for common project markers
|
|
52
|
+
like .git, .thailint.yaml, or pyproject.toml.
|
|
30
53
|
|
|
31
54
|
Args:
|
|
32
55
|
path: Directory path to check
|
|
@@ -43,6 +66,21 @@ def is_project_root(path: Path) -> bool:
|
|
|
43
66
|
if not path.exists() or not path.is_dir():
|
|
44
67
|
return False
|
|
45
68
|
|
|
69
|
+
if HAS_PYPROJROOT:
|
|
70
|
+
return _check_root_with_pyprojroot(path)
|
|
71
|
+
|
|
72
|
+
return _check_root_with_markers(path)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _check_root_with_pyprojroot(path: Path) -> bool:
|
|
76
|
+
"""Check if path is project root using pyprojroot.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
path: Directory path to check
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
True if path is a project root, False otherwise
|
|
83
|
+
"""
|
|
46
84
|
try:
|
|
47
85
|
# Find root from this path - if it equals this path, it's a root
|
|
48
86
|
found_root = find_root(path)
|
|
@@ -52,14 +90,74 @@ def is_project_root(path: Path) -> bool:
|
|
|
52
90
|
return False
|
|
53
91
|
|
|
54
92
|
|
|
93
|
+
def _check_root_with_markers(path: Path) -> bool:
|
|
94
|
+
"""Check if path contains project root markers.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
path: Directory path to check
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
True if path contains .git, .thailint.yaml, or pyproject.toml
|
|
101
|
+
"""
|
|
102
|
+
return (
|
|
103
|
+
_has_marker(path, ".git", is_dir=True)
|
|
104
|
+
or _has_marker(path, ".thailint.yaml", is_dir=False)
|
|
105
|
+
or _has_marker(path, "pyproject.toml", is_dir=False)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _try_find_with_criterion(criterion: object, start_path: Path) -> Path | None:
|
|
110
|
+
"""Try to find project root with a specific criterion.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
criterion: pyprojroot criterion function (e.g., has_dir(".git"))
|
|
114
|
+
start_path: Path to start searching from
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Found project root or None if not found
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
return find_root(criterion, start=start_path) # type: ignore[arg-type]
|
|
121
|
+
except (OSError, RuntimeError):
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _find_root_manual(start_path: Path) -> Path:
|
|
126
|
+
"""Manually find project root by walking up directory tree.
|
|
127
|
+
|
|
128
|
+
Fallback implementation when pyprojroot is not available.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
start_path: Directory to start searching from
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Path to project root, or start_path if no markers found
|
|
135
|
+
"""
|
|
136
|
+
current = start_path.resolve()
|
|
137
|
+
|
|
138
|
+
# Walk up the directory tree
|
|
139
|
+
for parent in [current] + list(current.parents):
|
|
140
|
+
# Check for project markers
|
|
141
|
+
if (
|
|
142
|
+
_has_marker(parent, ".git", is_dir=True)
|
|
143
|
+
or _has_marker(parent, ".thailint.yaml", is_dir=False)
|
|
144
|
+
or _has_marker(parent, "pyproject.toml", is_dir=False)
|
|
145
|
+
):
|
|
146
|
+
return parent
|
|
147
|
+
|
|
148
|
+
# No markers found, return start path
|
|
149
|
+
return current
|
|
150
|
+
|
|
151
|
+
|
|
55
152
|
def get_project_root(start_path: Path | None = None) -> Path:
|
|
56
153
|
"""Find project root by walking up the directory tree.
|
|
57
154
|
|
|
58
155
|
This is the single source of truth for project root detection.
|
|
59
156
|
All code that needs to find the project root should use this function.
|
|
60
157
|
|
|
61
|
-
Uses pyprojroot
|
|
62
|
-
|
|
158
|
+
Uses pyprojroot if available, otherwise uses manual detection searching for
|
|
159
|
+
standard project markers (.git directory, pyproject.toml, .thailint.yaml, etc)
|
|
160
|
+
starting from start_path and walking upward.
|
|
63
161
|
|
|
64
162
|
Args:
|
|
65
163
|
start_path: Directory to start searching from. If None, uses current working directory.
|
|
@@ -76,9 +174,30 @@ def get_project_root(start_path: Path | None = None) -> Path:
|
|
|
76
174
|
|
|
77
175
|
current = start_path.resolve()
|
|
78
176
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
177
|
+
if HAS_PYPROJROOT:
|
|
178
|
+
return _find_root_with_pyprojroot(current)
|
|
179
|
+
|
|
180
|
+
# Manual fallback for test environments
|
|
181
|
+
return _find_root_manual(current)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _find_root_with_pyprojroot(current: Path) -> Path:
|
|
185
|
+
"""Find project root using pyprojroot library.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
current: Current path to start searching from
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Path to project root, or current if no markers found
|
|
192
|
+
"""
|
|
193
|
+
from pyprojroot import has_dir, has_file
|
|
194
|
+
|
|
195
|
+
# Search for project root markers in priority order
|
|
196
|
+
# Try .git first (most reliable), then .thailint.yaml, then pyproject.toml
|
|
197
|
+
for criterion in [has_dir(".git"), has_file(".thailint.yaml"), has_file("pyproject.toml")]:
|
|
198
|
+
root = _try_find_with_criterion(criterion, current)
|
|
199
|
+
if root is not None:
|
|
200
|
+
return root
|
|
201
|
+
|
|
202
|
+
# No markers found, return start path
|
|
203
|
+
return current
|