prospector 1.7.1__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.
Files changed (89) hide show
  1. {prospector-1.7.1 → prospector-1.14.0}/PKG-INFO +81 -29
  2. {prospector-1.7.1 → prospector-1.14.0}/README.rst +60 -13
  3. {prospector-1.7.1 → prospector-1.14.0}/prospector/__main__.py +1 -3
  4. {prospector-1.7.1 → prospector-1.14.0}/prospector/autodetect.py +30 -29
  5. {prospector-1.7.1 → prospector-1.14.0}/prospector/blender.py +19 -12
  6. prospector-1.14.0/prospector/blender_combinations.yaml +287 -0
  7. prospector-1.14.0/prospector/compat.py +14 -0
  8. {prospector-1.7.1 → prospector-1.14.0}/prospector/config/__init__.py +110 -62
  9. {prospector-1.7.1 → prospector-1.14.0}/prospector/config/configuration.py +20 -15
  10. {prospector-1.7.1 → prospector-1.14.0}/prospector/config/datatype.py +3 -3
  11. prospector-1.14.0/prospector/encoding.py +36 -0
  12. prospector-1.14.0/prospector/exceptions.py +36 -0
  13. prospector-1.14.0/prospector/finder.py +132 -0
  14. {prospector-1.7.1 → prospector-1.14.0}/prospector/formatters/__init__.py +5 -3
  15. prospector-1.14.0/prospector/formatters/base.py +56 -0
  16. prospector-1.14.0/prospector/formatters/base_summary.py +43 -0
  17. {prospector-1.7.1 → prospector-1.14.0}/prospector/formatters/emacs.py +5 -10
  18. {prospector-1.7.1 → prospector-1.14.0}/prospector/formatters/grouped.py +9 -8
  19. {prospector-1.7.1 → prospector-1.14.0}/prospector/formatters/json.py +4 -7
  20. prospector-1.14.0/prospector/formatters/pylint.py +80 -0
  21. prospector-1.14.0/prospector/formatters/pylint_parseable.py +74 -0
  22. prospector-1.14.0/prospector/formatters/text.py +52 -0
  23. {prospector-1.7.1 → prospector-1.14.0}/prospector/formatters/vscode.py +17 -8
  24. {prospector-1.7.1 → prospector-1.14.0}/prospector/formatters/xunit.py +6 -7
  25. {prospector-1.7.1 → prospector-1.14.0}/prospector/formatters/yaml.py +5 -4
  26. prospector-1.14.0/prospector/message.py +119 -0
  27. prospector-1.14.0/prospector/pathutils.py +37 -0
  28. {prospector-1.7.1 → prospector-1.14.0}/prospector/postfilter.py +16 -11
  29. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/__init__.py +2 -2
  30. prospector-1.14.0/prospector/profiles/exceptions.py +31 -0
  31. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profile.py +184 -112
  32. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/no_doc_warnings.yaml +3 -0
  33. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/no_test_warnings.yaml +1 -0
  34. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/strictness_high.yaml +7 -0
  35. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/strictness_medium.yaml +4 -0
  36. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/strictness_veryhigh.yaml +4 -0
  37. {prospector-1.7.1 → prospector-1.14.0}/prospector/run.py +62 -75
  38. prospector-1.14.0/prospector/suppression.py +157 -0
  39. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/__init__.py +32 -12
  40. prospector-1.14.0/prospector/tools/bandit/__init__.py +81 -0
  41. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/base.py +13 -2
  42. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/dodgy/__init__.py +14 -20
  43. prospector-1.14.0/prospector/tools/exceptions.py +3 -0
  44. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/mccabe/__init__.py +16 -18
  45. prospector-1.14.0/prospector/tools/mypy/__init__.py +107 -0
  46. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/profile_validator/__init__.py +87 -48
  47. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/pycodestyle/__init__.py +38 -48
  48. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/pydocstyle/__init__.py +18 -20
  49. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/pyflakes/__init__.py +36 -21
  50. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/pylint/__init__.py +97 -77
  51. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/pylint/collector.py +16 -17
  52. prospector-1.14.0/prospector/tools/pylint/linter.py +45 -0
  53. prospector-1.14.0/prospector/tools/pyright/__init__.py +99 -0
  54. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/pyroma/__init__.py +32 -21
  55. prospector-1.14.0/prospector/tools/ruff/__init__.py +86 -0
  56. prospector-1.14.0/prospector/tools/utils.py +59 -0
  57. {prospector-1.7.1 → prospector-1.14.0}/prospector/tools/vulture/__init__.py +26 -16
  58. prospector-1.14.0/pyproject.toml +110 -0
  59. prospector-1.14.0/setup.py +81 -0
  60. prospector-1.7.1/prospector/blender_combinations.yaml +0 -254
  61. prospector-1.7.1/prospector/encoding.py +0 -33
  62. prospector-1.7.1/prospector/exceptions.py +0 -14
  63. prospector-1.7.1/prospector/finder.py +0 -212
  64. prospector-1.7.1/prospector/formatters/base.py +0 -14
  65. prospector-1.7.1/prospector/formatters/pylint.py +0 -45
  66. prospector-1.7.1/prospector/formatters/text.py +0 -101
  67. prospector-1.7.1/prospector/message.py +0 -113
  68. prospector-1.7.1/prospector/pathutils.py +0 -33
  69. prospector-1.7.1/prospector/suppression.py +0 -118
  70. prospector-1.7.1/prospector/tools/bandit/__init__.py +0 -62
  71. prospector-1.7.1/prospector/tools/frosted/__init__.py +0 -82
  72. prospector-1.7.1/prospector/tools/mypy/__init__.py +0 -97
  73. prospector-1.7.1/prospector/tools/pylint/linter.py +0 -26
  74. prospector-1.7.1/prospector/tools/utils.py +0 -45
  75. prospector-1.7.1/pyproject.toml +0 -97
  76. prospector-1.7.1/setup.py +0 -77
  77. {prospector-1.7.1 → prospector-1.14.0}/LICENSE +0 -0
  78. {prospector-1.7.1 → prospector-1.14.0}/prospector/__init__.py +0 -0
  79. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/default.yaml +0 -0
  80. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/doc_warnings.yaml +0 -0
  81. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/flake8.yaml +0 -0
  82. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/full_pep8.yaml +0 -0
  83. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/member_warnings.yaml +0 -0
  84. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/no_member_warnings.yaml +0 -0
  85. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/no_pep8.yaml +0 -0
  86. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/strictness_low.yaml +0 -0
  87. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/strictness_none.yaml +0 -0
  88. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/strictness_verylow.yaml +0 -0
  89. {prospector-1.7.1 → prospector-1.14.0}/prospector/profiles/profiles/test_warnings.yaml +0 -0
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prospector
3
- Version: 1.7.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.6.2,<4.0
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.6
22
- Classifier: Programming Language :: Python :: 3.7
23
- Classifier: Programming Language :: Python :: 3.8
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: frosted (>=1.4.1); extra == "with_frosted" or extra == "with_everything"
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.6.0,<2.9.0)
43
+ Requires-Dist: pycodestyle (>=2.9.0)
40
44
  Requires-Dist: pydocstyle (>=2.0.0)
