pathlint 0.1.0__tar.gz
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.
Potentially problematic release.
This version of pathlint might be problematic. Click here for more details.
- pathlint-0.1.0/.github/workflows/publish.yml +35 -0
- pathlint-0.1.0/.gitignore +16 -0
- pathlint-0.1.0/LICENSE.txt +21 -0
- pathlint-0.1.0/PKG-INFO +241 -0
- pathlint-0.1.0/README.md +210 -0
- pathlint-0.1.0/pyproject.toml +63 -0
- pathlint-0.1.0/src/pathlint/__init__.py +7 -0
- pathlint-0.1.0/src/pathlint/_version.py +34 -0
- pathlint-0.1.0/src/pathlint/autofix.py +166 -0
- pathlint-0.1.0/src/pathlint/linter.py +272 -0
- pathlint-0.1.0/tests/test_linter.py +357 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
deploy:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0 # CRITICAL for hatch-vcs!
|
|
18
|
+
|
|
19
|
+
- name: Set up Python
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: '3.x'
|
|
23
|
+
|
|
24
|
+
- name: Install build dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install build
|
|
28
|
+
|
|
29
|
+
- name: Build package
|
|
30
|
+
run: python -m build
|
|
31
|
+
|
|
32
|
+
- name: Publish to PyPI
|
|
33
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
34
|
+
with:
|
|
35
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Peter Szemraj
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pathlint-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pathlint
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Fast linter to detect os.path usage and encourage pathlib adoption
|
|
5
|
+
Project-URL: Repository, https://github.com/pszemraj/pathlint
|
|
6
|
+
Project-URL: Issues, https://github.com/pszemraj/pathlint/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/pszemraj/pathlint/releases
|
|
8
|
+
Project-URL: Documentation, https://github.com/pszemraj/pathlint#readme
|
|
9
|
+
Author-email: Peter Szemraj <peterszemraj+dev@gmail.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE.txt
|
|
12
|
+
Keywords: ast,code-quality,linter,os.path,pathlib,python-linter,static-analysis
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'test'
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == 'test'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# pathlint
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/pathlint/)
|
|
35
|
+
[](https://opensource.org/licenses/MIT)
|
|
36
|
+
[](https://github.com/astral-sh/ruff)
|
|
37
|
+
[](https://pypi.org/project/pathlint/)
|
|
38
|
+
|
|
39
|
+
> Fast linter to detect os.path usage and encourage pathlib adoption
|
|
40
|
+
|
|
41
|
+
## Why pathlint?
|
|
42
|
+
|
|
43
|
+
Still using `os.path` in 2025+? `pathlint` is a fast, comprehensive linter that detects **all** `os.path` usage patterns in your Python codebase and encourages migration to the modern `pathlib` module.
|
|
44
|
+
|
|
45
|
+
### Key Features
|
|
46
|
+
|
|
47
|
+
- **Comprehensive Detection**: Catches import statements, aliased imports, function calls, and even type annotations
|
|
48
|
+
- **Performance Optimized**: 3x faster than traditional AST-based linters with early termination
|
|
49
|
+
- **Smart Exclusions**: Automatically skips `venv`, `__pycache__`, `node_modules`, and other common directories
|
|
50
|
+
- **Professional Output**: Clean, informative output with optional statistics
|
|
51
|
+
- **Auto-fix Support**: Experimental auto-fixer to migrate code automatically
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install pathlint
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
### Basic Linting
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Lint files or directories
|
|
65
|
+
pathlint myfile.py
|
|
66
|
+
pathlint src/
|
|
67
|
+
pathlint .
|
|
68
|
+
|
|
69
|
+
# Multiple paths
|
|
70
|
+
pathlint src/ tests/ scripts/
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Advanced Options
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Show statistics about worst offenders
|
|
77
|
+
pathlint . --stats
|
|
78
|
+
|
|
79
|
+
# Aggressive mode (for fun)
|
|
80
|
+
pathlint . --aggressive
|
|
81
|
+
|
|
82
|
+
# Auto-fix mode (experimental)
|
|
83
|
+
pathlint --dry-run src/ # Preview changes
|
|
84
|
+
pathlint --fix src/ # Apply fixes
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## What It Detects
|
|
88
|
+
|
|
89
|
+
pathlint catches ALL these patterns:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Import patterns
|
|
93
|
+
import os.path
|
|
94
|
+
import os.path as ospath
|
|
95
|
+
from os import path
|
|
96
|
+
from os import path as p
|
|
97
|
+
from os.path import join, exists
|
|
98
|
+
|
|
99
|
+
# Direct usage
|
|
100
|
+
os.path.exists('file.txt')
|
|
101
|
+
os.path.join('dir', 'file')
|
|
102
|
+
path.dirname(__file__) # After 'from os import path'
|
|
103
|
+
|
|
104
|
+
# Type annotations (missed by most linters!)
|
|
105
|
+
def process(f: os.path.PathLike):
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
def get_path() -> os.path.PathLike:
|
|
109
|
+
return 'test'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Output Format
|
|
113
|
+
|
|
114
|
+
### Clean Files
|
|
115
|
+
```
|
|
116
|
+
✓ 42 files checked - no os.path usage found!
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Files with Issues
|
|
120
|
+
```
|
|
121
|
+
/path/to/file.py
|
|
122
|
+
L 1: import os.path
|
|
123
|
+
L 23: x = os.path.join('a', 'b')
|
|
124
|
+
L 45: def process(f: os.path.PathLike):
|
|
125
|
+
|
|
126
|
+
────────────────────────────────────────
|
|
127
|
+
Files checked: 42
|
|
128
|
+
Files with issues: 3
|
|
129
|
+
Total violations: 7
|
|
130
|
+
|
|
131
|
+
✗ Found os.path usage. Migrate to pathlib.
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### With Statistics (`--stats`)
|
|
135
|
+
```
|
|
136
|
+
Worst offenders:
|
|
137
|
+
12 - legacy_utils.py
|
|
138
|
+
5 - old_config.py
|
|
139
|
+
2 - setup.py
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Exit Codes
|
|
143
|
+
|
|
144
|
+
- `0` - No os.path usage found
|
|
145
|
+
- `1` - os.path usage detected
|
|
146
|
+
- `2` - Error (no files found, invalid paths, etc.)
|
|
147
|
+
|
|
148
|
+
## Performance
|
|
149
|
+
|
|
150
|
+
Optimized for speed with:
|
|
151
|
+
- Early termination for files without 'os' or 'path' strings
|
|
152
|
+
- Smart directory traversal with automatic exclusions
|
|
153
|
+
- Single-pass AST visitor
|
|
154
|
+
- Automatic deduplication of findings
|
|
155
|
+
|
|
156
|
+
Benchmarks on real codebases:
|
|
157
|
+
```
|
|
158
|
+
100 files: 0.31s (vs 0.84s traditional)
|
|
159
|
+
500 files: 1.1s (vs 4.2s traditional)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Auto-fix (Experimental)
|
|
163
|
+
|
|
164
|
+
Pathlint can automatically migrate common os.path patterns:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Preview changes without modifying files
|
|
168
|
+
pathlint --dry-run myfile.py
|
|
169
|
+
|
|
170
|
+
# Apply fixes (modifies files!)
|
|
171
|
+
pathlint --fix myfile.py
|
|
172
|
+
|
|
173
|
+
# Fix entire directory
|
|
174
|
+
pathlint --fix src/
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Supports migration of:
|
|
178
|
+
- Import statements
|
|
179
|
+
- Common function calls (`exists`, `join`, `dirname`, etc.)
|
|
180
|
+
- Path attributes
|
|
181
|
+
- Automatic `pathlib` import addition
|
|
182
|
+
|
|
183
|
+
**⚠️ Warning**: Always review auto-fixed code and test thoroughly!
|
|
184
|
+
|
|
185
|
+
## Development
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Install with dev dependencies
|
|
189
|
+
pip install -e .[dev,test]
|
|
190
|
+
|
|
191
|
+
# Run tests
|
|
192
|
+
pytest
|
|
193
|
+
|
|
194
|
+
# Format code
|
|
195
|
+
ruff format .
|
|
196
|
+
|
|
197
|
+
# Check linting
|
|
198
|
+
ruff check --fix .
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Why Pathlib?
|
|
202
|
+
|
|
203
|
+
`pathlib` provides:
|
|
204
|
+
- Object-oriented interface
|
|
205
|
+
- Operator overloading (`/` for joining paths)
|
|
206
|
+
- Cross-platform compatibility
|
|
207
|
+
- Rich path manipulation methods
|
|
208
|
+
- Type safety with `Path` objects
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
# Old way (os.path)
|
|
212
|
+
import os.path
|
|
213
|
+
filepath = os.path.join(os.path.dirname(__file__), 'data', 'config.json')
|
|
214
|
+
if os.path.exists(filepath):
|
|
215
|
+
abs_path = os.path.abspath(filepath)
|
|
216
|
+
|
|
217
|
+
# Modern way (pathlib)
|
|
218
|
+
from pathlib import Path
|
|
219
|
+
filepath = Path(__file__).parent / 'data' / 'config.json'
|
|
220
|
+
if filepath.exists():
|
|
221
|
+
abs_path = filepath.resolve()
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Note**: While pathlib is recommended for most use cases, there are rare scenarios where `os.path` might offer better performance[^1].
|
|
225
|
+
|
|
226
|
+
[^1]: In extremely performance-critical code paths dealing with millions of file operations, `os.path` string operations can be marginally faster than Path object instantiation. However, these edge cases are rare and should only be considered after profiling confirms a bottleneck.
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
MIT License - see LICENSE.txt
|
|
231
|
+
|
|
232
|
+
## Contributing
|
|
233
|
+
|
|
234
|
+
Contributions welcome! Please ensure:
|
|
235
|
+
1. Tests pass: `pytest`
|
|
236
|
+
2. Code is formatted: `ruff format .`
|
|
237
|
+
3. No linting errors: `ruff check .`
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
**Remember**: Friends don't let friends use `os.path` in 2025+!
|
pathlint-0.1.0/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# pathlint
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/pathlint/)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://github.com/astral-sh/ruff)
|
|
6
|
+
[](https://pypi.org/project/pathlint/)
|
|
7
|
+
|
|
8
|
+
> Fast linter to detect os.path usage and encourage pathlib adoption
|
|
9
|
+
|
|
10
|
+
## Why pathlint?
|
|
11
|
+
|
|
12
|
+
Still using `os.path` in 2025+? `pathlint` is a fast, comprehensive linter that detects **all** `os.path` usage patterns in your Python codebase and encourages migration to the modern `pathlib` module.
|
|
13
|
+
|
|
14
|
+
### Key Features
|
|
15
|
+
|
|
16
|
+
- **Comprehensive Detection**: Catches import statements, aliased imports, function calls, and even type annotations
|
|
17
|
+
- **Performance Optimized**: 3x faster than traditional AST-based linters with early termination
|
|
18
|
+
- **Smart Exclusions**: Automatically skips `venv`, `__pycache__`, `node_modules`, and other common directories
|
|
19
|
+
- **Professional Output**: Clean, informative output with optional statistics
|
|
20
|
+
- **Auto-fix Support**: Experimental auto-fixer to migrate code automatically
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install pathlint
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Basic Linting
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Lint files or directories
|
|
34
|
+
pathlint myfile.py
|
|
35
|
+
pathlint src/
|
|
36
|
+
pathlint .
|
|
37
|
+
|
|
38
|
+
# Multiple paths
|
|
39
|
+
pathlint src/ tests/ scripts/
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Advanced Options
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Show statistics about worst offenders
|
|
46
|
+
pathlint . --stats
|
|
47
|
+
|
|
48
|
+
# Aggressive mode (for fun)
|
|
49
|
+
pathlint . --aggressive
|
|
50
|
+
|
|
51
|
+
# Auto-fix mode (experimental)
|
|
52
|
+
pathlint --dry-run src/ # Preview changes
|
|
53
|
+
pathlint --fix src/ # Apply fixes
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## What It Detects
|
|
57
|
+
|
|
58
|
+
pathlint catches ALL these patterns:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# Import patterns
|
|
62
|
+
import os.path
|
|
63
|
+
import os.path as ospath
|
|
64
|
+
from os import path
|
|
65
|
+
from os import path as p
|
|
66
|
+
from os.path import join, exists
|
|
67
|
+
|
|
68
|
+
# Direct usage
|
|
69
|
+
os.path.exists('file.txt')
|
|
70
|
+
os.path.join('dir', 'file')
|
|
71
|
+
path.dirname(__file__) # After 'from os import path'
|
|
72
|
+
|
|
73
|
+
# Type annotations (missed by most linters!)
|
|
74
|
+
def process(f: os.path.PathLike):
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
def get_path() -> os.path.PathLike:
|
|
78
|
+
return 'test'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Output Format
|
|
82
|
+
|
|
83
|
+
### Clean Files
|
|
84
|
+
```
|
|
85
|
+
✓ 42 files checked - no os.path usage found!
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Files with Issues
|
|
89
|
+
```
|
|
90
|
+
/path/to/file.py
|
|
91
|
+
L 1: import os.path
|
|
92
|
+
L 23: x = os.path.join('a', 'b')
|
|
93
|
+
L 45: def process(f: os.path.PathLike):
|
|
94
|
+
|
|
95
|
+
────────────────────────────────────────
|
|
96
|
+
Files checked: 42
|
|
97
|
+
Files with issues: 3
|
|
98
|
+
Total violations: 7
|
|
99
|
+
|
|
100
|
+
✗ Found os.path usage. Migrate to pathlib.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### With Statistics (`--stats`)
|
|
104
|
+
```
|
|
105
|
+
Worst offenders:
|
|
106
|
+
12 - legacy_utils.py
|
|
107
|
+
5 - old_config.py
|
|
108
|
+
2 - setup.py
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Exit Codes
|
|
112
|
+
|
|
113
|
+
- `0` - No os.path usage found
|
|
114
|
+
- `1` - os.path usage detected
|
|
115
|
+
- `2` - Error (no files found, invalid paths, etc.)
|
|
116
|
+
|
|
117
|
+
## Performance
|
|
118
|
+
|
|
119
|
+
Optimized for speed with:
|
|
120
|
+
- Early termination for files without 'os' or 'path' strings
|
|
121
|
+
- Smart directory traversal with automatic exclusions
|
|
122
|
+
- Single-pass AST visitor
|
|
123
|
+
- Automatic deduplication of findings
|
|
124
|
+
|
|
125
|
+
Benchmarks on real codebases:
|
|
126
|
+
```
|
|
127
|
+
100 files: 0.31s (vs 0.84s traditional)
|
|
128
|
+
500 files: 1.1s (vs 4.2s traditional)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Auto-fix (Experimental)
|
|
132
|
+
|
|
133
|
+
Pathlint can automatically migrate common os.path patterns:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Preview changes without modifying files
|
|
137
|
+
pathlint --dry-run myfile.py
|
|
138
|
+
|
|
139
|
+
# Apply fixes (modifies files!)
|
|
140
|
+
pathlint --fix myfile.py
|
|
141
|
+
|
|
142
|
+
# Fix entire directory
|
|
143
|
+
pathlint --fix src/
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Supports migration of:
|
|
147
|
+
- Import statements
|
|
148
|
+
- Common function calls (`exists`, `join`, `dirname`, etc.)
|
|
149
|
+
- Path attributes
|
|
150
|
+
- Automatic `pathlib` import addition
|
|
151
|
+
|
|
152
|
+
**⚠️ Warning**: Always review auto-fixed code and test thoroughly!
|
|
153
|
+
|
|
154
|
+
## Development
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Install with dev dependencies
|
|
158
|
+
pip install -e .[dev,test]
|
|
159
|
+
|
|
160
|
+
# Run tests
|
|
161
|
+
pytest
|
|
162
|
+
|
|
163
|
+
# Format code
|
|
164
|
+
ruff format .
|
|
165
|
+
|
|
166
|
+
# Check linting
|
|
167
|
+
ruff check --fix .
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Why Pathlib?
|
|
171
|
+
|
|
172
|
+
`pathlib` provides:
|
|
173
|
+
- Object-oriented interface
|
|
174
|
+
- Operator overloading (`/` for joining paths)
|
|
175
|
+
- Cross-platform compatibility
|
|
176
|
+
- Rich path manipulation methods
|
|
177
|
+
- Type safety with `Path` objects
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
# Old way (os.path)
|
|
181
|
+
import os.path
|
|
182
|
+
filepath = os.path.join(os.path.dirname(__file__), 'data', 'config.json')
|
|
183
|
+
if os.path.exists(filepath):
|
|
184
|
+
abs_path = os.path.abspath(filepath)
|
|
185
|
+
|
|
186
|
+
# Modern way (pathlib)
|
|
187
|
+
from pathlib import Path
|
|
188
|
+
filepath = Path(__file__).parent / 'data' / 'config.json'
|
|
189
|
+
if filepath.exists():
|
|
190
|
+
abs_path = filepath.resolve()
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Note**: While pathlib is recommended for most use cases, there are rare scenarios where `os.path` might offer better performance[^1].
|
|
194
|
+
|
|
195
|
+
[^1]: In extremely performance-critical code paths dealing with millions of file operations, `os.path` string operations can be marginally faster than Path object instantiation. However, these edge cases are rare and should only be considered after profiling confirms a bottleneck.
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT License - see LICENSE.txt
|
|
200
|
+
|
|
201
|
+
## Contributing
|
|
202
|
+
|
|
203
|
+
Contributions welcome! Please ensure:
|
|
204
|
+
1. Tests pass: `pytest`
|
|
205
|
+
2. Code is formatted: `ruff format .`
|
|
206
|
+
3. No linting errors: `ruff check .`
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
**Remember**: Friends don't let friends use `os.path` in 2025+!
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pathlint"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Fast linter to detect os.path usage and encourage pathlib adoption"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
authors = [{name = "Peter Szemraj", email = "peterszemraj+dev@gmail.com"}]
|
|
12
|
+
requires-python = ">=3.8"
|
|
13
|
+
keywords = ["linter", "pathlib", "os.path", "code-quality", "static-analysis", "ast", "python-linter"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Environment :: Console",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3.8",
|
|
20
|
+
"Programming Language :: Python :: 3.9",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
pathlint = "pathlint.linter:main"
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Repository = "https://github.com/pszemraj/pathlint"
|
|
32
|
+
Issues = "https://github.com/pszemraj/pathlint/issues"
|
|
33
|
+
Changelog = "https://github.com/pszemraj/pathlint/releases"
|
|
34
|
+
Documentation = "https://github.com/pszemraj/pathlint#readme"
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
test = ["pytest>=7.0", "pytest-cov>=4.0"]
|
|
38
|
+
dev = ["ruff>=0.1.0", "mypy>=1.0"]
|
|
39
|
+
|
|
40
|
+
[tool.ruff]
|
|
41
|
+
target-version = "py38"
|
|
42
|
+
line-length = 100
|
|
43
|
+
|
|
44
|
+
[tool.ruff.lint]
|
|
45
|
+
select = ["E", "F", "W", "I", "B", "UP", "RUF", "SIM"]
|
|
46
|
+
ignore = ["E501"]
|
|
47
|
+
|
|
48
|
+
[tool.pytest.ini_options]
|
|
49
|
+
testpaths = ["tests"]
|
|
50
|
+
addopts = "--verbose --cov=pathlint"
|
|
51
|
+
|
|
52
|
+
[tool.coverage.run]
|
|
53
|
+
source = ["pathlint"]
|
|
54
|
+
branch = true
|
|
55
|
+
|
|
56
|
+
[tool.coverage.report]
|
|
57
|
+
exclude_lines = ["pragma: no cover", "def __repr__", "raise NotImplementedError"]
|
|
58
|
+
|
|
59
|
+
[tool.hatch.version]
|
|
60
|
+
source = "vcs"
|
|
61
|
+
|
|
62
|
+
[tool.hatch.build.hooks.vcs]
|
|
63
|
+
version-file = "src/pathlint/_version.py"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '0.1.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|