python-linters 0.1.3__tar.gz → 0.1.5__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.
- python_linters-0.1.3/README.md → python_linters-0.1.5/PKG-INFO +39 -40
- python_linters-0.1.3/PKG-INFO → python_linters-0.1.5/README.md +19 -61
- {python_linters-0.1.3 → python_linters-0.1.5}/pyproject.toml +3 -7
- {python_linters-0.1.3 → python_linters-0.1.5}/python_linters/.flake8 +2 -23
- python_linters-0.1.5/python_linters/add_noqa.py +30 -0
- python_linters-0.1.5/python_linters/config_files.py +11 -0
- python_linters-0.1.5/python_linters/extending_ruff_toml.py +37 -0
- {python_linters-0.1.3 → python_linters-0.1.5}/python_linters/fix_code.py +7 -7
- python_linters-0.1.5/python_linters/getting_to_be_linted_folders.py +51 -0
- {python_linters-0.1.3 → python_linters-0.1.5}/python_linters/parse_rules.py +2 -4
- python_linters-0.1.5/python_linters/pyrightconfig.json +21 -0
- {python_linters-0.1.3 → python_linters-0.1.5}/python_linters/ruff.toml +18 -5
- {python_linters-0.1.3 → python_linters-0.1.5}/python_linters/ruff_rule_categories.py +7 -2
- python_linters-0.1.5/python_linters/run_linters.py +44 -0
- python_linters-0.1.3/python_linters/add_noqa.py +0 -32
- python_linters-0.1.3/python_linters/run_linters.py +0 -105
- {python_linters-0.1.3 → python_linters-0.1.5}/LICENSE +0 -0
- {python_linters-0.1.3 → python_linters-0.1.5}/python_linters/__init__.py +0 -0
- {python_linters-0.1.3 → python_linters-0.1.5}/python_linters/ruff_rules.txt +0 -0
|
@@ -1,12 +1,47 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: python-linters
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: bundling config files for linters like ruff and flake8
|
|
5
|
+
Home-page: https://github.com/dertilo/python-linters
|
|
6
|
+
License: MIT
|
|
7
|
+
Author: Tilo Himmelsbach
|
|
8
|
+
Author-email: dertilo@gmail.com
|
|
9
|
+
Requires-Python: >=3.10,<4.0
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Dist: basedpyright (>=1.12.5,<2.0.0)
|
|
16
|
+
Requires-Dist: ruff (>=0.0.291)
|
|
17
|
+
Requires-Dist: toml (>=0.10.2,<0.11.0)
|
|
18
|
+
Project-URL: Repository, https://github.com/dertilo/python-linters
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
1
21
|