41
- Requires-Dist: pyflakes (>=2.2.0,<3)
42
- Requires-Dist: pylint (>=2.8.3)
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.5,<2.6)
48
+ Requires-Dist: pylint-django (>=2.6.1)
45
49
  Requires-Dist: pylint-flask (==0.6)
46
- Requires-Dist: pylint-plugin-utils (>=0.7,<0.8)
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 (>=0.7,<0.8)
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,17 +63,14 @@ 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://travis-ci.org/PyCQA/prospector.svg?branch=master
62
- :target: https://travis-ci.org/PyCQA/prospector
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
- .. image:: https://landscape.io/github/landscapeio/prospector/master/landscape.svg?style=flat
65
- :target: https://landscape.io/github/landscapeio/prospector/master
66
- :alt: Code Health
67
69
  .. image:: https://img.shields.io/coveralls/PyCQA/prospector.svg?style=flat
68
70
  :target: https://coveralls.io/r/PyCQA/prospector
69
71
  :alt: Test Coverage
70
72
  .. image:: https://readthedocs.org/projects/prospector/badge/?version=latest
71
- :target: http://prospector.readthedocs.io/
73
+ :target: https://prospector.readthedocs.io/
72
74
  :alt: Documentation
73
75
 
74
76
 
@@ -79,10 +81,10 @@ Prospector is a tool to analyse Python code and output information about
79
81
  errors, potential problems, convention violations and complexity.
