prospector 1.7.5__tar.gz → 1.14.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.
- {prospector-1.7.5 → prospector-1.14.0}/PKG-INFO +54 -24
- {prospector-1.7.5 → prospector-1.14.0}/README.rst +33 -8
- prospector-1.14.0/prospector/__main__.py +4 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/autodetect.py +26 -28
- {prospector-1.7.5 → prospector-1.14.0}/prospector/blender.py +19 -12
- prospector-1.14.0/prospector/blender_combinations.yaml +287 -0
- prospector-1.14.0/prospector/compat.py +14 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/config/__init__.py +110 -62
- {prospector-1.7.5 → prospector-1.14.0}/prospector/config/configuration.py +20 -15
- {prospector-1.7.5 → prospector-1.14.0}/prospector/config/datatype.py +3 -3
- {prospector-1.7.5 → prospector-1.14.0}/prospector/encoding.py +13 -8
- {prospector-1.7.5 → prospector-1.14.0}/prospector/exceptions.py +7 -10
- prospector-1.14.0/prospector/finder.py +132 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/formatters/__init__.py +5 -3
- prospector-1.14.0/prospector/formatters/base.py +56 -0
- prospector-1.14.0/prospector/formatters/base_summary.py +43 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/formatters/emacs.py +5 -10
- {prospector-1.7.5 → prospector-1.14.0}/prospector/formatters/grouped.py +9 -8
- {prospector-1.7.5 → prospector-1.14.0}/prospector/formatters/json.py +4 -7
- prospector-1.14.0/prospector/formatters/pylint.py +80 -0
- prospector-1.14.0/prospector/formatters/pylint_parseable.py +74 -0
- prospector-1.14.0/prospector/formatters/text.py +52 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/formatters/vscode.py +17 -8
- {prospector-1.7.5 → prospector-1.14.0}/prospector/formatters/xunit.py +6 -7
- {prospector-1.7.5 → prospector-1.14.0}/prospector/formatters/yaml.py +5 -4
- prospector-1.14.0/prospector/message.py +119 -0
- prospector-1.14.0/prospector/pathutils.py +37 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/postfilter.py +16 -11
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/__init__.py +2 -2
- prospector-1.14.0/prospector/profiles/exceptions.py +31 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profile.py +121 -69
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/no_test_warnings.yaml +1 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/strictness_high.yaml +7 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/strictness_medium.yaml +4 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/strictness_veryhigh.yaml +4 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/run.py +41 -43
- prospector-1.14.0/prospector/suppression.py +157 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/__init__.py +30 -11
- prospector-1.14.0/prospector/tools/bandit/__init__.py +81 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/base.py +13 -2
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/dodgy/__init__.py +14 -20
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/mccabe/__init__.py +15 -13
- prospector-1.14.0/prospector/tools/mypy/__init__.py +107 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/profile_validator/__init__.py +46 -36
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/pycodestyle/__init__.py +35 -45
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/pydocstyle/__init__.py +17 -18
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/pyflakes/__init__.py +36 -21
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/pylint/__init__.py +90 -61
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/pylint/collector.py +16 -17
- prospector-1.14.0/prospector/tools/pylint/linter.py +45 -0
- prospector-1.14.0/prospector/tools/pyright/__init__.py +99 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/pyroma/__init__.py +32 -21
- prospector-1.14.0/prospector/tools/ruff/__init__.py +86 -0
- prospector-1.14.0/prospector/tools/utils.py +59 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/vulture/__init__.py +26 -16
- prospector-1.14.0/pyproject.toml +110 -0
- prospector-1.14.0/setup.py +81 -0
- prospector-1.7.5/prospector/blender_combinations.yaml +0 -257
- prospector-1.7.5/prospector/finder.py +0 -218
- prospector-1.7.5/prospector/formatters/base.py +0 -14
- prospector-1.7.5/prospector/formatters/pylint.py +0 -45
- prospector-1.7.5/prospector/formatters/text.py +0 -101
- prospector-1.7.5/prospector/message.py +0 -112
- prospector-1.7.5/prospector/pathutils.py +0 -33
- prospector-1.7.5/prospector/profiles/exceptions.py +0 -28
- prospector-1.7.5/prospector/suppression.py +0 -118
- prospector-1.7.5/prospector/tools/bandit/__init__.py +0 -62
- prospector-1.7.5/prospector/tools/frosted/__init__.py +0 -82
- prospector-1.7.5/prospector/tools/mypy/__init__.py +0 -116
- prospector-1.7.5/prospector/tools/pylint/linter.py +0 -26
- prospector-1.7.5/prospector/tools/utils.py +0 -45
- prospector-1.7.5/pyproject.toml +0 -99
- prospector-1.7.5/setup.py +0 -77
- {prospector-1.7.5 → prospector-1.14.0}/LICENSE +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/__init__.py +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/default.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/doc_warnings.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/flake8.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/full_pep8.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/member_warnings.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/no_doc_warnings.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/no_member_warnings.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/no_pep8.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/strictness_low.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/strictness_none.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/strictness_verylow.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/profiles/profiles/test_warnings.yaml +0 -0
- {prospector-1.7.5 → prospector-1.14.0}/prospector/tools/exceptions.py +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: prospector
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.14.0
|
|
4
|
+
Summary: Prospector is a tool to analyse Python code by aggregating the result of other tools.
|
|
5
5
|
Home-page: http://prospector.readthedocs.io
|
|
6
|
-
License: GPLv2
|
|
6
|
+
License: GPLv2+
|
|
7
7
|
Keywords: pylint,prospector,static code analysis
|
|
8
8
|
Author: Carl Crowder
|
|
9
9
|
Author-email: git@carlcrowder.com
|
|
10
10
|
Maintainer: Carl Crowder
|
|
11
11
|
Maintainer-email: git@carlcrowder.com
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.9,<4.0
|
|
13
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
14
14
|
Classifier: Environment :: Console
|
|
15
15
|
Classifier: Intended Audience :: Developers
|
|
@@ -17,35 +17,40 @@ Classifier: License :: OSI Approved :: GNU General Public License v2 or later (G
|
|
|
17
17
|
Classifier: License :: Other/Proprietary License
|
|
18
18
|
Classifier: Operating System :: Unix
|
|
19
19
|
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
26
|
Classifier: Programming Language :: Python :: 3.9
|
|
25
27
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
26
28
|
Provides-Extra: with_bandit
|
|
27
29
|
Provides-Extra: with_everything
|
|
28
|
-
Provides-Extra: with_frosted
|
|
29
30
|
Provides-Extra: with_mypy
|
|
31
|
+
Provides-Extra: with_pyright
|
|
30
32
|
Provides-Extra: with_pyroma
|
|
33
|
+
Provides-Extra: with_ruff
|
|
31
34
|
Provides-Extra: with_vulture
|
|
35
|
+
Requires-Dist: GitPython (>=3.1.27,<4.0.0)
|
|
32
36
|
Requires-Dist: PyYAML
|
|
33
37
|
Requires-Dist: bandit (>=1.5.1); extra == "with_bandit" or extra == "with_everything"
|
|
34
38
|
Requires-Dist: dodgy (>=0.2.1,<0.3.0)
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist: mccabe (>=0.6.0,<0.7.0)
|
|
39
|
+
Requires-Dist: mccabe (>=0.7.0,<0.8.0)
|
|
37
40
|
Requires-Dist: mypy (>=0.600); extra == "with_mypy" or extra == "with_everything"
|
|
41
|
+
Requires-Dist: packaging
|
|
38
42
|
Requires-Dist: pep8-naming (>=0.3.3,<=0.10.0)
|
|
39
|
-
Requires-Dist: pycodestyle (>=2.
|
|
43
|
+
Requires-Dist: pycodestyle (>=2.9.0)
|
|
40
44
|
Requires-Dist: pydocstyle (>=2.0.0)
|
|
41
|
-
Requires-Dist: pyflakes (>=2.2.0
|
|
42
|
-
Requires-Dist: pylint (>=
|
|
45
|
+
Requires-Dist: pyflakes (>=2.2.0)
|
|
46
|
+
Requires-Dist: pylint (>=3.0)
|
|
43
47
|
Requires-Dist: pylint-celery (==0.3)
|
|
44
|
-
Requires-Dist: pylint-django (>=2.
|
|
48
|
+
Requires-Dist: pylint-django (>=2.6.1)
|
|
45
49
|
Requires-Dist: pylint-flask (==0.6)
|
|
46
|
-
Requires-Dist:
|
|
50
|
+
Requires-Dist: pyright (>=1.1.3); extra == "with_pyright" or extra == "with_everything"
|
|
47
51
|
Requires-Dist: pyroma (>=2.4); extra == "with_pyroma" or extra == "with_everything"
|
|
48
|
-
Requires-Dist: requirements-detector (>=
|
|
52
|
+
Requires-Dist: requirements-detector (>=1.3.2)
|
|
53
|
+
Requires-Dist: ruff; extra == "with_ruff" or extra == "with_everything"
|
|
49
54
|
Requires-Dist: setoptconf-tmp (>=0.3.1,<0.4.0)
|
|
50
55
|
Requires-Dist: toml (>=0.10.2,<0.11.0)
|
|
51
56
|
Requires-Dist: vulture (>=1.5); extra == "with_vulture" or extra == "with_everything"
|
|
@@ -58,8 +63,8 @@ prospector
|
|
|
58
63
|
.. image:: https://img.shields.io/pypi/v/prospector.svg
|
|
59
64
|
:target: https://pypi.python.org/pypi/prospector
|
|
60
65
|
:alt: Latest Version of Prospector
|
|
61
|
-
.. image:: https://
|
|
62
|
-
:target: https://
|
|
66
|
+
.. image:: https://github.com/PyCQA/prospector/actions/workflows/tests.yml/badge.svg
|
|
67
|
+
:target: https://github.com/PyCQA/prospector/actions/workflows/tests.yml
|
|
63
68
|
:alt: Build Status
|
|
64
69
|
.. image:: https://img.shields.io/coveralls/PyCQA/prospector.svg?style=flat
|
|
65
70
|
:target: https://coveralls.io/r/PyCQA/prospector
|
|
@@ -202,35 +207,60 @@ text to your repositories' ``.pre-commit-config.yaml``::
|
|
|
202
207
|
|
|
203
208
|
repos:
|
|
204
209
|
- repo: https://github.com/PyCQA/prospector
|
|
205
|
-
rev: 1.
|
|
210
|
+
rev: 1.10.0 # The version of Prospector to use, if not 'master' for latest
|
|
206
211
|
hooks:
|
|
207
212
|
- id: prospector
|
|
208
213
|
|
|
209
|
-
This only installs base prospector - if you also use optional tools, for example bandit or mypy, then you can add
|
|
214
|
+
This only installs base prospector - if you also use optional tools, for example bandit and/or mypy, then you can add
|
|
210
215
|
them to the hook configuration like so::
|
|
211
216
|
|
|
212
217
|
repos:
|
|
213
218
|
- repo: https://github.com/PyCQA/prospector
|
|
214
|
-
rev: 1.
|
|
219
|
+
rev: 1.10.0
|
|
215
220
|
hooks:
|
|
216
221
|
- id: prospector
|
|
217
|
-
|
|
222
|
+
additional_dependencies:
|
|
218
223
|
- ".[with_mypy,with_bandit]"
|
|
224
|
+
- args: [
|
|
225
|
+
'--with-tool=mypy',
|
|
226
|
+
'--with-tool=bandit',
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
Additional dependencies can be `individually configured <https://prospector.landscape.io/en/master/profiles.html#individual-configuration-options>`_ in your `prospector.yml` file ::
|
|
230
|
+
|
|
231
|
+
# https://bandit.readthedocs.io/en/latest/config.html
|
|
232
|
+
bandit:
|
|
233
|
+
options:
|
|
234
|
+
skips:
|
|
235
|
+
- B201
|
|
236
|
+
- B601
|
|
237
|
+
- B610
|
|
238
|
+
- B611
|
|
239
|
+
- B703
|
|
240
|
+
|
|
241
|
+
# https://mypy.readthedocs.io/en/stable/command_line.html
|
|
242
|
+
mypy:
|
|
243
|
+
options:
|
|
244
|
+
ignore-missing-imports: true
|
|
219
245
|
|
|
220
246
|
For prospector options which affect display only - those which are not configurable using a profile - these can be
|
|
221
247
|
added as command line arguments to the hook. For example::
|
|
222
248
|
|
|
223
249
|
repos:
|
|
224
250
|
- repo: https://github.com/PyCQA/prospector
|
|
225
|
-
rev: 1.
|
|
251
|
+
rev: 1.10.0
|
|
226
252
|
hooks:
|
|
227
253
|
- id: prospector
|
|
228
|
-
|
|
254
|
+
additional_dependencies:
|
|
229
255
|
- ".[with_mypy,with_bandit]"
|
|
230
256
|
args:
|
|
257
|
+
- --with-tool=mypy
|
|
258
|
+
- --with-tool=bandit
|
|
231
259
|
- --summary-only
|
|
232
260
|
- --zero-exit
|
|
233
261
|
|
|
262
|
+
|
|
263
|
+
|
|
234
264
|
License
|
|
235
265
|
-------
|
|
236
266
|
|
|
@@ -4,8 +4,8 @@ prospector
|
|
|
4
4
|
.. image:: https://img.shields.io/pypi/v/prospector.svg
|
|
5
5
|
:target: https://pypi.python.org/pypi/prospector
|
|
6
6
|
:alt: Latest Version of Prospector
|
|
7
|
-
.. image:: https://
|
|
8
|
-
:target: https://
|
|
7
|
+
.. image:: https://github.com/PyCQA/prospector/actions/workflows/tests.yml/badge.svg
|
|
8
|
+
:target: https://github.com/PyCQA/prospector/actions/workflows/tests.yml
|
|
9
9
|
:alt: Build Status
|
|
10
10
|
.. image:: https://img.shields.io/coveralls/PyCQA/prospector.svg?style=flat
|
|
11
11
|
:target: https://coveralls.io/r/PyCQA/prospector
|
|
@@ -148,35 +148,60 @@ text to your repositories' ``.pre-commit-config.yaml``::
|
|
|
148
148
|
|
|
149
149
|
repos:
|
|
150
150
|
- repo: https://github.com/PyCQA/prospector
|
|
151
|
-
rev: 1.
|
|
151
|
+
rev: 1.10.0 # The version of Prospector to use, if not 'master' for latest
|
|
152
152
|
hooks:
|
|
153
153
|
- id: prospector
|
|
154
154
|
|
|
155
|
-
This only installs base prospector - if you also use optional tools, for example bandit or mypy, then you can add
|
|
155
|
+
This only installs base prospector - if you also use optional tools, for example bandit and/or mypy, then you can add
|
|
156
156
|
them to the hook configuration like so::
|
|
157
157
|
|
|
158
158
|
repos:
|
|
159
159
|
- repo: https://github.com/PyCQA/prospector
|
|
160
|
-
rev: 1.
|
|
160
|
+
rev: 1.10.0
|
|
161
161
|
hooks:
|
|
162
162
|
- id: prospector
|
|
163
|
-
|
|
163
|
+
additional_dependencies:
|
|
164
164
|
- ".[with_mypy,with_bandit]"
|
|
165
|
+
- args: [
|
|
166
|
+
'--with-tool=mypy',
|
|
167
|
+
'--with-tool=bandit',
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
Additional dependencies can be `individually configured <https://prospector.landscape.io/en/master/profiles.html#individual-configuration-options>`_ in your `prospector.yml` file ::
|
|
171
|
+
|
|
172
|
+
# https://bandit.readthedocs.io/en/latest/config.html
|
|
173
|
+
bandit:
|
|
174
|
+
options:
|
|
175
|
+
skips:
|
|
176
|
+
- B201
|
|
177
|
+
- B601
|
|
178
|
+
- B610
|
|
179
|
+
- B611
|
|
180
|
+
- B703
|
|
181
|
+
|
|
182
|
+
# https://mypy.readthedocs.io/en/stable/command_line.html
|
|
183
|
+
mypy:
|
|
184
|
+
options:
|
|
185
|
+
ignore-missing-imports: true
|
|
165
186
|
|
|
166
187
|
For prospector options which affect display only - those which are not configurable using a profile - these can be
|
|
167
188
|
added as command line arguments to the hook. For example::
|
|
168
189
|
|
|
169
190
|
repos:
|
|
170
191
|
- repo: https://github.com/PyCQA/prospector
|
|
171
|
-
rev: 1.
|
|
192
|
+
rev: 1.10.0
|
|
172
193
|
hooks:
|
|
173
194
|
- id: prospector
|
|
174
|
-
|
|
195
|
+
additional_dependencies:
|
|
175
196
|
- ".[with_mypy,with_bandit]"
|
|
176
197
|
args:
|
|
198
|
+
- --with-tool=mypy
|
|
199
|
+
- --with-tool=bandit
|
|
177
200
|
- --summary-only
|
|
178
201
|
- --zero-exit
|
|
179
202
|
|
|
203
|
+
|
|
204
|
+
|
|
180
205
|
License
|
|
181
206
|
-------
|
|
182
207
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import re
|
|
3
3
|
import warnings
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Union
|
|
4
6
|
|
|
5
7
|
from requirements_detector import find_requirements
|
|
6
8
|
from requirements_detector.detect import RequirementsNotFound
|
|
@@ -18,7 +20,7 @@ _IMPORT_REGEX = re.compile(r"^\s*import ([\._a-zA-Z0-9]+)$")
|
|
|
18
20
|
_IMPORT_MULTIPLE_REGEX = re.compile(r"^\s*import ([\._a-zA-Z0-9]+(, ){1})+")
|
|
19
21
|
|
|
20
22
|
|
|
21
|
-
def find_from_imports(file_contents):
|
|
23
|
+
def find_from_imports(file_contents: str) -> set[str]:
|
|
22
24
|
names = set()
|
|
23
25
|
for line in file_contents.split("\n"):
|
|
24
26
|
match = _IMPORT_MULTIPLE_REGEX.match(line)
|
|
@@ -41,52 +43,48 @@ def find_from_imports(file_contents):
|
|
|
41
43
|
return names
|
|
42
44
|
|
|
43
45
|
|
|
44
|
-
def find_from_path(path):
|
|
46
|
+
def find_from_path(path: Path) -> set[str]:
|
|
45
47
|
names = set()
|
|
46
48
|
|
|
47
49
|
try:
|
|
48
|
-
|
|
50
|
+
for item in path.iterdir():
|
|
51
|
+
if item.is_dir():
|
|
52
|
+
if is_virtualenv(item):
|
|
53
|
+
continue
|
|
54
|
+
names |= find_from_path(item)
|
|
55
|
+
elif not item.is_symlink() and item.suffix == ".py":
|
|
56
|
+
try:
|
|
57
|
+
contents = encoding.read_py_file(item)
|
|
58
|
+
names |= find_from_imports(contents)
|
|
59
|
+
except encoding.CouldNotHandleEncoding as err:
|
|
60
|
+
# TODO: this output will break output formats such as JSON
|
|
61
|
+
warnings.warn(f"{err.path}: {err.__cause__}", ImportWarning, stacklevel=0)
|
|
62
|
+
|
|
63
|
+
if len(names) == len(POSSIBLE_LIBRARIES):
|
|
64
|
+
# don't continue on recursing, there's no point!
|
|
65
|
+
break
|
|
49
66
|
except PermissionError as err:
|
|
50
67
|
raise PermissionMissing(path) from err
|
|
51
68
|
|
|
52
|
-
for item in dirlist:
|
|
53
|
-
item_path = os.path.abspath(os.path.join(path, item))
|
|
54
|
-
if os.path.isdir(item_path):
|
|
55
|
-
if is_virtualenv(item_path):
|
|
56
|
-
continue
|
|
57
|
-
names |= find_from_path(item_path)
|
|
58
|
-
elif not os.path.islink(item_path) and item_path.endswith(".py"):
|
|
59
|
-
try:
|
|
60
|
-
contents = encoding.read_py_file(item_path)
|
|
61
|
-
names |= find_from_imports(contents)
|
|
62
|
-
except encoding.CouldNotHandleEncoding as err:
|
|
63
|
-
# TODO: this output will break output formats such as JSON
|
|
64
|
-
warnings.warn("{0}: {1}".format(err.path, err.cause), ImportWarning)
|
|
65
|
-
|
|
66
|
-
if len(names) == len(POSSIBLE_LIBRARIES):
|
|
67
|
-
# don't continue on recursing, there's no point!
|
|
68
|
-
break
|
|
69
|
-
|
|
70
69
|
return names
|
|
71
70
|
|
|
72
71
|
|
|
73
|
-
def find_from_requirements(path):
|
|
72
|
+
def find_from_requirements(path: Union[str, Path]) -> set[str]:
|
|
74
73
|
reqs = find_requirements(path)
|
|
75
|
-
names =
|
|
74
|
+
names: set[str] = set()
|
|
76
75
|
for requirement in reqs:
|
|
77
76
|
if requirement.name is not None and requirement.name.lower() in POSSIBLE_LIBRARIES:
|
|
78
|
-
names.
|
|
77
|
+
names.add(requirement.name.lower())
|
|
79
78
|
return names
|
|
80
79
|
|
|
81
80
|
|
|
82
|
-
def autodetect_libraries(path):
|
|
83
|
-
|
|
81
|
+
def autodetect_libraries(path: Union[str, Path]) -> set[str]:
|
|
84
82
|
if os.path.isfile(path):
|
|
85
83
|
path = os.path.dirname(path)
|
|
86
84
|
if path == "":
|
|
87
85
|
path = "."
|
|
88
86
|
|
|
89
|
-
libraries =
|
|
87
|
+
libraries: set[str] = set()
|
|
90
88
|
|
|
91
89
|
try:
|
|
92
90
|
libraries = find_from_requirements(path)
|
|
@@ -94,6 +92,6 @@ def autodetect_libraries(path):
|
|
|
94
92
|
pass
|
|
95
93
|
|
|
96
94
|
if len(libraries) < len(POSSIBLE_LIBRARIES):
|
|
97
|
-
libraries = find_from_path(path)
|
|
95
|
+
libraries = find_from_path(Path(path))
|
|
98
96
|
|
|
99
97
|
return libraries
|
|
@@ -4,18 +4,22 @@
|
|
|
4
4
|
# the same line. For example, both pyflakes and pylint will generate an
|
|
5
5
|
# "Unused Import" warning on the same line. This is obviously redundant, so we
|
|
6
6
|
# remove duplicates.
|
|
7
|
+
import pkgutil
|
|
7
8
|
from collections import defaultdict
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional
|
|
8
11
|
|
|
9
|
-
import pkg_resources
|
|
10
12
|
import yaml
|
|
11
13
|
|
|
14
|
+
from prospector.message import Message
|
|
15
|
+
|
|
12
16
|
__all__ = (
|
|
13
17
|
"blend",
|
|
14
18
|
"BLEND_COMBOS",
|
|
15
19
|
)
|
|
16
20
|
|
|
17
21
|
|
|
18
|
-
def blend_line(messages, blend_combos=None):
|
|
22
|
+
def blend_line(messages: list[Message], blend_combos: Optional[list[list[tuple[str, str]]]] = None) -> list[Message]:
|
|
19
23
|
"""
|
|
20
24
|
Given a list of messages on the same line, blend them together so that we
|
|
21
25
|
end up with one message per actual problem. Note that we can still return
|
|
@@ -23,8 +27,8 @@ def blend_line(messages, blend_combos=None):
|
|
|
23
27
|
the line.
|
|
24
28
|
"""
|
|
25
29
|
blend_combos = blend_combos or BLEND_COMBOS
|
|
26
|
-
blend_lists = [[] for _ in range(len(blend_combos))]
|
|
27
|
-
blended = []
|
|
30
|
+
blend_lists: list[list[Message]] = [[] for _ in range(len(blend_combos))]
|
|
31
|
+
blended: list[Message] = []
|
|
28
32
|
|
|
29
33
|
# first we split messages into each of the possible blendable categories
|
|
30
34
|
# so that we have a list of lists of messages which can be blended together
|
|
@@ -52,6 +56,7 @@ def blend_line(messages, blend_combos=None):
|
|
|
52
56
|
for blend_combo_idx, blend_list in enumerate(blend_lists):
|
|
53
57
|
if len(blend_list) == 0:
|
|
54
58
|
continue
|
|
59
|
+
# pylint:disable=cell-var-from-loop
|
|
55
60
|
blend_list.sort(
|
|
56
61
|
key=lambda msg: blend_combos[blend_combo_idx].index(
|
|
57
62
|
(msg.source, msg.code),
|
|
@@ -71,16 +76,16 @@ def blend_line(messages, blend_combos=None):
|
|
|
71
76
|
# it will appear in two blend_lists. Therefore we mark anything not taken from the blend list
|
|
72
77
|
# as "consumed" and then filter later, to avoid such cases.
|
|
73
78
|
for now_used in blend_list[1:]:
|
|
74
|
-
now_used.used = True
|
|
79
|
+
now_used.used = True # type: ignore[attr-defined]
|
|
75
80
|
|
|
76
81
|
return [m for m in blended if not getattr(m, "used", False)]
|
|
77
82
|
|
|
78
83
|
|
|
79
|
-
def blend(messages, blend_combos=None):
|
|
84
|
+
def blend(messages: list[Message], blend_combos: Optional[list[list[tuple[str, str]]]] = None) -> list[Message]:
|
|
80
85
|
blend_combos = blend_combos or BLEND_COMBOS
|
|
81
86
|
|
|
82
87
|
# group messages by file and then line number
|
|
83
|
-
msgs_grouped = defaultdict(lambda: defaultdict(list))
|
|
88
|
+
msgs_grouped: dict[Optional[Path], dict[Optional[int], list[Message]]] = defaultdict(lambda: defaultdict(list))
|
|
84
89
|
|
|
85
90
|
for message in messages:
|
|
86
91
|
msgs_grouped[message.location.path][message.location.line].append(
|
|
@@ -96,18 +101,20 @@ def blend(messages, blend_combos=None):
|
|
|
96
101
|
return out
|
|
97
102
|
|
|
98
103
|
|
|
99
|
-
def get_default_blend_combinations():
|
|
100
|
-
|
|
104
|
+
def get_default_blend_combinations() -> list[list[tuple[str, str]]]:
|
|
105
|
+
blender_combinations = pkgutil.get_data(__name__, "blender_combinations.yaml")
|
|
106
|
+
assert blender_combinations is not None
|
|
107
|
+
combos = yaml.safe_load(blender_combinations)
|
|
101
108
|
combos = combos.get("combinations", [])
|
|
102
109
|
|
|
103
|
-
defaults = []
|
|
110
|
+
defaults: list[list[tuple[str, str]]] = []
|
|
104
111
|
for combo in combos:
|
|
105
112
|
toblend = []
|
|
106
113
|
for msg in combo:
|
|
107
114
|
toblend += msg.items()
|
|
108
|
-
defaults.append(
|
|
115
|
+
defaults.append(toblend)
|
|
109
116
|
|
|
110
|
-
return
|
|
117
|
+
return defaults
|
|
111
118
|
|
|
112
119
|
|
|
113
120
|
BLEND_COMBOS = get_default_blend_combinations()
|