prospector 1.10.0__py3-none-any.whl → 1.13.2__py3-none-any.whl
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/autodetect.py +10 -9
- prospector/blender.py +18 -12
- prospector/config/__init__.py +66 -49
- prospector/config/configuration.py +17 -14
- prospector/config/datatype.py +1 -1
- prospector/encoding.py +2 -2
- prospector/exceptions.py +1 -6
- prospector/finder.py +9 -8
- prospector/formatters/__init__.py +1 -1
- prospector/formatters/base.py +17 -11
- prospector/formatters/base_summary.py +43 -0
- prospector/formatters/emacs.py +5 -5
- prospector/formatters/grouped.py +9 -7
- prospector/formatters/json.py +3 -2
- prospector/formatters/pylint.py +41 -9
- prospector/formatters/text.py +10 -58
- prospector/formatters/vscode.py +17 -7
- prospector/formatters/xunit.py +6 -7
- prospector/formatters/yaml.py +4 -2
- prospector/message.py +32 -14
- prospector/pathutils.py +3 -10
- prospector/postfilter.py +9 -8
- prospector/profiles/exceptions.py +14 -11
- prospector/profiles/profile.py +70 -59
- prospector/run.py +20 -18
- prospector/suppression.py +19 -13
- prospector/tools/__init__.py +19 -13
- prospector/tools/bandit/__init__.py +27 -15
- prospector/tools/base.py +11 -3
- prospector/tools/dodgy/__init__.py +7 -3
- prospector/tools/mccabe/__init__.py +13 -6
- prospector/tools/mypy/__init__.py +44 -76
- prospector/tools/profile_validator/__init__.py +24 -15
- prospector/tools/pycodestyle/__init__.py +22 -15
- prospector/tools/pydocstyle/__init__.py +12 -6
- prospector/tools/pyflakes/__init__.py +35 -19
- prospector/tools/pylint/__init__.py +57 -31
- prospector/tools/pylint/collector.py +3 -5
- prospector/tools/pylint/linter.py +19 -14
- prospector/tools/pyright/__init__.py +18 -7
- prospector/tools/pyroma/__init__.py +10 -6
- prospector/tools/ruff/__init__.py +84 -0
- prospector/tools/utils.py +25 -19
- prospector/tools/vulture/__init__.py +25 -15
- {prospector-1.10.0.dist-info → prospector-1.13.2.dist-info}/METADATA +13 -14
- prospector-1.13.2.dist-info/RECORD +71 -0
- README.rst +0 -208
- prospector-1.10.0.dist-info/LICENSE +0 -339
- prospector-1.10.0.dist-info/RECORD +0 -71
- /LICENSE → /prospector-1.13.2.dist-info/LICENSE +0 -0
- {prospector-1.10.0.dist-info → prospector-1.13.2.dist-info}/WHEEL +0 -0
- {prospector-1.10.0.dist-info → prospector-1.13.2.dist-info}/entry_points.txt +0 -0
|
@@ -1,49 +1,61 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
2
|
+
|
|
1
3
|
from bandit.cli.main import _get_profile, _init_extensions
|
|
2
4
|
from bandit.core.config import BanditConfig
|
|
3
5
|
from bandit.core.constants import RANKING
|
|
4
6
|
from bandit.core.manager import BanditManager
|
|
5
7
|
|
|
8
|
+
from prospector.finder import FileFinder
|
|
6
9
|
from prospector.message import Location, Message
|
|
7
10
|
from prospector.tools.base import ToolBase
|
|
8
11
|
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from prospector.config import ProspectorConfig
|
|
14
|
+
|
|
9
15
|
|
|
10
16
|
class BanditTool(ToolBase):
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def configure(self, prospector_config, _):
|
|
17
|
+
manager: Optional[BanditManager] = None
|
|
18
|
+
profile: Optional[str] = None
|
|
19
|
+
config_file: Optional[str] = None
|
|
20
|
+
agg_type = "file"
|
|
21
|
+
severity = 0
|
|
22
|
+
confidence = 0
|
|
23
|
+
|
|
24
|
+
def configure(self, prospector_config: "ProspectorConfig", _: Any) -> None:
|
|
21
25
|
options = prospector_config.tool_options("bandit")
|
|
22
26
|
|
|
23
27
|
if "profile" in options:
|
|
24
|
-
self.profile = options
|
|
28
|
+
self.profile = options.pop("profile")
|
|
25
29
|
|
|
26
30
|
if "config" in options:
|
|
27
|
-
self.config_file = options
|
|
31
|
+
self.config_file = options.pop("config")
|
|
28
32
|
|
|
29
33
|
if "severity" in options:
|
|
30
|
-
self.severity = options
|
|
34
|
+
self.severity = options.pop("severity")
|
|
31
35
|
if not 0 <= self.severity <= 2:
|
|
32
36
|
raise ValueError(f"severity {self.severity!r} must be between 0 and 2")
|
|
33
37
|
|
|
34
38
|
if "confidence" in options:
|
|
35
|
-
self.confidence = options
|
|
39
|
+
self.confidence = options.pop("confidence")
|
|
36
40
|
if not 0 <= self.confidence <= 2:
|
|
37
41
|
raise ValueError(f"confidence {self.confidence!r} must be between 0 and 2")
|
|
38
42
|
|
|
39
43
|
b_conf = BanditConfig(config_file=self.config_file)
|
|
44
|
+
disabled_messages = prospector_config.get_disabled_messages("bandit")
|
|
45
|
+
if disabled_messages:
|
|
46
|
+
b_conf.config.setdefault("skips", []).extend(disabled_messages)
|
|
47
|
+
if options:
|
|
48
|
+
b_conf.config.update(options)
|
|
49
|
+
b_conf.validate(path="<prospector config>")
|
|
40
50
|
profile = _get_profile(b_conf, self.profile, self.config_file)
|
|
41
51
|
extension_mgr = _init_extensions()
|
|
42
52
|
extension_mgr.validate_profile(profile)
|
|
43
53
|
|
|
44
54
|
self.manager = BanditManager(b_conf, None, profile=profile)
|
|
45
55
|
|
|
46
|
-
def run(self, found_files):
|
|
56
|
+
def run(self, found_files: FileFinder) -> list[Message]:
|
|
57
|
+
assert self.manager is not None
|
|
58
|
+
|
|
47
59
|
self.manager.files_list = sorted(found_files.files)
|
|
48
60
|
self.manager.exclude_files = []
|
|
49
61
|
|
prospector/tools/base.py
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from
|
|
2
|
+
from collections.abc import Iterable
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
3
5
|
|
|
6
|
+
from prospector.finder import FileFinder
|
|
4
7
|
from prospector.message import Message
|
|
5
8
|
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from prospector.config import ProspectorConfig
|
|
11
|
+
|
|
6
12
|
|
|
7
13
|
class ToolBase(ABC):
|
|
8
14
|
@abstractmethod
|
|
9
|
-
def configure(
|
|
15
|
+
def configure(
|
|
16
|
+
self, prospector_config: "ProspectorConfig", found_files: FileFinder
|
|
17
|
+
) -> Optional[tuple[Optional[Union[str, Path]], Optional[Iterable[Message]]]]:
|
|
10
18
|
"""
|
|
11
19
|
Tools have their own way of being configured from configuration files
|
|
12
20
|
on the current path - for example, a .pep8rc file. Prospector will use
|
|
@@ -25,7 +33,7 @@ class ToolBase(ABC):
|
|
|
25
33
|
raise NotImplementedError
|
|
26
34
|
|
|
27
35
|
@abstractmethod
|
|
28
|
-
def run(self, found_files) ->
|
|
36
|
+
def run(self, found_files: FileFinder) -> list[Message]:
|
|
29
37
|
"""
|
|
30
38
|
Actually run the tool and collect the various messages emitted by the tool.
|
|
31
39
|
It is expected that this will convert whatever output of the tool into the
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import mimetypes
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
from dodgy.checks import check_file_contents
|
|
5
6
|
|
|
@@ -8,18 +9,21 @@ from prospector.finder import FileFinder
|
|
|
8
9
|
from prospector.message import Location, Message
|
|
9
10
|
from prospector.tools.base import ToolBase
|
|
10
11
|
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from prospector.config import ProspectorConfig
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
|
|
16
|
+
def module_from_path(path: Path) -> str:
|
|
13
17
|
# TODO hacky...
|
|
14
18
|
return ".".join(path.parts[1:-1] + (path.stem,))
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
class DodgyTool(ToolBase):
|
|
18
|
-
def configure(self, prospector_config, found_files):
|
|
22
|
+
def configure(self, prospector_config: "ProspectorConfig", found_files: FileFinder) -> None:
|
|
19
23
|
# empty: just implementing to satisfy the ABC contract
|
|
20
24
|
pass
|
|
21
25
|
|
|
22
|
-
def run(self, found_files: FileFinder):
|
|
26
|
+
def run(self, found_files: FileFinder) -> list[Message]:
|
|
23
27
|
warnings = []
|
|
24
28
|
for filepath in found_files.files:
|
|
25
29
|
mimetype = mimetypes.guess_type(str(filepath.absolute()))
|
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
import ast
|
|
2
|
+
from typing import TYPE_CHECKING, Any
|
|
2
3
|
|
|
3
4
|
from mccabe import PathGraphingAstVisitor
|
|
4
5
|
|
|
5
6
|
from prospector.encoding import CouldNotHandleEncoding, read_py_file
|
|
7
|
+
from prospector.finder import FileFinder
|
|
6
8
|
from prospector.message import Location, Message, make_tool_error_message
|
|
7
9
|
from prospector.tools.base import ToolBase
|
|
8
10
|
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from prospector.config import ProspectorConfig
|
|
13
|
+
|
|
9
14
|
__all__ = ("McCabeTool",)
|
|
10
15
|
|
|
11
16
|
|
|
12
17
|
class McCabeTool(ToolBase):
|
|
13
|
-
def __init__(self, *args, **kwargs):
|
|
18
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
14
19
|
super().__init__(*args, **kwargs)
|
|
15
|
-
self.ignore_codes =
|
|
20
|
+
self.ignore_codes: list[str] = []
|
|
16
21
|
self.max_complexity = 10
|
|
17
22
|
|
|
18
|
-
def configure(self, prospector_config, _):
|
|
23
|
+
def configure(self, prospector_config: "ProspectorConfig", _: Any) -> None:
|
|
19
24
|
self.ignore_codes = prospector_config.get_disabled_messages("mccabe")
|
|
20
25
|
|
|
21
26
|
options = prospector_config.tool_options("mccabe")
|
|
22
27
|
if "max-complexity" in options:
|
|
23
28
|
self.max_complexity = options["max-complexity"]
|
|
24
29
|
|
|
25
|
-
def run(self, found_files):
|
|
30
|
+
def run(self, found_files: FileFinder) -> list[Message]:
|
|
26
31
|
messages = []
|
|
27
32
|
|
|
28
33
|
for code_file in found_files.python_modules:
|
|
@@ -38,7 +43,9 @@ class McCabeTool(ToolBase):
|
|
|
38
43
|
code_file,
|
|
39
44
|
"mccabe",
|
|
40
45
|
"MC0000",
|
|
41
|
-
message=
|
|
46
|
+
message=(
|
|
47
|
+
f"Could not handle the encoding of this file: {err.encoding}" # type: ignore[attr-defined]
|
|
48
|
+
),
|
|
42
49
|
)
|
|
43
50
|
)
|
|
44
51
|
continue
|
|
@@ -77,5 +84,5 @@ class McCabeTool(ToolBase):
|
|
|
77
84
|
|
|
78
85
|
return self.filter_messages(messages)
|
|
79
86
|
|
|
80
|
-
def filter_messages(self, messages):
|
|
87
|
+
def filter_messages(self, messages: list[Message]) -> list[Message]:
|
|
81
88
|
return [message for message in messages if message.code not in self.ignore_codes]
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from multiprocessing import Process, Queue
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional
|
|
2
3
|
|
|
3
4
|
from mypy import api
|
|
4
5
|
|
|
6
|
+
from prospector.finder import FileFinder
|
|
5
7
|
from prospector.message import Location, Message
|
|
6
8
|
from prospector.tools import ToolBase
|
|
7
9
|
|
|
@@ -9,30 +11,20 @@ __all__ = ("MypyTool",)
|
|
|
9
11
|
|
|
10
12
|
from prospector.tools.exceptions import BadToolConfig
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"implicit-optional",
|
|
19
|
-
"strict-optional",
|
|
20
|
-
"platform",
|
|
21
|
-
"python-2-mode",
|
|
22
|
-
"python-version",
|
|
23
|
-
"namespace-packages",
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def format_message(message):
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from prospector.config import ProspectorConfig
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def format_message(message: str) -> Message:
|
|
19
|
+
character: Optional[int]
|
|
28
20
|
try:
|
|
29
|
-
(path,
|
|
30
|
-
line = int(
|
|
31
|
-
character = int(
|
|
21
|
+
(path, line_str, char_str, err_type, err_msg) = message.split(":", 4)
|
|
22
|
+
line = int(line_str)
|
|
23
|
+
character = int(char_str)
|
|
32
24
|
except ValueError:
|
|
33
25
|
try:
|
|
34
|
-
(path,
|
|
35
|
-
line = int(
|
|
26
|
+
(path, line_str, err_type, err_msg) = message.split(":", 3)
|
|
27
|
+
line = int(line_str)
|
|
36
28
|
character = None
|
|
37
29
|
except ValueError:
|
|
38
30
|
(path, err_type, err_msg) = message.split(":", 2)
|
|
@@ -53,7 +45,9 @@ def format_message(message):
|
|
|
53
45
|
)
|
|
54
46
|
|
|
55
47
|
|
|
56
|
-
def _run_in_subprocess(
|
|
48
|
+
def _run_in_subprocess(
|
|
49
|
+
q: "Queue[tuple[str, str]]", cmd: Callable[[list[str]], tuple[str, str]], paths: list[str]
|
|
50
|
+
) -> None:
|
|
57
51
|
"""
|
|
58
52
|
This function exists only to be called by multiprocessing.Process as using
|
|
59
53
|
lambda is forbidden
|
|
@@ -62,72 +56,46 @@ def _run_in_subprocess(q, cmd, paths):
|
|
|
62
56
|
|
|
63
57
|
|
|
64
58
|
class MypyTool(ToolBase):
|
|
65
|
-
def __init__(self, *args, **kwargs):
|
|
59
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
66
60
|
super().__init__(*args, **kwargs)
|
|
67
61
|
self.checker = api
|
|
68
62
|
self.options = ["--show-column-numbers", "--no-error-summary"]
|
|
69
63
|
self.use_dmypy = False
|
|
70
64
|
|
|
71
|
-
def configure(self, prospector_config, _):
|
|
65
|
+
def configure(self, prospector_config: "ProspectorConfig", _: Any) -> None:
|
|
72
66
|
options = prospector_config.tool_options("mypy")
|
|
73
67
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if ignore_missing_imports:
|
|
100
|
-
self.options.append("--ignore-missing-imports")
|
|
101
|
-
|
|
102
|
-
if implict_optional:
|
|
103
|
-
self.options.append("--implict-optional")
|
|
104
|
-
|
|
105
|
-
if platform:
|
|
106
|
-
self.options.append(f"--platform {platform}")
|
|
107
|
-
|
|
108
|
-
if python_2_mode:
|
|
109
|
-
self.options.append("--py2")
|
|
110
|
-
|
|
111
|
-
if python_version:
|
|
112
|
-
self.options.append(f"--python-version {python_version}")
|
|
113
|
-
|
|
114
|
-
if strict_optional:
|
|
115
|
-
self.options.append("--strict-optional")
|
|
116
|
-
|
|
117
|
-
if namespace_packages:
|
|
118
|
-
self.options.append("--namespace-packages")
|
|
119
|
-
|
|
120
|
-
for list_option in LIST_OPTIONS:
|
|
121
|
-
for entry in options.get(list_option, []):
|
|
122
|
-
self.options.append(f"--{list_option}-{entry}")
|
|
123
|
-
|
|
124
|
-
def run(self, found_files):
|
|
68
|
+
self.use_dmypy = options.pop("use-dmypy", False)
|
|
69
|
+
|
|
70
|
+
# For backward compatibility
|
|
71
|
+
if "follow-imports" not in options:
|
|
72
|
+
options["follow-imports"] = "normal"
|
|
73
|
+
if "python-2-mode" in options and "py2" not in options:
|
|
74
|
+
options["py2"] = options.pop("python-2-mode")
|
|
75
|
+
|
|
76
|
+
for name, value in options.items():
|
|
77
|
+
if value is False:
|
|
78
|
+
continue
|
|
79
|
+
if value is True:
|
|
80
|
+
self.options.append(f"--{name}")
|
|
81
|
+
continue
|
|
82
|
+
if isinstance(value, (int, float, str)):
|
|
83
|
+
self.options.append(f"--{name}={value}")
|
|
84
|
+
continue
|
|
85
|
+
if isinstance(value, list):
|
|
86
|
+
for v in value:
|
|
87
|
+
self.options.append(f"--{name}-{v}")
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
raise BadToolConfig("mypy", f"The option {name} has an unsupported balue type: {type(value)}")
|
|
91
|
+
|
|
92
|
+
def run(self, found_files: FileFinder) -> list[Message]:
|
|
125
93
|
paths = [str(path) for path in found_files.python_modules]
|
|
126
94
|
paths.extend(self.options)
|
|
127
95
|
if self.use_dmypy:
|
|
128
96
|
# Due to dmypy messing with stdout/stderr we call it in a separate
|
|
129
97
|
# process
|
|
130
|
-
q = Queue(1)
|
|
98
|
+
q: Queue[str] = Queue(1)
|
|
131
99
|
p = Process(target=_run_in_subprocess, args=(q, self.checker.run_dmypy, ["run", "--"] + paths))
|
|
132
100
|
p.start()
|
|
133
101
|
result = q.get()
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from prospector.tools.base import ToolBase
|
|
3
6
|
|
|
4
7
|
try: # Python >= 3.11
|
|
5
8
|
import re._constants as sre_constants
|
|
6
9
|
except ImportError:
|
|
7
|
-
import sre_constants
|
|
10
|
+
import sre_constants # pylint: disable=deprecated-module
|
|
8
11
|
|
|
9
12
|
import yaml
|
|
10
13
|
|
|
11
14
|
from prospector.finder import FileFinder
|
|
12
15
|
from prospector.message import Location, Message
|
|
13
16
|
from prospector.profiles import AUTO_LOADED_PROFILES
|
|
14
|
-
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from prospector.config import ProspectorConfig
|
|
20
|
+
|
|
15
21
|
|
|
16
22
|
PROFILE_IS_EMPTY = "profile-is-empty"
|
|
17
23
|
CONFIG_SETTING_SHOULD_BE_LIST = "should-be-list"
|
|
@@ -26,7 +32,9 @@ CONFIG_DEPRECATED_CODE = "deprecated-tool-code"
|
|
|
26
32
|
__all__ = ("ProfileValidationTool",)
|
|
27
33
|
|
|
28
34
|
|
|
29
|
-
def _tool_names(with_deprecated: bool = True):
|
|
35
|
+
def _tool_names(with_deprecated: bool = True) -> list[str]:
|
|
36
|
+
from prospector.tools import DEPRECATED_TOOL_NAMES, TOOLS # pylint: disable=import-outside-toplevel
|
|
37
|
+
|
|
30
38
|
tools = list(TOOLS)
|
|
31
39
|
if with_deprecated:
|
|
32
40
|
tools += DEPRECATED_TOOL_NAMES.keys()
|
|
@@ -49,27 +57,27 @@ class ProfileValidationTool(ToolBase):
|
|
|
49
57
|
)
|
|
50
58
|
ALL_SETTINGS = LIST_SETTINGS + BOOL_SETTINGS + OTHER_SETTINGS
|
|
51
59
|
|
|
52
|
-
def __init__(self):
|
|
60
|
+
def __init__(self) -> None:
|
|
53
61
|
self.to_check = set(AUTO_LOADED_PROFILES)
|
|
54
|
-
self.ignore_codes =
|
|
62
|
+
self.ignore_codes: list[str] = []
|
|
55
63
|
|
|
56
|
-
def configure(self, prospector_config, found_files):
|
|
64
|
+
def configure(self, prospector_config: "ProspectorConfig", found_files: FileFinder) -> None:
|
|
57
65
|
for profile in prospector_config.config.profiles:
|
|
58
66
|
self.to_check.add(profile)
|
|
59
67
|
|
|
60
68
|
self.ignore_codes = prospector_config.get_disabled_messages("profile-validator")
|
|
61
69
|
|
|
62
|
-
def validate(self, filepath: Path):
|
|
70
|
+
def validate(self, filepath: Path) -> list[Message]:
|
|
63
71
|
# pylint: disable=too-many-locals
|
|
64
72
|
# TODO: this should be broken down into smaller pieces
|
|
65
|
-
messages = []
|
|
73
|
+
messages: list[Message] = []
|
|
66
74
|
|
|
67
75
|
with filepath.open() as profile_file:
|
|
68
76
|
_file_contents = profile_file.read()
|
|
69
77
|
parsed = yaml.safe_load(_file_contents)
|
|
70
78
|
raw_contents = _file_contents.split("\n")
|
|
71
79
|
|
|
72
|
-
def add_message(code, message, setting):
|
|
80
|
+
def add_message(code: str, message: str, setting: str) -> None:
|
|
73
81
|
if code in self.ignore_codes:
|
|
74
82
|
return
|
|
75
83
|
line = -1
|
|
@@ -77,9 +85,8 @@ class ProfileValidationTool(ToolBase):
|
|
|
77
85
|
if setting in fileline:
|
|
78
86
|
line = number + 1
|
|
79
87
|
break
|
|
80
|
-
location = Location(filepath, None, None, line, 0
|
|
81
|
-
|
|
82
|
-
messages.append(message)
|
|
88
|
+
location = Location(filepath, None, None, line, 0)
|
|
89
|
+
messages.append(Message("profile-validator", code, location, message))
|
|
83
90
|
|
|
84
91
|
if parsed is None:
|
|
85
92
|
# this happens if a completely empty profile is found
|
|
@@ -159,7 +166,7 @@ class ProfileValidationTool(ToolBase):
|
|
|
159
166
|
if not isinstance(parsed[key], (tuple, list)):
|
|
160
167
|
add_message(CONFIG_SETTING_SHOULD_BE_LIST, f'"{key}" should be a list', key)
|
|
161
168
|
|
|
162
|
-
for key in parsed
|
|
169
|
+
for key in parsed:
|
|
163
170
|
if key not in ProfileValidationTool.ALL_SETTINGS and key not in _tool_names():
|
|
164
171
|
add_message(
|
|
165
172
|
CONFIG_UNKNOWN_SETTING,
|
|
@@ -170,7 +177,7 @@ class ProfileValidationTool(ToolBase):
|
|
|
170
177
|
if "pep257" in parsed:
|
|
171
178
|
add_message(
|
|
172
179
|
CONFIG_DEPRECATED_CODE,
|
|
173
|
-
"pep257 tool has been renamed to 'pydocstyle'.
|
|
180
|
+
"pep257 tool has been renamed to 'pydocstyle'. The name pep257 will be removed in prospector 2.0+.",
|
|
174
181
|
"pep257",
|
|
175
182
|
)
|
|
176
183
|
|
|
@@ -191,6 +198,8 @@ class ProfileValidationTool(ToolBase):
|
|
|
191
198
|
)
|
|
192
199
|
|
|
193
200
|
if "pyflakes" in parsed:
|
|
201
|
+
from prospector.tools import pyflakes # pylint: disable=import-outside-toplevel
|
|
202
|
+
|
|
194
203
|
for code in parsed["pyflakes"].get("enable", []) + parsed["pyflakes"].get("disable", []):
|
|
195
204
|
if code in pyflakes.LEGACY_CODE_MAP:
|
|
196
205
|
_legacy = pyflakes.LEGACY_CODE_MAP[code]
|
|
@@ -202,7 +211,7 @@ class ProfileValidationTool(ToolBase):
|
|
|
202
211
|
|
|
203
212
|
return messages
|
|
204
213
|
|
|
205
|
-
def run(self, found_files: FileFinder):
|
|
214
|
+
def run(self, found_files: FileFinder) -> list[Message]:
|
|
206
215
|
messages = []
|
|
207
216
|
for filepath in found_files.files:
|
|
208
217
|
for possible in self.to_check:
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import codecs
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
|
+
from collections.abc import Iterable
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
4
7
|
|
|
5
8
|
from pep8ext_naming import NamingChecker
|
|
6
9
|
from pycodestyle import PROJECT_CONFIG, USER_CONFIG, BaseReport, StyleGuide, register_check
|
|
@@ -9,15 +12,18 @@ from prospector.finder import FileFinder
|
|
|
9
12
|
from prospector.message import Location, Message
|
|
10
13
|
from prospector.tools.base import ToolBase
|
|
11
14
|
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from prospector.config import ProspectorConfig
|
|
17
|
+
|
|
12
18
|
__all__ = ("PycodestyleTool",)
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
class ProspectorReport(BaseReport):
|
|
16
|
-
def __init__(self, *args, **kwargs):
|
|
22
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
17
23
|
super().__init__(*args, **kwargs)
|
|
18
|
-
self._prospector_messages = []
|
|
24
|
+
self._prospector_messages: list[Message] = []
|
|
19
25
|
|
|
20
|
-
def error(self, line_number, offset, text, check):
|
|
26
|
+
def error(self, line_number: Optional[int], offset: int, text: str, check: str) -> None:
|
|
21
27
|
code = super().error(
|
|
22
28
|
line_number,
|
|
23
29
|
offset,
|
|
@@ -53,12 +59,12 @@ class ProspectorReport(BaseReport):
|
|
|
53
59
|
|
|
54
60
|
self._prospector_messages.append(message)
|
|
55
61
|
|
|
56
|
-
def get_messages(self):
|
|
62
|
+
def get_messages(self) -> list[Message]:
|
|
57
63
|
return self._prospector_messages
|
|
58
64
|
|
|
59
65
|
|
|
60
66
|
class ProspectorStyleGuide(StyleGuide):
|
|
61
|
-
def __init__(self, config, found_files, *args, **kwargs):
|
|
67
|
+
def __init__(self, config: "ProspectorConfig", found_files: FileFinder, *args: Any, **kwargs: Any) -> None:
|
|
62
68
|
self._config = config
|
|
63
69
|
self._files = found_files
|
|
64
70
|
self._module_paths = found_files.python_modules
|
|
@@ -68,7 +74,7 @@ class ProspectorStyleGuide(StyleGuide):
|
|
|
68
74
|
|
|
69
75
|
super().__init__(*args, **kwargs)
|
|
70
76
|
|
|
71
|
-
def excluded(self, filename, parent=None):
|
|
77
|
+
def excluded(self, filename: str, parent: Optional[str] = None) -> bool:
|
|
72
78
|
if super().excluded(filename, parent):
|
|
73
79
|
return True
|
|
74
80
|
|
|
@@ -82,11 +88,11 @@ class ProspectorStyleGuide(StyleGuide):
|
|
|
82
88
|
|
|
83
89
|
|
|
84
90
|
class PycodestyleTool(ToolBase):
|
|
85
|
-
|
|
86
|
-
super().__init__(*args, **kwargs)
|
|
87
|
-
self.checker = None
|
|
91
|
+
checker: Optional[ProspectorStyleGuide] = None
|
|
88
92
|
|
|
89
|
-
def configure(
|
|
93
|
+
def configure(
|
|
94
|
+
self, prospector_config: "ProspectorConfig", found_files: FileFinder
|
|
95
|
+
) -> Optional[tuple[Optional[str], Optional[Iterable[Message]]]]:
|
|
90
96
|
# figure out if we should use a pre-existing config file
|
|
91
97
|
# such as setup.cfg or tox.ini
|
|
92
98
|
external_config = None
|
|
@@ -97,18 +103,18 @@ class PycodestyleTool(ToolBase):
|
|
|
97
103
|
if prospector_config.use_external_config("pycodestyle"):
|
|
98
104
|
use_config = True
|
|
99
105
|
|
|
100
|
-
paths = [os.path.join(prospector_config.workdir, name) for name in PROJECT_CONFIG]
|
|
106
|
+
paths: list[Union[str, Path]] = [os.path.join(prospector_config.workdir, name) for name in PROJECT_CONFIG]
|
|
101
107
|
paths.append(USER_CONFIG)
|
|
102
108
|
ext_loc = prospector_config.external_config_location("pycodestyle")
|
|
103
109
|
if ext_loc is not None:
|
|
104
|
-
paths = [ext_loc] + paths
|
|
110
|
+
paths = [ext_loc] + paths # type: ignore[assignment,operator]
|
|
105
111
|
|
|
106
112
|
for conf_path in paths:
|
|
107
113
|
if os.path.exists(conf_path) and os.path.isfile(conf_path):
|
|
108
114
|
# this file exists - but does it have pep8 or pycodestyle config in it?
|
|
109
115
|
# TODO: Remove this
|
|
110
116
|
header = re.compile(r"\[(pep8|pycodestyle)\]")
|
|
111
|
-
with codecs.open(conf_path) as conf_file:
|
|
117
|
+
with codecs.open(str(conf_path)) as conf_file:
|
|
112
118
|
if any(header.search(line) for line in conf_file.readlines()):
|
|
113
119
|
external_config = conf_path
|
|
114
120
|
break
|
|
@@ -133,7 +139,7 @@ class PycodestyleTool(ToolBase):
|
|
|
133
139
|
if "max-line-length" in prospector_config.tool_options("pycodestyle"):
|
|
134
140
|
self.checker.options.max_line_length = prospector_config.tool_options("pycodestyle")["max-line-length"]
|
|
135
141
|
else:
|
|
136
|
-
configured_by = "Configuration found at
|
|
142
|
+
configured_by = f"Configuration found at {external_config}"
|
|
137
143
|
|
|
138
144
|
# if we have a command line --max-line-length argument, that
|
|
139
145
|
# overrules everything
|
|
@@ -143,7 +149,8 @@ class PycodestyleTool(ToolBase):
|
|
|
143
149
|
|
|
144
150
|
return configured_by, []
|
|
145
151
|
|
|
146
|
-
def run(self, _):
|
|
152
|
+
def run(self, _: Any) -> list[Message]:
|
|
153
|
+
assert self.checker is not None
|
|
147
154
|
report = self.checker.check_files()
|
|
148
155
|
return report.get_messages()
|
|
149
156
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any
|
|
2
|
+
|
|
1
3
|
from pydocstyle.checker import AllError, ConventionChecker
|
|
2
4
|
|
|
3
5
|
from prospector.encoding import CouldNotHandleEncoding, read_py_file
|
|
@@ -5,19 +7,23 @@ from prospector.finder import FileFinder
|
|
|
5
7
|
from prospector.message import Location, Message, make_tool_error_message
|
|
6
8
|
from prospector.tools.base import ToolBase
|
|
7
9
|
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from prospector.config import ProspectorConfig
|
|
12
|
+
|
|
13
|
+
|
|
8
14
|
__all__ = ("PydocstyleTool",)
|
|
9
15
|
|
|
10
16
|
|
|
11
17
|
class PydocstyleTool(ToolBase):
|
|
12
|
-
def __init__(self, *args, **kwargs):
|
|
18
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
13
19
|
super().__init__(*args, **kwargs)
|
|
14
|
-
self._code_files = []
|
|
15
|
-
self.ignore_codes =
|
|
20
|
+
self._code_files: list[str] = []
|
|
21
|
+
self.ignore_codes: list[str] = []
|
|
16
22
|
|
|
17
|
-
def configure(self, prospector_config, found_files):
|
|
23
|
+
def configure(self, prospector_config: "ProspectorConfig", found_files: FileFinder) -> None:
|
|
18
24
|
self.ignore_codes = prospector_config.get_disabled_messages("pydocstyle")
|
|
19
25
|
|
|
20
|
-
def run(self, found_files: FileFinder):
|
|
26
|
+
def run(self, found_files: FileFinder) -> list[Message]:
|
|
21
27
|
messages = []
|
|
22
28
|
|
|
23
29
|
checker = ConventionChecker()
|
|
@@ -61,5 +67,5 @@ class PydocstyleTool(ToolBase):
|
|
|
61
67
|
|
|
62
68
|
return self.filter_messages(messages)
|
|
63
69
|
|
|
64
|
-
def filter_messages(self, messages):
|
|
70
|
+
def filter_messages(self, messages: list[Message]) -> list[Message]:
|
|
65
71
|
return [message for message in messages if message.code not in self.ignore_codes]
|