80
82
 
81
83
  It brings together the functionality of other Python analysis tools such as
82
- `Pylint <http://docs.pylint.org/>`_,
83
- `pep8 <http://pep8.readthedocs.org/en/latest/>`_,
84
+ `Pylint <https://docs.pylint.org/>`_,
85
+ `pycodestyle <https://pycodestyle.pycqa.org/>`_,
84
86
  and `McCabe complexity <https://pypi.python.org/pypi/mccabe>`_.
85
- See the `Supported Tools <http://prospector.readthedocs.io/en/latest/supported_tools.html>`_
87
+ See the `Supported Tools <https://prospector.readthedocs.io/en/latest/supported_tools.html>`_
86
88
  documentation section for a complete list.
87
89
 
88
90
  The primary aim of Prospector is to be useful 'out of the box'. A common complaint of other
@@ -118,13 +120,13 @@ And for extras::
118
120
  poetry install -E with_everything
119
121
 
120
122
  For more detailed information on installing the tool, see the
121
- `installation section <http://prospector.readthedocs.io/en/latest/#installation>`_ of the tool's main page
123
+ `installation section <https://prospector.readthedocs.io/en/latest/#installation>`_ of the tool's main page
122
124
  on ReadTheDocs.
123
125
 
124
126
  Documentation
125
127
  -------------
126
128
 
127
- Full `documentation is available at ReadTheDocs <http://prospector.readthedocs.io>`_.
129
+ Full `documentation is available at ReadTheDocs <https://prospector.readthedocs.io>`_.
128
130
 
129
131
  Usage
130
132
  -----
@@ -156,7 +158,7 @@ Profiles
156
158
 
157
159
  Prospector is configurable using "profiles". These are composable YAML files with directives to
158
160
  disable or enable tools or messages. For more information, read
159
- `the documentation about profiles <http://prospector.readthedocs.io/en/latest/profiles.html>`_.
161
+ `the documentation about profiles <https://prospector.readthedocs.io/en/latest/profiles.html>`_.
160
162
 
161
163
  If your code uses frameworks and libraries
162
164
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -205,9 +207,59 @@ text to your repositories' ``.pre-commit-config.yaml``::
205
207
 
206
208
  repos:
207
209
  - repo: https://github.com/PyCQA/prospector
208
- rev: 1.5.3.1 # The version of Prospector to use, if not 'master' for latest
210
+ rev: 1.10.0 # The version of Prospector to use, if not 'master' for latest
211
+ hooks:
212
+ - id: prospector
213
+
214
+ This only installs base prospector - if you also use optional tools, for example bandit and/or mypy, then you can add
215
+ them to the hook configuration like so::
216
+
217
+ repos:
218
+ - repo: https://github.com/PyCQA/prospector
219
+ rev: 1.10.0
209
220
  hooks:
210
221
  - id: prospector
222
+ additional_dependencies:
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
245
+
246
+ For prospector options which affect display only - those which are not configurable using a profile - these can be
247
+ added as command line arguments to the hook. For example::
248
+
249
+ repos:
250
+ - repo: https://github.com/PyCQA/prospector
251
+ rev: 1.10.0
252
+ hooks:
253
+ - id: prospector
254
+ additional_dependencies:
255
+ - ".[with_mypy,with_bandit]"
256
+ args:
257
+ - --with-tool=mypy
258
+ - --with-tool=bandit
259
+ - --summary-only
260
+ - --zero-exit
261
+
262
+
211
263
 
212
264
  License
213
265
  -------