|
|
2
22
|
[](https://opensource.org/licenses/MIT)
|
|
3
23
|
[](https://beartype.readthedocs.io)
|
|
4
24
|
# python-linters
|
|
5
|
-
- bundles
|
|
25
|
+
- bundles ruff and basedpyright into a single poetry-script
|
|
6
26
|
- project independent linter configuration (via `ruff.toml`,`.flake8`) -> one config to rule them all
|
|
7
27
|
### use-cases:
|
|
8
28
|
1. interactively learning python code quality standards via ruff+flake8, see [local development workflow](#2-local-development-workflow-before-pushing-to-ci-pipeline)
|
|
9
29
|
2. enforcing minimal quality-standards via a "lint-stage" in a ci-pipeline, see [setup for ci-pipeline](#3-setup-for-ci-pipeline)
|
|
30
|
+
## 0. motivation:
|
|
31
|
+
### Python is a Bicycle!
|
|
32
|
+
- initial idea of python: `Bridge the gap between the shell and C.`[see](https://www.artima.com/articles/pythons-design-goals)
|
|
33
|
+

|
|
34
|
+
### run-time "safety"
|
|
35
|
+
- type and data validation at runtime
|
|
36
|
+
- pytests run your code -> runtime
|
|
37
|
+

|
|
38
|
+
### lint-time "safety"
|
|
39
|
+
- linting and static type checking
|
|
40
|
+

|
|
41
|
+
- flake8 already fell down!
|
|
42
|
+
### more "safety" via shorter feed-back loops
|
|
43
|
+

|
|
44
|
+
|
|
10
45
|
|
|
11
46
|
## 1. install (via poetry)
|
|
12
47
|
1. in `pyproject.toml` add to dependencies
|
|
@@ -59,7 +94,7 @@ cond9 --> | complains | cond47{{"ruff"}}:::style0
|
|
|
59
94
|
cond47 --> | complains | op51[\"poetry run addnoqa"/]:::style1
|
|
60
95
|
op51 --> sub53[\"refactor your code \nOR\n keep/add noqa-comment"/]:::style1
|
|
61
96
|
sub53 --> op2
|
|
62
|
-
cond47 --> | is happy | cond58{{"
|
|
97
|
+
cond47 --> | is happy | cond58{{"pyright"}}:::style0
|
|
63
98
|
cond58 --> | complains | sub53
|
|
64
99
|
cond58 --> | is happy | sub66["git commit"]
|
|
65
100
|
sub66 --> sub80
|
|
@@ -113,19 +148,6 @@ All done! ✨ 🍰 ✨
|
|
|
113
148
|
folders_to_be_linted=['whisper_streaming', 'tests']
|
|
114
149
|
```
|
|
115
150
|
|
|
116
|
-
### pythonlinter black is not happy
|
|
117
|
-
```commandline
|
|
118
|
-
poetry run pythonlinter
|
|
119
|
-
linter-order: black->ruff->flake8
|
|
120
|
-
folders_tobelinted=['whisper_streaming', 'tests']
|
|
121
|
-
running black
|
|
122
|
-
would reformat <somehwere>/whisper-streaming/whisper_streaming/post_asr_preparations.py
|
|
123
|
-
would reformat <somehwere>/whisper-streaming/whisper_streaming/faster_whisper_inference/faster_whisper_inferencer.py
|
|
124
|
-
|
|
125
|
-
Oh no! 💥 💔 💥
|
|
126
|
-
2 files would be reformatted, 20 files would be left unchanged.
|
|
127
|
-
python_linters.run_linters.LinterException: 💩 black is not happy! 💩
|
|
128
|
-
```
|
|
129
151
|
### pythonlinter ruff is not happy
|
|
130
152
|
- complains about
|
|
131
153
|
- an unused argument
|
|
@@ -146,27 +168,6 @@ Found 4 errors.
|
|
|
146
168
|
No fixes available (2 hidden fixes can be enabled with the `--unsafe-fixes` option).
|
|
147
169
|
python_linters.run_linters.LinterException: 💩 ruff is not happy! 💩
|
|
148
170
|
```
|
|
149
|
-
### pythonlinter flake8 is not happy
|
|
150
|
-
- complains about too many methods in a class and wrong position of a function in a module
|
|
151
|
-
```commandline
|
|
152
|
-
poetry run pythonlinter
|
|
153
|
-
linter-order: black->ruff->flake8
|
|
154
|
-
folders_tobelinted=['whisper_streaming', 'tests']
|
|
155
|
-
running black
|
|
156
|
-
All done! ✨ 🍰 ✨
|
|
157
|
-
22 files would be left unchanged.
|
|
158
|
-
|
|
159
|
-
passed black linter! ✨ 🍰 ✨
|
|
160
|
-
|
|
161
|
-
running ruff
|
|
162
|
-
|
|
163
|
-
passed ruff linter! ✨ 🍰 ✨
|
|
164
|
-
|
|
165
|
-
running flake8
|
|
166
|
-
whisper_streaming/faster_whisper_inference/faster_whisper_inferencer.py:111:1: WPS214 Found too many methods: 10 > 9
|
|
167
|
-
tests/conftest.py:35:8: NEW100 newspaper style: function is_in_docker_container defined in line 16 should be moved down
|
|
168
|
-
python_linters.run_linters.LinterException: 💩 flake8 is not happy! 💩
|
|
169
|
-
```
|
|
170
171
|
### addnoqa example
|
|
171
172
|
- only shows how many noqas it added (`3`) and how many files it left unchanged (`22`)
|
|
172
173
|
```commandline
|
|
@@ -179,11 +180,9 @@ addnoqa iteration: 0
|
|
|
179
180
|
```
|
|
180
181
|
- it adds noqas like this one:
|
|
181
182
|
```python
|
|
182
|
-
def foobar(x):
|
|
183
|
+
def foobar(x): # noqa: ANN001, ANN202
|
|
183
184
|
return "whatever"
|
|
184
185
|
|
|
185
|
-
from faster_whisper.transcribe import Segment as FasterWhisperSegment # noqa: E402
|
|
186
|
-
|
|
187
186
|
```
|
|
188
187
|
# IDE integration
|
|
189
188
|
## manual vscode integration
|
|
@@ -216,4 +215,4 @@ from faster_whisper.transcribe import Segment as FasterWhisperSegment # noqa: E
|
|
|
216
215
|

|
|
217
216
|
## alternatives
|
|
218
217
|
- https://github.com/astral-sh/ruff-vscode
|
|
219
|
-
- https://plugins.jetbrains.com/plugin/20574-ruff
|
|
218
|
+
- https://plugins.jetbrains.com/plugin/20574-ruff
|
|
@@ -1,33 +1,27 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: python-linters
|
|
3
|
-
Version: 0.1.3
|
|
4
|
-
Summary: bundling config files for linters like ruff and flake8
|
|
5
|
-
Home-page: https://github.com/dertilo/python-linters
|
|
6
|
-
Author: Tilo Himmelsbach
|
|
7
|
-
Author-email: dertilo@gmail.com
|
|
8
|
-
Requires-Python: >=3.10,<4.0
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
-
Requires-Dist: black (>=23.9.1,<24.0.0)
|
|
14
|
-
Requires-Dist: flake8 (>=6.1.0,<7.0.0)
|
|
15
|
-
Requires-Dist: flake8-newspaper-style (>=0.4.3,<0.5.0)
|
|
16
|
-
Requires-Dist: ruff (>=0.0.291)
|
|
17
|
-
Requires-Dist: toml (>=0.10.2,<0.11.0)
|
|
18
|
-
Requires-Dist: wemake-python-styleguide (>=0.18.0,<0.19.0)
|
|
19
|
-
Project-URL: Repository, https://github.com/dertilo/python-linters
|
|
20
|
-
Description-Content-Type: text/markdown
|
|
21
|
-
|
|
22
1
|

|
|
23
2
|
[](https://opensource.org/licenses/MIT)
|
|
24
3
|
[](https://beartype.readthedocs.io)
|
|
25
4
|
# python-linters
|
|
26
|
-
- bundles
|
|
5
|
+
- bundles ruff and basedpyright into a single poetry-script
|
|
27
6
|
- project independent linter configuration (via `ruff.toml`,`.flake8`) -> one config to rule them all
|
|
28
7
|
### use-cases:
|
|
29
8
|
1. interactively learning python code quality standards via ruff+flake8, see [local development workflow](#2-local-development-workflow-before-pushing-to-ci-pipeline)
|
|
30
9
|
2. enforcing minimal quality-standards via a "lint-stage" in a ci-pipeline, see [setup for ci-pipeline](#3-setup-for-ci-pipeline)
|
|
10
|
+
## 0. motivation:
|
|
11
|
+
### Python is a Bicycle!
|
|
12
|
+
- initial idea of python: `Bridge the gap between the shell and C.`[see](https://www.artima.com/articles/pythons-design-goals)
|
|
13
|
+

|
|
14
|
+
### run-time "safety"
|
|
15
|
+
- type and data validation at runtime
|
|
16
|
+
- pytests run your code -> runtime
|
|
17
|
+

|
|
18
|
+
### lint-time "safety"
|
|
19
|
+
- linting and static type checking
|
|
20
|
+

|
|
21
|
+
- flake8 already fell down!
|
|
22
|
+
### more "safety" via shorter feed-back loops
|
|
23
|
+

|
|
24
|
+
|
|
31
25
|
|
|
32
26
|
## 1. install (via poetry)
|
|
33
27
|
1. in `pyproject.toml` add to dependencies
|
|
@@ -80,7 +74,7 @@ cond9 --> | complains | cond47{{"ruff"}}:::style0
|
|
|
80
74
|
cond47 --> | complains | op51[\"poetry run addnoqa"/]:::style1
|
|
81
75
|
op51 --> sub53[\"refactor your code \nOR\n keep/add noqa-comment"/]:::style1
|
|
82
76
|
sub53 --> op2
|
|
83
|
-
cond47 --> | is happy | cond58{{"
|
|
77
|
+
cond47 --> | is happy | cond58{{"pyright"}}:::style0
|
|
84
78
|
cond58 --> | complains | sub53
|
|
85
79
|
cond58 --> | is happy | sub66["git commit"]
|
|
86
80
|
sub66 --> sub80
|
|
@@ -134,19 +128,6 @@ All done! ✨ 🍰 ✨
|
|
|
134
128
|
folders_to_be_linted=['whisper_streaming', 'tests']
|
|
135
129
|
```
|
|
136
130
|
|
|
137
|
-
### pythonlinter black is not happy
|
|
138
|
-
```commandline
|
|
139
|
-
poetry run pythonlinter
|
|
140
|
-
linter-order: black->ruff->flake8
|
|
141
|
-
folders_tobelinted=['whisper_streaming', 'tests']
|
|
142
|
-
running black
|
|
143
|
-
would reformat <somehwere>/whisper-streaming/whisper_streaming/post_asr_preparations.py
|
|
144
|
-
would reformat <somehwere>/whisper-streaming/whisper_streaming/faster_whisper_inference/faster_whisper_inferencer.py
|
|
145
|
-
|
|
146
|
-
Oh no! 💥 💔 💥
|
|
147
|
-
2 files would be reformatted, 20 files would be left unchanged.
|
|
148
|
-
python_linters.run_linters.LinterException: 💩 black is not happy! 💩
|
|
149
|
-
```
|
|
150
131
|
### pythonlinter ruff is not happy
|
|
151
132
|
- complains about
|
|
152
133
|
- an unused argument
|
|
@@ -167,27 +148,6 @@ Found 4 errors.
|
|
|
167
148
|
No fixes available (2 hidden fixes can be enabled with the `--unsafe-fixes` option).
|
|
168
149
|
python_linters.run_linters.LinterException: 💩 ruff is not happy! 💩
|
|
169
150
|
```
|
|
170
|
-
### pythonlinter flake8 is not happy
|
|
171
|
-
- complains about too many methods in a class and wrong position of a function in a module
|
|
172
|
-
```commandline
|
|
173
|
-
poetry run pythonlinter
|
|
174
|
-
linter-order: black->ruff->flake8
|
|
175
|
-
folders_tobelinted=['whisper_streaming', 'tests']
|
|
176
|
-
running black
|
|
177
|
-
All done! ✨ 🍰 ✨
|
|
178
|
-
22 files would be left unchanged.
|
|
179
|
-
|
|
180
|
-
passed black linter! ✨ 🍰 ✨
|
|
181
|
-
|
|
182
|
-
running ruff
|
|
183
|
-
|
|
184
|
-
passed ruff linter! ✨ 🍰 ✨
|
|
185
|
-
|
|
186
|
-
running flake8
|
|
187
|
-
whisper_streaming/faster_whisper_inference/faster_whisper_inferencer.py:111:1: WPS214 Found too many methods: 10 > 9
|
|
188
|
-
tests/conftest.py:35:8: NEW100 newspaper style: function is_in_docker_container defined in line 16 should be moved down
|
|
189
|
-
python_linters.run_linters.LinterException: 💩 flake8 is not happy! 💩
|
|
190
|
-
```
|
|
191
151
|
### addnoqa example
|
|
192
152
|
- only shows how many noqas it added (`3`) and how many files it left unchanged (`22`)
|
|
193
153
|
```commandline
|
|
@@ -200,11 +160,9 @@ addnoqa iteration: 0
|
|
|
200
160
|
```
|
|
201
161
|
- it adds noqas like this one:
|
|
202
162
|
```python
|
|
203
|
-
def foobar(x):
|
|
163
|
+
def foobar(x): # noqa: ANN001, ANN202
|
|
204
164
|
return "whatever"
|
|
205
165
|
|
|
206
|
-
from faster_whisper.transcribe import Segment as FasterWhisperSegment # noqa: E402
|
|
207
|
-
|
|
208
166
|
```
|
|
209
167
|
# IDE integration
|
|
210
168
|
## manual vscode integration
|
|
@@ -237,4 +195,4 @@ from faster_whisper.transcribe import Segment as FasterWhisperSegment # noqa: E
|
|
|
237
195
|

|
|
238
196
|
## alternatives
|
|
239
197
|
- https://github.com/astral-sh/ruff-vscode
|
|
240
|
-
- https://plugins.jetbrains.com/plugin/20574-ruff
|
|
198
|
+
- https://plugins.jetbrains.com/plugin/20574-ruff
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-linters"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.5"
|
|
4
4
|
description = "bundling config files for linters like ruff and flake8"
|
|
5
5
|
authors = ["Tilo Himmelsbach <dertilo@gmail.com>"]
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
repository = "https://github.com/dertilo/python-linters"
|
|
8
8
|
packages = [{ include = "python_linters" }]
|
|
9
|
-
|
|
10
|
-
include=["python_linters/.flake8","python_linters/ruff.toml"]
|
|
9
|
+
license = "MIT"
|
|
11
10
|
|
|
12
11
|
[tool.poetry.scripts]
|
|
13
12
|
pythonlinter = 'python_linters.run_linters:main'
|
|
@@ -17,11 +16,8 @@ addnoqa = 'python_linters.add_noqa:main'
|
|
|
17
16
|
[tool.poetry.dependencies]
|
|
18
17
|
python = "^3.10"
|
|
19
18
|
toml = "^0.10.2"
|
|
20
|
-
flake8 = "^6.1.0"
|
|
21
|
-
wemake-python-styleguide = "^0.18.0"
|
|
22
19
|
ruff = ">=0.0.291"
|
|
23
|
-
|
|
24
|
-
flake8-newspaper-style = "^0.4.3"
|
|
20
|
+
basedpyright = "^1.12.5"
|
|
25
21
|
|
|
26
22
|
[tool.poetry.group.dev.dependencies]
|
|
27
23
|
setuptools-scm = "^7.1.0"
|
|
@@ -2,16 +2,12 @@
|
|
|
2
2
|
per-file-ignores=
|
|
3
3
|
exclude=
|
|
4
4
|
ignore = B
|
|
5
|
-
select =
|
|
5
|
+
select = WPS204,WPS236, NEW
|
|
6
6
|
|
|
7
7
|
# --- WPS: Complexity Violations by "wemake-python-styleguide" ---
|
|
8
8
|
# see https://wemake-python-styleguide.readthedocs.io/en/latest/pages/usage/violations/complexity.html#complexity
|
|
9
9
|
|
|
10
|
-
# WPS200: JonesScoreViolation -> this is a median of "LineComplexity", default is 12
|
|
11
|
-
max-jones-score= 12
|
|
12
10
|
# EXCLUDED WPS201: TooManyImportsViolation, default is 12, make no sense for heavy type-annotation usage, many types need to be imported
|
|
13
|
-
# WPS202: TooManyModuleMembersViolation default is 7
|
|
14
|
-
max-module-members=9
|
|
15
11
|
# EXCLUDED WPS203: TooManyImportedNamesViolation, excluded because its not super necessary!
|
|
16
12
|
# WPS204: OverusedExpressionViolation
|
|
17
13
|
# EXCLUDED WPS210: TooManyLocalsViolation, has default of 5 which is too low, it encourages complex lines and is bad for readability!
|
|
@@ -19,30 +15,13 @@ max-module-members=9
|
|
|
19
15
|
# EXCLUDED WPS211: TooManyArgumentsViolation -> this one is already covered by "PLR0913"
|
|
20
16
|
# EXCLUDED WPS212: TooManyReturnsViolation -> this one is already covered by "PLR0911"
|
|
21
17
|
### WPS213: TooManyExpressionsViolation -> this one is already covered by "PLR0915"
|
|
22
|
-
# WPS214: TooManyMethodsViolation, "wemake-default" is 7!
|
|
23
|
-
max-methods=9
|
|
24
|
-
# WPS219: TooDeepAccessViolation, Default: 4, tilo: even 3 is a lot!
|
|
25
|
-
max-access-level=3
|
|
26
18
|
# EXCLUDED WPS221: LineComplexityViolation, "wemake-default" is 14 -> this is not properly working for annotations!
|
|
27
19
|
##max-line-complexity=14
|
|
28
20
|
# EXCLUDED WPS226: OverusedStringViolation -> sure that this isn't already in ruff? -> eigenverantwortung here?
|
|
29
|
-
# WPS227: TooLongOutputTupleViolation
|
|
30
|
-
# WPS228: TooLongCompareViolation -> already covered by WPS221?
|
|
31
|
-
# WPS229: TooLongTryBodyViolation: default is at 1!!
|
|
32
|
-
max-try-body-length=3
|
|
33
|
-
# WPS230: TooManyPublicAttributesViolation, default is 6!
|
|
34
|
-
max-attributes=6
|
|
35
|
-
# WPS231: CognitiveComplexityViolation, wemake-default is 12, melevir's is 7
|
|
36
|
-
max-cognitive-score=12
|
|
37
|
-
# WPS232: CognitiveModuleComplexityViolation, default is 8
|
|
38
|
-
max-cognitive-average=8
|
|
39
|
-
# WPS233: TooLongCallChainViolation
|
|
40
21
|
# WPS236: TooLongTupleUnpackViolation: "If you have more than 2 values in a tuple, consider using typing.NamedTuple or a dataclass instead." rather than unpacking third-party returns you should directly "pipe" into a dataclass
|
|
41
22
|
max-tuple-unpack-length=4
|
|
42
|
-
# WPS425 — Forbid booleans as non-keyword parameters.
|
|
43
|
-
# WPS449 — Forbid float keys.
|
|
44
23
|
# NEW https://github.com/mobility-university/flake8-newspaper-style
|
|
45
|
-
# TMN002: TODO(tilo): maybe incorporate some of this packages logic into the linter?: essentially prohibiting tuples, see: flake8-too-many
|
|
24
|
+
# TMN002: TODO(tilo): maybe incorporate some of this packages logic into the linter?: essentially prohibiting tuples, see: https://gitlab.cc-asp.fraunhofer.de/iais.nm.audio/sandbox/nmaudio-flake8-too-many
|
|
46
25
|
# max-function-return-values=3
|
|
47
26
|
|
|
48
27
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from python_linters.extending_ruff_toml import create_extended_ruff_toml
|
|
4
|
+
from python_linters.getting_to_be_linted_folders import get_folders_to_be_linted
|
|
5
|
+
from python_linters.run_linters import run_cmd
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main() -> None:
|
|
9
|
+
"""
|
|
10
|
+
expects to run from $ContentRoot$
|
|
11
|
+
"""
|
|
12
|
+
folders_tobelinted = get_folders_to_be_linted("pyproject.toml")
|
|
13
|
+
BIG_NUMBER = 9
|
|
14
|
+
for k in range(
|
|
15
|
+
BIG_NUMBER,
|
|
16
|
+
): # theoretically could be necessary to run this loop as long as code changes!
|
|
17
|
+
print(f"addnoqa iteration: {k}")
|
|
18
|
+
run_cmd(
|
|
19
|
+
f"ruff check {' '.join(folders_tobelinted)} --config={create_extended_ruff_toml()} --add-noqa",
|
|
20
|
+
)
|
|
21
|
+
try:
|
|
22
|
+
run_cmd(f"ruff format --check {' '.join(folders_tobelinted)}")
|
|
23
|
+
break
|
|
24
|
+
except Exception:
|
|
25
|
+
run_cmd(f"ruff format {' '.join(folders_tobelinted)}")
|
|
26
|
+
run_cmd(f"fixcode {os.getcwd()}")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
main()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
|
|
3
|
+
package_dir = str(pathlib.Path(__file__).parent.resolve())
|
|
4
|
+
|
|
5
|
+
FLAKE8_CONFIG_FILE = f"{package_dir}/.flake8"
|
|
6
|
+
RUFF_CONFIG_FILE = f"{package_dir}/ruff.toml"
|
|
7
|
+
PYRIGHT_CONFIG_FILE = f"{package_dir}/pyrightconfig.json"
|
|
8
|
+
|
|
9
|
+
assert pathlib.Path(FLAKE8_CONFIG_FILE).is_file()
|
|
10
|
+
assert pathlib.Path(RUFF_CONFIG_FILE).is_file()
|
|
11
|
+
assert pathlib.Path(PYRIGHT_CONFIG_FILE).is_file()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from python_linters.config_files import RUFF_CONFIG_FILE
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def create_extended_ruff_toml() -> str:
|
|
8
|
+
ruff_extension_file = Path("ruff_extension.toml")
|
|
9
|
+
|
|
10
|
+
if ruff_extension_file.is_file():
|
|
11
|
+
fingerprint = f"{ruff_extension_file.stat().st_size}-{ruff_extension_file.stat().st_mtime}"
|
|
12
|
+
extended_ruff_toml_file = f"extended_ruff-{fingerprint}.toml"
|
|
13
|
+
if not Path(extended_ruff_toml_file).is_file():
|
|
14
|
+
print(f"extending {RUFF_CONFIG_FILE} with {ruff_extension_file=}")
|
|
15
|
+
with Path(extended_ruff_toml_file).open("w", encoding="locale") as f:
|
|
16
|
+
lines = [
|
|
17
|
+
f'extend = "{RUFF_CONFIG_FILE}"',
|
|
18
|
+
*list(_read_lines(ruff_extension_file)),
|
|
19
|
+
]
|
|
20
|
+
for l in lines:
|
|
21
|
+
f.write(f"{l}\n")
|
|
22
|
+
else:
|
|
23
|
+
print(f"using {extended_ruff_toml_file}")
|
|
24
|
+
else:
|
|
25
|
+
extended_ruff_toml_file = RUFF_CONFIG_FILE
|
|
26
|
+
return extended_ruff_toml_file
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _read_lines(
|
|
30
|
+
file: Path,
|
|
31
|
+
encoding: str = "utf-8",
|
|
32
|
+
) -> Iterator[str]:
|
|
33
|
+
with file.open(mode="rb") as f:
|
|
34
|
+
for raw_line in f:
|
|
35
|
+
line = raw_line.decode(encoding)
|
|
36
|
+
line = line.replace("\n", "").replace("\r", "")
|
|
37
|
+
yield line
|
|
@@ -2,27 +2,27 @@ import subprocess
|
|
|
2
2
|
import sys
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
|
-
from python_linters.
|
|
5
|
+
from python_linters.extending_ruff_toml import create_extended_ruff_toml
|
|
6
|
+
from python_linters.getting_to_be_linted_folders import get_folders_to_be_linted
|
|
6
7
|
|
|
7
8
|
|
|
8
|
-
def run_cmd(cmd):
|
|
9
|
+
def run_cmd(cmd) -> None:
|
|
9
10
|
subprocess.check_call(cmd, stdout=sys.stdout, stderr=sys.stdout, shell=True)
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
def run_cmd_ignore_errors(cmd):
|
|
13
|
+
def run_cmd_ignore_errors(cmd) -> None:
|
|
13
14
|
subprocess.call(cmd, stdout=sys.stdout, stderr=sys.stdout, shell=True)
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
def main():
|
|
17
|
+
def main() -> None:
|
|
17
18
|
dirr = Path.cwd()
|
|
18
19
|
folders_to_be_linted = get_folders_to_be_linted("pyproject.toml")
|
|
19
20
|
folders = " ".join(folders_to_be_linted)
|
|
20
21
|
|
|
21
|
-
run_cmd(f"cd {dirr} && isort --profile black {folders}")
|
|
22
22
|
run_cmd_ignore_errors(
|
|
23
|
-
f"cd {dirr} && ruff check {folders} --config={
|
|
23
|
+
f"cd {dirr} && ruff check {folders} --config={create_extended_ruff_toml()} --fix",
|
|
24
24
|
)
|
|
25
|
-
run_cmd(f"cd {dirr} &&
|
|
25
|
+
run_cmd(f"cd {dirr} && ruff format {folders}")
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import toml
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PackagesOrFoldersToBeLintedAreNotProperlyDefined(Exception): # noqa: N818
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
sys.tracebacklimit = -1
|
|
10
|
+
msg = """in your pyproject.toml specify the directories that you want to be linted
|
|
11
|
+
a. via packages
|
|
12
|
+
|
|
13
|
+
packages = [
|
|
14
|
+
{ include = \"my_package_name\" },
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
b. or via tool.python-linters
|
|
18
|
+
|
|
19
|
+
[tool.python-linters]
|
|
20
|
+
folders_to_be_linted=["my_directory","another_dir/my_sub_package"]"""
|
|
21
|
+
super().__init__(msg)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_folders_to_be_linted(pyproject_toml: str) -> list[str]:
|
|
25
|
+
if not pathlib.Path(pyproject_toml).is_file():
|
|
26
|
+
msg = f"pyproject.toml not found in {pathlib.Path.cwd()}\nplease run this script from the root of your project"
|
|
27
|
+
raise FileNotFoundError(
|
|
28
|
+
msg,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
with open(pyproject_toml, encoding="locale") as f:
|
|
32
|
+
t = toml.load(f)
|
|
33
|
+
folders = (
|
|
34
|
+
t.get("tool", {})
|
|
35
|
+
.get("python-linters", {})
|
|
36
|
+
.get("folders_to_be_linted", None)
|
|
37
|
+
)
|
|
38
|
+
if (
|
|
39
|
+
folders is None
|
|
40
|
+
and (packages := t.get("tool", {}).get("poetry", {}).get("packages", None))
|
|
41
|
+
is not None
|
|
42
|
+
):
|
|
43
|
+
folders = [p["include"] for p in packages]
|
|
44
|
+
if pathlib.Path(f"{pathlib.Path(pyproject_toml).parent}/tests").is_dir():
|
|
45
|
+
folders += ["tests"]
|
|
46
|
+
|
|
47
|
+
if folders is None:
|
|
48
|
+
raise PackagesOrFoldersToBeLintedAreNotProperlyDefined
|
|
49
|
+
assert len(folders) > 0
|
|
50
|
+
print(f"found following {folders=}")
|
|
51
|
+
return folders
|
|
@@ -10,9 +10,7 @@ if __name__ == "__main__":
|
|
|
10
10
|
)
|
|
11
11
|
return code, f"{short_expl}: {long_expl}"
|
|
12
12
|
|
|
13
|
-
with open("python_linter_configs/ruff_rules.txt") as f:
|
|
14
|
-
code_desc = (
|
|
15
|
-
parse_line(l) for l in f.readlines() if pattern.match(l) is not None
|
|
16
|
-
)
|
|
13
|
+
with open("python_linter_configs/ruff_rules.txt", encoding="locale") as f:
|
|
14
|
+
code_desc = (parse_line(l) for l in f if pattern.match(l) is not None)
|
|
17
15
|
code2desc = dict(code_desc)
|
|
18
16
|
print(code2desc)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"typeCheckingMode": "basic", // basic to ease transition, this entire config is (automatically copypasted and) to be adapted to each project
|
|
3
|
+
"reportAny": false,
|
|
4
|
+
"reportImplicitOverride": false,
|
|
5
|
+
// cause typing.override leads to false positives
|
|
6
|
+
"reportMissingSuperCall": false,
|
|
7
|
+
"reportMissingParameterType": false, // already done by ruff
|
|
8
|
+
"reportUnusedCallResult": false, // gibt schlimmeres!
|
|
9
|
+
"reportPrivateUsage": false, // underscore convention is enough!
|
|
10
|
+
"reportIncompatibleMethodOverride": false,
|
|
11
|
+
"reportMissingTypeStubs": false,
|
|
12
|
+
"reportUnknownLambdaType": false, // seems to affect all lambdas
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
"reportUnknownVariableType": "warning",
|
|
16
|
+
"reportUnknownMemberType": "warning",
|
|
17
|
+
"reportUnknownArgumentType": "warning",
|
|
18
|
+
"reportMissingTypeArgument": "warning",
|
|
19
|
+
"reportUnknownParameterType": "warning",
|
|
20
|
+
"reportUnusedVariable": "warning"
|
|
21
|
+
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
target-version = "py310"
|
|
2
2
|
# Exclude a variety of commonly ignored directories. see https://beta.ruff.rs/docs/configuration/#using-pyprojecttoml
|
|
3
3
|
[lint]
|
|
4
|
+
preview = true
|
|
5
|
+
extend-safe-fixes = ["ALL"] # yolo
|
|
6
|
+
extend-unsafe-fixes=[
|
|
7
|
+
"T20", # don't remove prints
|
|
8
|
+
"FURB140" # starmap slower than comprehension in 3.12
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
|
|
4
12
|
exclude = [
|
|
5
13
|
".bzr",
|
|
6
14
|
".direnv",
|
|
@@ -36,6 +44,7 @@ select = [
|
|
|
36
44
|
"YTT", # flake8-2020
|
|
37
45
|
"ANN", # flake8-annotations
|
|
38
46
|
"ASYNC", # flake8-async
|
|
47
|
+
"TRIO", # flake8-trio
|
|
39
48
|
"S", # flake8-bandit
|
|
40
49
|
"BLE", # flake8-blind-except
|
|
41
50
|
# excluded "FBT", # flake8-boolean-trap -> tilo: this one might be too strict/hard to refactor
|
|
@@ -52,6 +61,7 @@ select = [
|
|
|
52
61
|
"FA", # flake8-future-annotations
|
|
53
62
|
"ISC", # flake8-implicit-str-concat
|
|
54
63
|
"ICN", # flake8-import-conventions
|
|
64
|
+
"LOG", # flake8-logging
|
|
55
65
|
"G", # flake8-logging-format
|
|
56
66
|
"INP", # flake8-no-pep420
|
|
57
67
|
"PIE", # flake8-pie
|
|
@@ -75,13 +85,16 @@ select = [
|
|
|
75
85
|
"PD", # pandas-vet
|
|
76
86
|
"PGH", # pygrep-hooks
|
|
77
87
|
"PL", # Pylint
|
|
88
|
+
"C", # Convention
|
|
89
|
+
"E", # Error
|
|
90
|
+
"R", # Refactor
|
|
91
|
+
"W", # Warning
|
|
78
92
|
"TRY", # tryceratops
|
|
79
93
|
"FLY", # flynt
|
|
80
94
|
"NPY", # NumPy-specific rules
|
|
81
95
|
# excluded "AIR", # Airflow -> we are not using airflow!
|
|
82
96
|
"PERF", # Perflint
|
|
83
|
-
|
|
84
|
-
# excluded "LOG", # flake8-logging -> not yet stabel?
|
|
97
|
+
"FURB", # refurb
|
|
85
98
|
"RUF", # Ruff-specific rules
|
|
86
99
|
]
|
|
87
100
|
# --------------- IGNORING specific rules --------------------------------------------------------
|
|
@@ -112,6 +125,7 @@ ignore = [
|
|
|
112
125
|
"UP008", # see: https://stackoverflow.com/questions/73268995/typeerror-when-calling-super-in-dataclassslots-true-subclass
|
|
113
126
|
"RET506", # looks like a false-positive
|
|
114
127
|
"SLF001", # everybody knows about the _-conventin, if one still accesses "protected" attributes one has their reasons!
|
|
128
|
+
"FURB140", # starmap slower than comprehension in 3.12
|
|
115
129
|
]
|
|
116
130
|
|
|
117
131
|
[lint.mccabe]
|
|
@@ -140,6 +154,5 @@ max-returns = 3
|
|
|
140
154
|
# PLR0915 default is 50! -> can you ever reach this limit? max-complexity would catch those code-blocks first!
|
|
141
155
|
max-statements = 25
|
|
142
156
|
# --------------- PLR0904 too-many-public-methods --------------------------------------------------------
|
|
143
|
-
#
|
|
144
|
-
|
|
145
|
-
max-public-methods = 0
|
|
157
|
+
# Default value: 20, wemake's TooManyMethodsViolation (WPS214) has default of 7
|
|
158
|
+
max-public-methods = 20 # is not only counting public but all methods!
|
|
@@ -11,6 +11,7 @@ pyupgrade (UP)
|
|
|
11
11
|
flake8-2020 (YTT)
|
|
12
12
|
flake8-annotations (ANN)
|
|
13
13
|
flake8-async (ASYNC)
|
|
14
|
+
flake8-trio (TRIO)
|
|
14
15
|
flake8-bandit (S)
|
|
15
16
|
flake8-blind-except (BLE)
|
|
16
17
|
flake8-boolean-trap (FBT)
|
|
@@ -27,6 +28,7 @@ flake8-executable (EXE)
|
|
|
27
28
|
flake8-future-annotations (FA)
|
|
28
29
|
flake8-implicit-str-concat (ISC)
|
|
29
30
|
flake8-import-conventions (ICN)
|
|
31
|
+
flake8-logging (LOG)
|
|
30
32
|
flake8-logging-format (G)
|
|
31
33
|
flake8-no-pep420 (INP)
|
|
32
34
|
flake8-pie (PIE)
|
|
@@ -50,18 +52,21 @@ eradicate (ERA)
|
|
|
50
52
|
pandas-vet (PD)
|
|
51
53
|
pygrep-hooks (PGH)
|
|
52
54
|
Pylint (PL)
|
|
55
|
+
Convention (C)
|
|
56
|
+
Error (E)
|
|
57
|
+
Refactor (R)
|
|
58
|
+
Warning (W)
|
|
53
59
|
tryceratops (TRY)
|
|
54
60
|
flynt (FLY)
|
|
55
61
|
NumPy-specific rules (NPY)
|
|
56
62
|
Airflow (AIR)
|
|
57
63
|
Perflint (PERF)
|
|
58
64
|
refurb (FURB)
|
|
59
|
-
flake8-logging (LOG)
|
|
60
65
|
Ruff-specific rules (RUF)
|
|
61
66
|
"""
|
|
62
67
|
|
|
63
68
|
|
|
64
|
-
def copypaste_this_into_ruff_tomls_select_list():
|
|
69
|
+
def copypaste_this_into_ruff_tomls_select_list() -> None:
|
|
65
70
|
names_code = [l.replace(")", "").split("(") for l in rule_categories.split("\n")]
|
|
66
71
|
code_names = [(cn[1], cn[0]) for cn in names_code if len(cn) == 2]
|
|
67
72
|
print(code_names)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from python_linters.config_files import PYRIGHT_CONFIG_FILE
|
|
5
|
+
from python_linters.extending_ruff_toml import create_extended_ruff_toml
|
|
6
|
+
from python_linters.getting_to_be_linted_folders import get_folders_to_be_linted
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def run_cmd(cmd: str) -> int:
|
|
10
|
+
return subprocess.call(cmd, stdout=sys.stdout, stderr=sys.stdout, shell=True)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LinterException(Exception):
|
|
14
|
+
def __init__(self, linter_name: str):
|
|
15
|
+
sys.tracebacklimit = -1 # to disable traceback
|
|
16
|
+
super().__init__(f"💩 {linter_name} is not happy! 💩")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
NAME2LINTER = {
|
|
20
|
+
"ruff-format": lambda folders_tobelinted: f"ruff format --check {' '.join(folders_tobelinted)}",
|
|
21
|
+
"ruff": lambda folders_tobelinted: f"poetry run ruff check {' '.join(folders_tobelinted)} --config={create_extended_ruff_toml()}",
|
|
22
|
+
"basedpyright": lambda folders_tobelinted: f"cp -n {PYRIGHT_CONFIG_FILE} ./ && poetry run basedpyright {' '.join(folders_tobelinted)} --gitlabcodequality report.json --level $(cat pyrightlevel.txt 2>/dev/null || echo 'warning')",
|
|
23
|
+
# most flake8 linters are already included in ruff
|
|
24
|
+
# the news-paper-style function ordering rule is currently only enforced by a flake8 plugin but its not that important
|
|
25
|
+
# "flake8": lambda folders_tobelinted: f"poetry run flake8 --config={FLAKE8_CONFIG_FILE} {' '.join(folders_tobelinted)}",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def main() -> None:
|
|
30
|
+
folders_tobelinted = get_folders_to_be_linted("pyproject.toml")
|
|
31
|
+
print(f"linter-order: {'->'.join(NAME2LINTER.keys())}")
|
|
32
|
+
sys.stdout.flush()
|
|
33
|
+
|
|
34
|
+
for linter_name, linter_cmd_factory in NAME2LINTER.items():
|
|
35
|
+
print(f"running {linter_name}")
|
|
36
|
+
sys.stdout.flush()
|
|
37
|
+
|
|
38
|
+
if run_cmd(linter_cmd_factory(folders_tobelinted)) != 0:
|
|
39
|
+
raise LinterException(linter_name)
|
|
40
|
+
print(f"\npassed {linter_name} linter! ✨ 🍰 ✨\n")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
main()
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
from python_linters.run_linters import (
|
|
4
|
-
RUFF_CONFIG_FILE,
|
|
5
|
-
get_folders_to_be_linted,
|
|
6
|
-
run_cmd,
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def main():
|
|
11
|
-
"""
|
|
12
|
-
expects to run from $ContentRoot$
|
|
13
|
-
"""
|
|
14
|
-
folders_tobelinted = get_folders_to_be_linted("pyproject.toml")
|
|
15
|
-
BIG_NUMBER = 9
|
|
16
|
-
for k in range(
|
|
17
|
-
BIG_NUMBER,
|
|
18
|
-
): # theoretically could be necessary to run this loop as long as code changes!
|
|
19
|
-
print(f"addnoqa iteration: {k}")
|
|
20
|
-
run_cmd(
|
|
21
|
-
f"poetry run ruff check {' '.join(folders_tobelinted)} --config={RUFF_CONFIG_FILE} --add-noqa",
|
|
22
|
-
)
|
|
23
|
-
try:
|
|
24
|
-
run_cmd(f"black --check {' '.join(folders_tobelinted)}")
|
|
25
|
-
break
|
|
26
|
-
except Exception:
|
|
27
|
-
run_cmd(f"black {' '.join(folders_tobelinted)}")
|
|
28
|
-
run_cmd(f"poetry run fixcode {os.getcwd()}")
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if __name__ == "__main__":
|
|
32
|
-
main()
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import pathlib
|
|
2
|
-
import subprocess
|
|
3
|
-
import sys
|
|
4
|
-
|
|
5
|
-
import toml
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# TODO: one could brute-force search all files and replace codes, but is there a more elegant way?
|
|
9
|
-
# def replace_noqa_code():
|
|
10
|
-
# >> > import re
|
|
11
|
-
# >> > l = {'NORTH': 'N', 'SOUTH': 'S', 'EAST': 'E', 'WEST': 'W'}
|
|
12
|
-
# >> > pattern = '|'.join(sorted(re.escape(k) for k in l))
|
|
13
|
-
# >> > address = "123 north anywhere street"
|
|
14
|
-
# >> > re.sub(pattern, lambda m: l.get(m.group(0).upper()), address,
|
|
15
|
-
# flags=re.IGNORECASE)
|
|
16
|
-
# '123 N anywhere street'
|
|
17
|
-
# >> >
|
|
18
|
-
#
|
|
19
|
-
def run_cmd(cmd: str) -> int:
|
|
20
|
-
return subprocess.call(cmd, stdout=sys.stdout, stderr=sys.stdout, shell=True)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
package_dir = str(pathlib.Path(__file__).parent.resolve())
|
|
24
|
-
|
|
25
|
-
FLAKE8_CONFIG_FILE = f"{package_dir}/.flake8"
|
|
26
|
-
RUFF_CONFIG_FILE = f"{package_dir}/ruff.toml"
|
|
27
|
-
assert pathlib.Path(FLAKE8_CONFIG_FILE).is_file()
|
|
28
|
-
assert pathlib.Path(RUFF_CONFIG_FILE).is_file()
|
|
29
|
-
|
|
30
|
-
RUFF_ARGS = ["--fix", "--add-noqa"]
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class PackagesOrFoldersToBeLintedAreNotProperlyDefined(Exception): # noqa: N818
|
|
34
|
-
def __init__(self) -> None:
|
|
35
|
-
sys.tracebacklimit = -1
|
|
36
|
-
msg = """in your pyproject.toml specify the directories that you want to be linted
|
|
37
|
-
a. via packages
|
|
38
|
-
|
|
39
|
-
packages = [
|
|
40
|
-
{ include = \"my_package_name\" },
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
b. or via tool.python-linters
|
|
44
|
-
|
|
45
|
-
[tool.python-linters]
|
|
46
|
-
folders_to_be_linted=["my_directory","another_dir/my_sub_package"]"""
|
|
47
|
-
super().__init__(msg)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def get_folders_to_be_linted(pyproject_toml: str) -> list[str]:
|
|
51
|
-
if not pathlib.Path(pyproject_toml).is_file():
|
|
52
|
-
raise FileNotFoundError(
|
|
53
|
-
f"pyproject.toml not found in {pathlib.Path.cwd()}\nplease run this script from the root of your project",
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
with open(pyproject_toml) as f:
|
|
57
|
-
t = toml.load(f)
|
|
58
|
-
folders = (
|
|
59
|
-
t.get("tool", {}).get("python-linters", {}).get("folders_to_be_linted", None)
|
|
60
|
-
)
|
|
61
|
-
if (
|
|
62
|
-
folders is None
|
|
63
|
-
and (packages := t.get("tool", {}).get("poetry", {}).get("packages", None))
|
|
64
|
-
is not None
|
|
65
|
-
):
|
|
66
|
-
folders = [p["include"] for p in packages]
|
|
67
|
-
if pathlib.Path(f"{pathlib.Path(pyproject_toml).parent}/tests").is_dir():
|
|
68
|
-
folders += ["tests"]
|
|
69
|
-
|
|
70
|
-
if folders is None:
|
|
71
|
-
raise PackagesOrFoldersToBeLintedAreNotProperlyDefined
|
|
72
|
-
assert len(folders) > 0
|
|
73
|
-
print(f"found following {folders=}")
|
|
74
|
-
return folders
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class LinterException(Exception):
|
|
78
|
-
def __init__(self, linter_name: str):
|
|
79
|
-
sys.tracebacklimit = -1 # to disable traceback
|
|
80
|
-
super().__init__(f"💩 {linter_name} is not happy! 💩")
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
NAME2LINTER = {
|
|
84
|
-
"black": lambda folders_tobelinted: f"black --check {' '.join(folders_tobelinted)}",
|
|
85
|
-
"ruff": lambda folders_tobelinted: f"poetry run ruff check {' '.join(folders_tobelinted)} --config={RUFF_CONFIG_FILE}",
|
|
86
|
-
"flake8": lambda folders_tobelinted: f"poetry run flake8 --config={FLAKE8_CONFIG_FILE} {' '.join(folders_tobelinted)}",
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def main():
|
|
91
|
-
folders_tobelinted = get_folders_to_be_linted("pyproject.toml")
|
|
92
|
-
print(f"linter-order: {'->'.join(NAME2LINTER.keys())}")
|
|
93
|
-
sys.stdout.flush()
|
|
94
|
-
|
|
95
|
-
for linter_name, linter_cmd_factory in NAME2LINTER.items():
|
|
96
|
-
print(f"running {linter_name}")
|
|
97
|
-
sys.stdout.flush()
|
|
98
|
-
|
|
99
|
-
if run_cmd(linter_cmd_factory(folders_tobelinted)) != 0:
|
|
100
|
-
raise LinterException(linter_name)
|
|
101
|
-
print(f"\npassed {linter_name} linter! ✨ 🍰 ✨\n")
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if __name__ == "__main__":
|
|
105
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|