ruff-legibility 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.
- ruff_legibility-0.1.0/.gitignore +20 -0
- ruff_legibility-0.1.0/LICENSE +21 -0
- ruff_legibility-0.1.0/PKG-INFO +151 -0
- ruff_legibility-0.1.0/README.md +127 -0
- ruff_legibility-0.1.0/pyproject.toml +58 -0
- ruff_legibility-0.1.0/ruff-legibility.toml +3 -0
- ruff_legibility-0.1.0/src/ruff_legibility/__init__.py +13 -0
- ruff_legibility-0.1.0/src/ruff_legibility/__main__.py +3 -0
- ruff_legibility-0.1.0/src/ruff_legibility/cli.py +116 -0
- ruff_legibility-0.1.0/src/ruff_legibility/config.py +222 -0
- ruff_legibility-0.1.0/src/ruff_legibility/core.py +89 -0
- ruff_legibility-0.1.0/src/ruff_legibility/noqa.py +22 -0
- ruff_legibility-0.1.0/src/ruff_legibility/py.typed +1 -0
- ruff_legibility-0.1.0/src/ruff_legibility/rules.py +354 -0
- ruff_legibility-0.1.0/tests/test_cli.py +91 -0
- ruff_legibility-0.1.0/tests/test_config.py +66 -0
- ruff_legibility-0.1.0/tests/test_rules.py +75 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.pytest_cache/
|
|
4
|
+
.ruff_cache/
|
|
5
|
+
.venv/
|
|
6
|
+
.coverage*
|
|
7
|
+
htmlcov/
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
|
|
12
|
+
# Beads / Dolt files (added by bd init)
|
|
13
|
+
.dolt/
|
|
14
|
+
*.db
|
|
15
|
+
.beads-credential-key
|
|
16
|
+
.claude/
|
|
17
|
+
CLAUDE.md
|
|
18
|
+
.beads/
|
|
19
|
+
venv/
|
|
20
|
+
*.pyc
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jeffry Wainwright
|
|
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.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ruff-legibility
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Ruff-adjacent Python legibility rules for readable, reviewable code.
|
|
5
|
+
Project-URL: Homepage, https://github.com/yowainwright/ruff-legibility
|
|
6
|
+
Project-URL: Issues, https://github.com/yowainwright/ruff-legibility/issues
|
|
7
|
+
Project-URL: Repository, https://github.com/yowainwright/ruff-legibility
|
|
8
|
+
Author: Jeffry Wainwright
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: legibility,lint,python,readability,ruff
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# ruff-legibility
|
|
26
|
+
|
|
27
|
+
[](https://pypi.org/project/ruff-legibility/)
|
|
28
|
+
[](https://github.com/yowainwright/ruff-legibility/actions/workflows/ci.yml)
|
|
29
|
+
[](https://scorecard.dev/viewer/?uri=github.com/yowainwright/ruff-legibility)
|
|
30
|
+
|
|
31
|
+
`ruff-legibility` is a Ruff-adjacent Python linter for readability and reviewability rules inspired by `eslint-plugin-legibility`.
|
|
32
|
+
|
|
33
|
+
Ruff does not currently load third-party rule implementations from Python packages. This package therefore runs beside Ruff and emits Ruff-style diagnostics with `LEG###` codes.
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
ruff check .
|
|
37
|
+
ruff-legibility check .
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
To keep `# noqa: LEG001` comments valid when Ruff checks unused or unknown `noqa` codes, add `LEG` as an external prefix in Ruff:
|
|
41
|
+
|
|
42
|
+
```toml
|
|
43
|
+
[tool.ruff.lint]
|
|
44
|
+
external = ["LEG"]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
pip install ruff-legibility
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For local development:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
uv sync --all-groups
|
|
57
|
+
make check
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
ruff-legibility check .
|
|
64
|
+
ruff-legibility check src tests --output-format json
|
|
65
|
+
ruff-legibility check . --select LEG001,LEG002 --ignore LEG007
|
|
66
|
+
ruff-legibility check . --exit-zero
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Default text output is intentionally close to Ruff:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
example.py:4:8: LEG002 If condition has 2 boolean operators (max 0). Hoist it into a named boolean.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
Configuration can live in `pyproject.toml` under `[tool.ruff-legibility]`, or in `ruff-legibility.toml` / `.ruff-legibility.toml`.
|
|
78
|
+
|
|
79
|
+
```toml
|
|
80
|
+
[tool.ruff-legibility]
|
|
81
|
+
select = ["LEG"]
|
|
82
|
+
extend-select = []
|
|
83
|
+
ignore = ["LEG007"]
|
|
84
|
+
extend-ignore = []
|
|
85
|
+
exclude = [".venv", "build", "dist"]
|
|
86
|
+
max-expression-operators = 4
|
|
87
|
+
max-if-operators = 0
|
|
88
|
+
max-ternary-operators = 2
|
|
89
|
+
max-control-flow-depth = 3
|
|
90
|
+
|
|
91
|
+
[tool.ruff-legibility.per-file-ignores]
|
|
92
|
+
"tests/*" = ["LEG003"]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Standalone config files omit the `tool.ruff-legibility` wrapper:
|
|
96
|
+
|
|
97
|
+
```toml
|
|
98
|
+
select = ["LEG"]
|
|
99
|
+
ignore = ["LEG007"]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
This repository includes a `ruff-legibility.toml` for its own source. The default package thresholds stay stricter than the project-local development config.
|
|
103
|
+
|
|
104
|
+
## Rules
|
|
105
|
+
|
|
106
|
+
| Code | Rule | Default |
|
|
107
|
+
| --- | --- | --- |
|
|
108
|
+
| `LEG001` | Limit readability operators inside a single expression. | on |
|
|
109
|
+
| `LEG002` | Prefer a named boolean before operator-heavy `if` / `while` conditions. | on |
|
|
110
|
+
| `LEG003` | Limit nested control-flow depth. | on |
|
|
111
|
+
| `LEG004` | Avoid complex ternary expressions. | on |
|
|
112
|
+
| `LEG005` | Flag likely quadratic patterns such as nested loops and repeated membership checks in loops. | on |
|
|
113
|
+
| `LEG006` | Avoid redundant boolean comparisons like `flag == True`. | on |
|
|
114
|
+
| `LEG007` | Prefer positive condition names over names like `is_not_ready`. | on |
|
|
115
|
+
|
|
116
|
+
## Pre-commit
|
|
117
|
+
|
|
118
|
+
```yaml
|
|
119
|
+
repos:
|
|
120
|
+
- repo: local
|
|
121
|
+
hooks:
|
|
122
|
+
- id: ruff-legibility
|
|
123
|
+
name: ruff-legibility
|
|
124
|
+
entry: ruff-legibility check
|
|
125
|
+
language: system
|
|
126
|
+
types: [python]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
Common commands:
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
uv sync --all-groups
|
|
135
|
+
uv run ruff check .
|
|
136
|
+
uv run ruff-legibility check src tests
|
|
137
|
+
uv run pytest
|
|
138
|
+
uv build
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Release builds should use:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
uv build --no-sources
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Publishing is configured for PyPI Trusted Publishing:
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
uv publish
|
|
151
|
+
```
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# ruff-legibility
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/ruff-legibility/)
|
|
4
|
+
[](https://github.com/yowainwright/ruff-legibility/actions/workflows/ci.yml)
|
|
5
|
+
[](https://scorecard.dev/viewer/?uri=github.com/yowainwright/ruff-legibility)
|
|
6
|
+
|
|
7
|
+
`ruff-legibility` is a Ruff-adjacent Python linter for readability and reviewability rules inspired by `eslint-plugin-legibility`.
|
|
8
|
+
|
|
9
|
+
Ruff does not currently load third-party rule implementations from Python packages. This package therefore runs beside Ruff and emits Ruff-style diagnostics with `LEG###` codes.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
ruff check .
|
|
13
|
+
ruff-legibility check .
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
To keep `# noqa: LEG001` comments valid when Ruff checks unused or unknown `noqa` codes, add `LEG` as an external prefix in Ruff:
|
|
17
|
+
|
|
18
|
+
```toml
|
|
19
|
+
[tool.ruff.lint]
|
|
20
|
+
external = ["LEG"]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
pip install ruff-legibility
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For local development:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
uv sync --all-groups
|
|
33
|
+
make check
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
ruff-legibility check .
|
|
40
|
+
ruff-legibility check src tests --output-format json
|
|
41
|
+
ruff-legibility check . --select LEG001,LEG002 --ignore LEG007
|
|
42
|
+
ruff-legibility check . --exit-zero
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Default text output is intentionally close to Ruff:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
example.py:4:8: LEG002 If condition has 2 boolean operators (max 0). Hoist it into a named boolean.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
Configuration can live in `pyproject.toml` under `[tool.ruff-legibility]`, or in `ruff-legibility.toml` / `.ruff-legibility.toml`.
|
|
54
|
+
|
|
55
|
+
```toml
|
|
56
|
+
[tool.ruff-legibility]
|
|
57
|
+
select = ["LEG"]
|
|
58
|
+
extend-select = []
|
|
59
|
+
ignore = ["LEG007"]
|
|
60
|
+
extend-ignore = []
|
|
61
|
+
exclude = [".venv", "build", "dist"]
|
|
62
|
+
max-expression-operators = 4
|
|
63
|
+
max-if-operators = 0
|
|
64
|
+
max-ternary-operators = 2
|
|
65
|
+
max-control-flow-depth = 3
|
|
66
|
+
|
|
67
|
+
[tool.ruff-legibility.per-file-ignores]
|
|
68
|
+
"tests/*" = ["LEG003"]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Standalone config files omit the `tool.ruff-legibility` wrapper:
|
|
72
|
+
|
|
73
|
+
```toml
|
|
74
|
+
select = ["LEG"]
|
|
75
|
+
ignore = ["LEG007"]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This repository includes a `ruff-legibility.toml` for its own source. The default package thresholds stay stricter than the project-local development config.
|
|
79
|
+
|
|
80
|
+
## Rules
|
|
81
|
+
|
|
82
|
+
| Code | Rule | Default |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| `LEG001` | Limit readability operators inside a single expression. | on |
|
|
85
|
+
| `LEG002` | Prefer a named boolean before operator-heavy `if` / `while` conditions. | on |
|
|
86
|
+
| `LEG003` | Limit nested control-flow depth. | on |
|
|
87
|
+
| `LEG004` | Avoid complex ternary expressions. | on |
|
|
88
|
+
| `LEG005` | Flag likely quadratic patterns such as nested loops and repeated membership checks in loops. | on |
|
|
89
|
+
| `LEG006` | Avoid redundant boolean comparisons like `flag == True`. | on |
|
|
90
|
+
| `LEG007` | Prefer positive condition names over names like `is_not_ready`. | on |
|
|
91
|
+
|
|
92
|
+
## Pre-commit
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
repos:
|
|
96
|
+
- repo: local
|
|
97
|
+
hooks:
|
|
98
|
+
- id: ruff-legibility
|
|
99
|
+
name: ruff-legibility
|
|
100
|
+
entry: ruff-legibility check
|
|
101
|
+
language: system
|
|
102
|
+
types: [python]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Development
|
|
106
|
+
|
|
107
|
+
Common commands:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
uv sync --all-groups
|
|
111
|
+
uv run ruff check .
|
|
112
|
+
uv run ruff-legibility check src tests
|
|
113
|
+
uv run pytest
|
|
114
|
+
uv build
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Release builds should use:
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
uv build --no-sources
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Publishing is configured for PyPI Trusted Publishing:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
uv publish
|
|
127
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ruff-legibility"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Ruff-adjacent Python legibility rules for readable, reviewable code."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Jeffry Wainwright" }]
|
|
14
|
+
keywords = ["ruff", "lint", "legibility", "readability", "python"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
26
|
+
]
|
|
27
|
+
dependencies = []
|
|
28
|
+
|
|
29
|
+
[dependency-groups]
|
|
30
|
+
dev = [
|
|
31
|
+
"pytest>=8.0",
|
|
32
|
+
"ruff>=0.15",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/yowainwright/ruff-legibility"
|
|
37
|
+
Issues = "https://github.com/yowainwright/ruff-legibility/issues"
|
|
38
|
+
Repository = "https://github.com/yowainwright/ruff-legibility"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
ruff-legibility = "ruff_legibility.cli:main"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.wheel]
|
|
44
|
+
packages = ["src/ruff_legibility"]
|
|
45
|
+
|
|
46
|
+
[tool.hatch.build.targets.sdist]
|
|
47
|
+
include = ["src", "tests", "README.md", "LICENSE", "pyproject.toml", "ruff-legibility.toml"]
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
line-length = 120
|
|
51
|
+
target-version = "py311"
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
55
|
+
|
|
56
|
+
[tool.pytest.ini_options]
|
|
57
|
+
testpaths = ["tests"]
|
|
58
|
+
pythonpath = ["src"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Ruff-adjacent legibility checks for Python."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
from .core import Diagnostic, check_path, check_source
|
|
6
|
+
from .rules import RULES
|
|
7
|
+
|
|
8
|
+
__all__ = ["Diagnostic", "RULES", "check_path", "check_source"]
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
__version__ = version("ruff-legibility")
|
|
12
|
+
except PackageNotFoundError:
|
|
13
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from collections.abc import Sequence
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from . import __version__
|
|
10
|
+
from .config import apply_overrides, load_settings, parse_selectors
|
|
11
|
+
from .core import Diagnostic, check_path, discover_python_files
|
|
12
|
+
from .rules import RULES
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
16
|
+
args = _parse_args(list(argv) if argv is not None else sys.argv[1:])
|
|
17
|
+
|
|
18
|
+
if args.command == "rules":
|
|
19
|
+
_print_rules()
|
|
20
|
+
return 0
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
settings = load_settings(Path(args.config) if args.config else None)
|
|
24
|
+
settings = apply_overrides(
|
|
25
|
+
settings,
|
|
26
|
+
select=parse_selectors(args.select),
|
|
27
|
+
ignore=parse_selectors(args.ignore),
|
|
28
|
+
max_expression_operators=args.max_expression_operators,
|
|
29
|
+
max_if_operators=args.max_if_operators,
|
|
30
|
+
max_ternary_operators=args.max_ternary_operators,
|
|
31
|
+
max_control_flow_depth=args.max_control_flow_depth,
|
|
32
|
+
)
|
|
33
|
+
except ValueError as error:
|
|
34
|
+
print(f"ruff-legibility: {error}", file=sys.stderr)
|
|
35
|
+
return 2
|
|
36
|
+
|
|
37
|
+
paths = [Path(path) for path in args.paths]
|
|
38
|
+
files = discover_python_files(paths, settings)
|
|
39
|
+
diagnostics = _check_files(files, settings)
|
|
40
|
+
_print_diagnostics(diagnostics, output_format=args.output_format)
|
|
41
|
+
|
|
42
|
+
if args.exit_zero:
|
|
43
|
+
return 0
|
|
44
|
+
return 1 if diagnostics else 0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _parse_args(argv: list[str]) -> argparse.Namespace:
|
|
48
|
+
top_level_flags = {"-h", "--help", "--version"}
|
|
49
|
+
if not argv or (argv[0] not in {"check", "rules"} and argv[0] not in top_level_flags):
|
|
50
|
+
argv = ["check", *argv]
|
|
51
|
+
|
|
52
|
+
parser = argparse.ArgumentParser(prog="ruff-legibility")
|
|
53
|
+
parser.add_argument("--version", action="version", version=f"ruff-legibility {__version__}")
|
|
54
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
55
|
+
|
|
56
|
+
check = subparsers.add_parser("check", help="check Python files")
|
|
57
|
+
check.add_argument("paths", nargs="*", default=["."], help="files or directories to check")
|
|
58
|
+
check.add_argument("--config", help="path to ruff-legibility.toml or pyproject.toml")
|
|
59
|
+
check.add_argument("--select", help="comma-separated rule selectors to enable")
|
|
60
|
+
check.add_argument("--ignore", help="comma-separated rule selectors to ignore")
|
|
61
|
+
check.add_argument(
|
|
62
|
+
"--output-format",
|
|
63
|
+
"--format",
|
|
64
|
+
choices=("text", "json", "github"),
|
|
65
|
+
default="text",
|
|
66
|
+
help="diagnostic output format",
|
|
67
|
+
)
|
|
68
|
+
check.add_argument("--exit-zero", action="store_true", help="always exit successfully")
|
|
69
|
+
check.add_argument("--max-expression-operators", type=int)
|
|
70
|
+
check.add_argument("--max-if-operators", type=int)
|
|
71
|
+
check.add_argument("--max-ternary-operators", type=int)
|
|
72
|
+
check.add_argument("--max-control-flow-depth", type=int)
|
|
73
|
+
|
|
74
|
+
subparsers.add_parser("rules", help="list available rules")
|
|
75
|
+
return parser.parse_args(argv)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _check_files(files: list[Path], settings) -> list[Diagnostic]:
|
|
79
|
+
diagnostics: list[Diagnostic] = []
|
|
80
|
+
for file in files:
|
|
81
|
+
diagnostics.extend(check_path(file, settings))
|
|
82
|
+
return sorted(diagnostics)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _print_diagnostics(diagnostics: list[Diagnostic], *, output_format: str) -> None:
|
|
86
|
+
if output_format == "json":
|
|
87
|
+
print(json.dumps([diagnostic.to_json() for diagnostic in diagnostics], indent=2))
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
for diagnostic in diagnostics:
|
|
91
|
+
if output_format == "github":
|
|
92
|
+
file_name = _escape_github_command_property(diagnostic.path.as_posix())
|
|
93
|
+
message = _escape_github_command_data(f"{diagnostic.code} {diagnostic.message}")
|
|
94
|
+
print(
|
|
95
|
+
f"::warning file={file_name},"
|
|
96
|
+
f"line={diagnostic.line},col={diagnostic.column}::"
|
|
97
|
+
f"{message}"
|
|
98
|
+
)
|
|
99
|
+
else:
|
|
100
|
+
print(
|
|
101
|
+
f"{diagnostic.path.as_posix()}:{diagnostic.line}:{diagnostic.column}: "
|
|
102
|
+
f"{diagnostic.code} {diagnostic.message}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _escape_github_command_data(value: str) -> str:
|
|
107
|
+
return value.replace("%", "%25").replace("\r", "%0D").replace("\n", "%0A")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _escape_github_command_property(value: str) -> str:
|
|
111
|
+
return _escape_github_command_data(value).replace(":", "%3A").replace(",", "%2C")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _print_rules() -> None:
|
|
115
|
+
for code, rule in RULES.items():
|
|
116
|
+
print(f"{code} {rule.name}: {rule.summary}")
|