@@ -4,17 +4,14 @@ 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://travis-ci.org/PyCQA/prospector.svg?branch=master
8
- :target: https://travis-ci.org/PyCQA/prospector
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
- .. image:: https://landscape.io/github/landscapeio/prospector/master/landscape.svg?style=flat
11
- :target: https://landscape.io/github/landscapeio/prospector/master
12
- :alt: Code Health
13
10
  .. image:: https://img.shields.io/coveralls/PyCQA/prospector.svg?style=flat
14
11
  :target: https://coveralls.io/r/PyCQA/prospector
15
12
  :alt: Test Coverage
16
13
  .. image:: https://readthedocs.org/projects/prospector/badge/?version=latest
17
- :target: http://prospector.readthedocs.io/
14
+ :target: https://prospector.readthedocs.io/
18
15
  :alt: Documentation
19
16
 
20
17
 
@@ -25,10 +22,10 @@ Prospector is a tool to analyse Python code and output information about
25
22
  errors, potential problems, convention violations and complexity.
26
23
 
27
24
  It brings together the functionality of other Python analysis tools such as
28
- `Pylint <http://docs.pylint.org/>`_,
29
- `pep8 <http://pep8.readthedocs.org/en/latest/>`_,
25
+ `Pylint <https://docs.pylint.org/>`_,
26
+ `pycodestyle <https://pycodestyle.pycqa.org/>`_,
30
27
  and `McCabe complexity <https://pypi.python.org/pypi/mccabe>`_.
31
- See the `Supported Tools <http://prospector.readthedocs.io/en/latest/supported_tools.html>`_
28
+ See the `Supported Tools <https://prospector.readthedocs.io/en/latest/supported_tools.html>`_
32
29
  documentation section for a complete list.
33
30
 
34
31
  The primary aim of Prospector is to be useful 'out of the box'. A common complaint of other
@@ -64,13 +61,13 @@ And for extras::
64
61
  poetry install -E with_everything
65
62
 
66
63
  For more detailed information on installing the tool, see the
67
- `installation section <http://prospector.readthedocs.io/en/latest/#installation>`_ of the tool's main page
64
+ `installation section <https://prospector.readthedocs.io/en/latest/#installation>`_ of the tool's main page
68
65
  on ReadTheDocs.
69
66
 
70
67
  Documentation
71
68
  -------------
72
69
 
73
- Full `documentation is available at ReadTheDocs <http://prospector.readthedocs.io>`_.
70
+ Full `documentation is available at ReadTheDocs <https://prospector.readthedocs.io>`_.
74
71
 
75
72
  Usage
76
73
  -----
@@ -102,7 +99,7 @@ Profiles
102
99
 
103
100
  Prospector is configurable using "profiles". These are composable YAML files with directives to
104
101
  disable or enable tools or messages. For more information, read
105
- `the documentation about profiles <http://prospector.readthedocs.io/en/latest/profiles.html>`_.
102
+ `the documentation about profiles <https://prospector.readthedocs.io/en/latest/profiles.html>`_.
106
103
 
107
104
  If your code uses frameworks and libraries
108
105
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -151,10 +148,60 @@ text to your repositories' ``.pre-commit-config.yaml``::
151
148
 
152
149
  repos:
153
150
  - repo: https://github.com/PyCQA/prospector
154
- rev: 1.5.3.1 # The version of Prospector to use, if not 'master' for latest
151
+ rev: 1.10.0 # The version of Prospector to use, if not 'master' for latest
155
152
  hooks:
156
153
  - id: prospector
157
154
 
155
+ This only installs base prospector - if you also use optional tools, for example bandit and/or mypy, then you can add
156
+ them to the hook configuration like so::
157
+
158
+ repos:
159
+ - repo: https://github.com/PyCQA/prospector
160
+ rev: 1.10.0
161
+ hooks:
162
+ - id: prospector
163
+ additional_dependencies:
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
186
+
187
+ For prospector options which affect display only - those which are not configurable using a profile - these can be
188
+ added as command line arguments to the hook. For example::
189
+
190
+ repos:
191
+ - repo: https://github.com/PyCQA/prospector
192
+ rev: 1.10.0
193
+ hooks:
194
+ - id: prospector
195
+ additional_dependencies:
196
+ - ".[with_mypy,with_bandit]"
197
+ args:
198
+ - --with-tool=mypy
199
+ - --with-tool=bandit
200
+ - --summary-only
201
+ - --zero-exit
202
+
203
+
204
+
158
205
  License
159
206
  -------
160
207
 
@@ -1,6 +1,4 @@
1
- import sys
2
-
3
1
  from prospector.run import main
4
2
 
5
3
  if __name__ == "__main__":
6
- sys.exit(main())
4
+ main()
@@ -1,11 +1,14 @@
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
7
9
 
8
10
  from prospector import encoding
11
+ from prospector.exceptions import PermissionMissing
9
12
  from prospector.pathutils import is_virtualenv
10
13
 
11
14
  POSSIBLE_LIBRARIES = ("django", "celery", "flask")
@@ -17,7 +20,7 @@ _IMPORT_REGEX = re.compile(r"^\s*import ([\._a-zA-Z0-9]+)$")
17
20
  _IMPORT_MULTIPLE_REGEX = re.compile(r"^\s*import ([\._a-zA-Z0-9]+(, ){1})+")
18
21
 
19
22
 
20
- def find_from_imports(file_contents):
23
+ def find_from_imports(file_contents: str) -> set[str]:
21
24
  names = set()
22
25
  for line in file_contents.split("\n"):
23
26
  match = _IMPORT_MULTIPLE_REGEX.match(line)
@@ -40,57 +43,55 @@ def find_from_imports(file_contents):
40
43
  return names
41
44
 
42
45
 
43
- def find_from_path(path):
46
+ def find_from_path(path: Path) -> set[str]:
44
47
  names = set()
45
- max_possible = len(POSSIBLE_LIBRARIES)
46
48
 
47
- for item in os.listdir(path):
48
- item_path = os.path.abspath(os.path.join(path, item))
49
- if os.path.isdir(item_path):
50
- if is_virtualenv(item_path):
51
- continue
52
- names |= find_from_path(item_path)
53
- elif not os.path.islink(item_path) and item_path.endswith(".py"):
54
- try:
55
- contents = encoding.read_py_file(item_path)
56
- names |= find_from_imports(contents)
57
- except encoding.CouldNotHandleEncoding as err:
58
- # TODO: this output will break output formats such as JSON
59
- warnings.warn("{0}: {1}".format(err.path, err.cause), ImportWarning)
60
-
61
- if len(names) == max_possible:
62
- # don't continue on recursing, there's no point!
63
- break
49
+ try:
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
66
+ except PermissionError as err:
67
+ raise PermissionMissing(path) from err
64
68
 
65
69
  return names
66
70
 
67
71
 
68
- def find_from_requirements(path):
72
+ def find_from_requirements(path: Union[str, Path]) -> set[str]:
69
73
  reqs = find_requirements(path)
70
- names = []
74
+ names: set[str] = set()
71
75
  for requirement in reqs:
72
76
  if requirement.name is not None and requirement.name.lower() in POSSIBLE_LIBRARIES:
73
- names.append(requirement.name.lower())
77
+ names.add(requirement.name.lower())
74
78
  return names
75
79
 
76
80
 
77
- def autodetect_libraries(path):
78
-
81
+ def autodetect_libraries(path: Union[str, Path]) -> set[str]:
79
82
  if os.path.isfile(path):
80
83
  path = os.path.dirname(path)
81
84
  if path == "":
82
85
  path = "."
83
86
 
84
- libraries = []
87
+ libraries: set[str] = set()
85
88
 
86
89
  try:
87
90
  libraries = find_from_requirements(path)
88
-
89
- # pylint: disable=pointless-except
90
91
  except RequirementsNotFound:
91
92
  pass
92
93
 
93
94
  if len(libraries) < len(POSSIBLE_LIBRARIES):
94
- libraries = find_from_path(path)
95
+ libraries = find_from_path(Path(path))
95
96
 
96
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
- combos = yaml.safe_load(pkg_resources.resource_string(__name__, "blender_combinations.yaml"))
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(tuple(toblend))
115
+ defaults.append(toblend)
109
116
 
110
- return tuple(defaults)
117
+ return defaults
111
118
 
112
119
 
113
120
  BLEND_COMBOS = get_default_blend_combinations()