prospector 1.14.0__py3-none-any.whl → 1.15.0__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/postfilter.py CHANGED
@@ -1,10 +1,18 @@
1
1
  from pathlib import Path
2
+ from typing import Optional
2
3
 
3
4
  from prospector.message import Message
4
5
  from prospector.suppression import get_suppressions
6
+ from prospector.tools.base import ToolBase
5
7
 
6
8
 
7
- def filter_messages(filepaths: list[Path], messages: list[Message]) -> list[Message]:
9
+ def filter_messages(
10
+ filepaths: list[Path],
11
+ messages: list[Message],
12
+ tools: Optional[dict[str, ToolBase]] = None,
13
+ blending: bool = False,
14
+ blend_combos: Optional[list[list[tuple[str, str]]]] = None,
15
+ ) -> list[Message]:
8
16
  """
9
17
  This method post-processes all messages output by all tools, in order to filter
10
18
  out any based on the overall output.
@@ -23,7 +31,9 @@ def filter_messages(filepaths: list[Path], messages: list[Message]) -> list[Mess
23
31
  This method uses the information about suppressed messages from pylint to
24
32
  squash the unwanted redundant error from pyflakes and frosted.
25
33
  """
26
- paths_to_ignore, lines_to_ignore, messages_to_ignore = get_suppressions(filepaths, messages)
34
+ paths_to_ignore, lines_to_ignore, messages_to_ignore = get_suppressions(
35
+ filepaths, messages, tools, blending, blend_combos
36
+ )
27
37
 
28
38
  filtered = []
29
39
  for message in messages:
prospector/run.py CHANGED
@@ -16,6 +16,7 @@ from prospector.finder import FileFinder
16
16
  from prospector.formatters import FORMATTERS, Formatter
17
17
  from prospector.message import Location, Message
18
18
  from prospector.tools import DEPRECATED_TOOL_NAMES
19
+ from prospector.tools.base import ToolBase
19
20
  from prospector.tools.utils import CaptureOutput
20
21
 
21
22
 
@@ -25,7 +26,9 @@ class Prospector:
25
26
  self.summary: Optional[dict[str, Any]] = None
26
27
  self.messages = config.messages
27
28
 
28
- def process_messages(self, found_files: FileFinder, messages: list[Message]) -> list[Message]:
29
+ def process_messages(
30
+ self, found_files: FileFinder, messages: list[Message], tools: dict[str, tools.ToolBase]
31
+ ) -> list[Message]:
29
32
  if self.config.blending:
30
33
  messages = blender.blend(messages)
31
34
 
@@ -37,7 +40,7 @@ class Prospector:
37
40
  updated.append(msg)
38
41
  messages = updated
39
42
 
40
- return postfilter.filter_messages(found_files.python_modules, messages)
43
+ return postfilter.filter_messages(found_files.python_modules, messages, tools, self.config.blending)
41
44
 
42
45
  def execute(self) -> None:
43
46
  deprecated_names = self.config.replace_deprecated_tool_names()
@@ -70,6 +73,8 @@ class Prospector:
70
73
  messages.append(message)
71
74
  warnings.warn(msg, category=DeprecationWarning, stacklevel=0)
72
75
 
76
+ running_tools: dict[str, ToolBase] = {}
77
+
73
78
  # Run the tools
74
79
  for tool in self.config.get_tools(found_files):
75
80
  for name, cls in tools.TOOLS.items():
@@ -79,6 +84,8 @@ class Prospector:
79
84
  else:
80
85
  toolname = "Unknown"
81
86
 
87
+ running_tools[toolname] = tool
88
+
82
89
  try:
83
90
  # Tools can output to stdout/stderr in unexpected places, for example,
84
91
  # pydocstyle emits warnings about __all__ and as pyroma exec's the setup.py
@@ -116,7 +123,7 @@ class Prospector:
116
123
  )
117
124
  messages.append(message)
118
125
 
119
- messages = self.process_messages(found_files, messages)
126
+ messages = self.process_messages(found_files, messages, running_tools)
120
127
 
121
128
  summary["message_count"] = len(messages)
122
129
  summary["completed"] = datetime.now()
prospector/suppression.py CHANGED
@@ -27,12 +27,13 @@ from pathlib import Path
27
27
  from typing import Optional
28
28
 
29
29
  from prospector import encoding
30
+ from prospector.blender import BLEND_COMBOS
30
31
  from prospector.exceptions import FatalProspectorException
31
32
  from prospector.message import Message
33
+ from prospector.tools.base import PEP8_IGNORE_LINE_CODE, ToolBase
32
34
 
33
35
  _FLAKE8_IGNORE_FILE = re.compile(r"flake8[:=]\s*noqa", re.IGNORECASE)
34
36
  _PEP8_IGNORE_LINE = re.compile(r"#\s*noqa(\s*#.*)?$", re.IGNORECASE)
35
- _PEP8_IGNORE_LINE_CODE = re.compile(r"#\s*noqa:([^#]*[^# ])(\s*#.*)?$", re.IGNORECASE)
36
37
  _PYLINT_SUPPRESSED_MESSAGE = re.compile(r"^Suppressed \'([a-z0-9-]+)\' \(from line \d+\)$")
37
38
 
38
39
 
@@ -51,6 +52,17 @@ class Ignore:
51
52
  def __str__(self) -> str:
52
53
  return self.code if self.source is None else f"{self.source}.{self.code}"
53
54
 
55
+ def __repr__(self) -> str:
56
+ return f"<{type(self).__name__} {self}>"
57
+
58
+ def __eq__(self, value: object) -> bool:
59
+ if not isinstance(value, Ignore):
60
+ return False
61
+ return self.code == value.code and self.source == value.source
62
+
63
+ def __hash__(self) -> int:
64
+ return hash((self.source, self.code))
65
+
54
66
 
55
67
  def get_noqa_suppressions(file_contents: list[str]) -> tuple[bool, set[int], dict[int, set[Ignore]]]:
56
68
  """
@@ -71,7 +83,7 @@ def get_noqa_suppressions(file_contents: list[str]) -> tuple[bool, set[int], dic
71
83
  if _PEP8_IGNORE_LINE.search(line):
72
84
  ignore_lines.add(line_number + 1)
73
85
  else:
74
- noqa_match = _PEP8_IGNORE_LINE_CODE.search(line)
86
+ noqa_match = PEP8_IGNORE_LINE_CODE.search(line)
75
87
  if noqa_match:
76
88
  prospector_ignore = noqa_match.group(1).strip().split(",")
77
89
  prospector_ignore = [elem.strip() for elem in prospector_ignore]
@@ -81,15 +93,6 @@ def get_noqa_suppressions(file_contents: list[str]) -> tuple[bool, set[int], dic
81
93
  return ignore_whole_file, ignore_lines, messages_to_ignore
82
94
 
83
95
 
84
- _PYLINT_EQUIVALENTS = {
85
- # TODO: blending has this info already?
86
- "unused-import": (
87
- ("pyflakes", "FL0001"),
88
- ("frosted", "E101"),
89
- )
90
- }
91
-
92
-
93
96
  def _parse_pylint_informational(
94
97
  messages: list[Message],
95
98
  ) -> tuple[set[Optional[Path]], dict[Optional[Path], dict[int, list[str]]]]:
@@ -113,17 +116,43 @@ def _parse_pylint_informational(
113
116
  return ignore_files, ignore_messages
114
117
 
115
118
 
119
+ def _process_tool_ignores(
120
+ tools_ignore: dict[Path, dict[int, set[Ignore]]],
121
+ blend_combos_dict: dict[Ignore, set[Ignore]],
122
+ messages_to_ignore: dict[Optional[Path], dict[int, set[Ignore]]],
123
+ ) -> None:
124
+ for path, lines_ignore in tools_ignore.items():
125
+ for line, ignores in lines_ignore.items():
126
+ for ignore in ignores:
127
+ if ignore in blend_combos_dict:
128
+ messages_to_ignore[path][line].update(blend_combos_dict[ignore])
129
+
130
+
116
131
  def get_suppressions(
117
- filepaths: list[Path], messages: list[Message]
132
+ filepaths: list[Path],
133
+ messages: list[Message],
134
+ tools: Optional[dict[str, ToolBase]] = None,
135
+ blending: bool = False,
136
+ blend_combos: Optional[list[list[tuple[str, str]]]] = None,
118
137
  ) -> tuple[set[Optional[Path]], dict[Path, set[int]], dict[Optional[Path], dict[int, set[Ignore]]]]:
119
138
  """
120
139
  Given every message which was emitted by the tools, and the
121
140
  list of files to inspect, create a list of files to ignore,
122
141
  and a map of filepath -> line-number -> codes to ignore
123
142
  """
143
+ tools = tools or {}
144
+ blend_combos = blend_combos or BLEND_COMBOS
145
+ blend_combos_dict: dict[Ignore, set[Ignore]] = defaultdict(set)
146
+ if blending:
147
+ for combo in blend_combos:
148
+ ignore_combos = {Ignore(tool, code) for tool, code in combo}
149
+ for ignore in ignore_combos:
150
+ blend_combos_dict[ignore] |= ignore_combos
151
+
124
152
  paths_to_ignore: set[Optional[Path]] = set()
125
153
  lines_to_ignore: dict[Path, set[int]] = defaultdict(set)
126
154
  messages_to_ignore: dict[Optional[Path], dict[int, set[Ignore]]] = defaultdict(lambda: defaultdict(set))
155
+ tools_ignore: dict[Path, dict[int, set[Ignore]]] = defaultdict(lambda: defaultdict(set))
127
156
 
128
157
  # First deal with 'noqa' style messages
129
158
  for filepath in filepaths:
@@ -141,6 +170,17 @@ def get_suppressions(
141
170
  for line, codes_ignore in file_messages_to_ignore.items():
142
171
  messages_to_ignore[filepath][line] |= codes_ignore
143
172
 
173
+ if blending:
174
+ for line_number, line_content in enumerate(file_contents):
175
+ for tool_name, tool in tools.items():
176
+ tool_ignores = tool.get_ignored_codes(line_content)
177
+ for tool_ignore in tool_ignores:
178
+ tools_ignore[filepath][line_number + 1].add(Ignore(tool_name, tool_ignore))
179
+
180
+ # Ignore the blending messages
181
+ if blending:
182
+ _process_tool_ignores(tools_ignore, blend_combos_dict, messages_to_ignore)
183
+
144
184
  # Now figure out which messages were suppressed by pylint
145
185
  pylint_ignore_files, pylint_ignore_messages = _parse_pylint_informational(messages)
146
186
  paths_to_ignore |= pylint_ignore_files
@@ -149,9 +189,5 @@ def get_suppressions(
149
189
  for code in codes:
150
190
  ignore = Ignore("pylint", code)
151
191
  messages_to_ignore[pylint_filepath][line_number].add(ignore)
152
- if code in _PYLINT_EQUIVALENTS:
153
- for ignore_source, ignore_code in _PYLINT_EQUIVALENTS[code]:
154
- ignore = Ignore(ignore_source, ignore_code)
155
- messages_to_ignore[pylint_filepath][line_number].add(ignore)
156
192
 
157
193
  return paths_to_ignore, lines_to_ignore, messages_to_ignore
prospector/tools/base.py CHANGED
@@ -1,3 +1,4 @@
1
+ import re
1
2
  from abc import ABC, abstractmethod
2
3
  from collections.abc import Iterable
3
4
  from pathlib import Path
@@ -9,6 +10,8 @@ from prospector.message import Message
9
10
  if TYPE_CHECKING:
10
11
  from prospector.config import ProspectorConfig
11
12
 
13
+ PEP8_IGNORE_LINE_CODE = re.compile(r"#\s*noqa:([^#]*[^# ])(\s*#.*)?$", re.IGNORECASE)
14
+
12
15
 
13
16
  class ToolBase(ABC):
14
17
  @abstractmethod
@@ -40,3 +43,10 @@ class ToolBase(ABC):
40
43
  standard prospector Message and Location objects.
41
44
  """
42
45
  raise NotImplementedError
46
+
47
+ def get_ignored_codes(self, line: str) -> list[str]:
48
+ """
49
+ Return a list of error codes that the tool will ignore from a line of code.
50
+ """
51
+ del line # unused
52
+ return []
@@ -1,19 +1,31 @@
1
+ import json
2
+ import re
1
3
  from multiprocessing import Process, Queue
2
- from typing import TYPE_CHECKING, Any, Callable, Optional
3
-
4
- from mypy import api
4
+ from typing import (
5
+ TYPE_CHECKING,
6
+ Any,
7
+ Callable,
8
+ Optional,
9
+ )
10
+
11
+ import mypy.api
12
+ import mypy.build
13
+ import mypy.errors
14
+ import mypy.fscache
15
+ import mypy.main
5
16
 
6
17
  from prospector.finder import FileFinder
7
18
  from prospector.message import Location, Message
8
19
  from prospector.tools import ToolBase
9
-
10
- __all__ = ("MypyTool",)
11
-
12
20
  from prospector.tools.exceptions import BadToolConfig
13
21
 
14
22
  if TYPE_CHECKING:
15
23
  from prospector.config import ProspectorConfig
16
24
 
25
+ _IGNORE_RE = re.compile(r"#\s*type:\s*ignore\[([^#]*[^# ])\](\s*#.*)?$", re.IGNORECASE)
26
+
27
+ __all__ = ("MypyTool",)
28
+
17
29
 
18
30
  def format_message(message: str) -> Message:
19
31
  character: Optional[int]
@@ -58,9 +70,10 @@ def _run_in_subprocess(
58
70
  class MypyTool(ToolBase):
59
71
  def __init__(self, *args: Any, **kwargs: Any) -> None:
60
72
  super().__init__(*args, **kwargs)
61
- self.checker = api
73
+ self.checker = mypy.api
62
74
  self.options = ["--show-column-numbers", "--no-error-summary"]
63
75
  self.use_dmypy = False
76
+ self.fscache = mypy.fscache.FileSystemCache()
64
77
 
65
78
  def configure(self, prospector_config: "ProspectorConfig", _: Any) -> None:
66
79
  options = prospector_config.tool_options("mypy")
@@ -90,18 +103,54 @@ class MypyTool(ToolBase):
90
103
  raise BadToolConfig("mypy", f"The option {name} has an unsupported value type: {type(value)}")
91
104
 
92
105
  def run(self, found_files: FileFinder) -> list[Message]:
93
- paths = [str(path) for path in found_files.python_modules]
94
- paths.extend(self.options)
106
+ args = [str(path) for path in found_files.python_modules]
107
+ args.extend(self.options)
95
108
  if self.use_dmypy:
96
109
  # Due to dmypy messing with stdout/stderr we call it in a separate
97
110
  # process
98
111
  q: Queue[str] = Queue(1)
99
- p = Process(target=_run_in_subprocess, args=(q, self.checker.run_dmypy, ["run", "--"] + paths))
112
+ p = Process(target=_run_in_subprocess, args=(q, self.checker.run_dmypy, ["run", "--"] + args))
100
113
  p.start()
101
114
  result = q.get()
102
115
  p.join()
103
- else:
104
- result = self.checker.run(paths)
105
- report, _ = result[0], result[1:] # noqa
106
116
 
107
- return [format_message(message) for message in report.splitlines()]
117
+ report, _ = result[0], result[1:] # noqa
118
+ return [format_message(message) for message in report.splitlines()]
119
+ else:
120
+ return self._run_std(args)
121
+
122
+ def _run_std(self, args: list[str]) -> list[Message]:
123
+ sources, options = mypy.main.process_options(args, fscache=self.fscache)
124
+ options.output = "json"
125
+ res = mypy.build.build(sources, options, fscache=self.fscache)
126
+
127
+ messages = []
128
+ for mypy_json in res.errors:
129
+ mypy_message = json.loads(mypy_json)
130
+ message = f"{mypy_message['message']}."
131
+ if mypy_message.get("hint", ""):
132
+ message = f"{message}, Hint: {mypy_message['hint']}."
133
+ code = mypy_message["code"]
134
+ messages.append(
135
+ Message(
136
+ "mypy",
137
+ code=code,
138
+ location=Location(
139
+ path=mypy_message["file"],
140
+ module=None,
141
+ function=None,
142
+ line=mypy_message["line"],
143
+ character=mypy_message["column"],
144
+ ),
145
+ message=message,
146
+ doc_url=f"{mypy.errors.BASE_RTD_URL}-{code}",
147
+ )
148
+ )
149
+
150
+ return messages
151
+
152
+ def get_ignored_codes(self, line: str) -> list[str]:
153
+ match = _IGNORE_RE.search(line)
154
+ if match:
155
+ return [e.strip() for e in match.group(1).split(",")]
156
+ return []
@@ -21,6 +21,8 @@ if TYPE_CHECKING:
21
21
 
22
22
  _UNUSED_WILDCARD_IMPORT_RE = re.compile(r"^Unused import(\(s\))? (.*) from wildcard import")
23
23
 
24
+ _IGNORE_RE = re.compile(r"#\s*pylint:\s*disable=([^#]*[^#\s])(\s*#.*)?$", re.IGNORECASE)
25
+
24
26
 
25
27
  def _is_in_dir(subpath: Path, path: Path) -> bool:
26
28
  return subpath.parent == path
@@ -266,3 +268,9 @@ class PylintTool(ToolBase):
266
268
 
267
269
  messages = self._collector.get_messages()
268
270
  return self.combine(messages)
271
+
272
+ def get_ignored_codes(self, line: str) -> list[str]:
273
+ match = _IGNORE_RE.search(line)
274
+ if match:
275
+ return [e.strip() for e in match.group(1).split(",")]
276
+ return []
@@ -1,12 +1,13 @@
1
1
  import json
2
2
  import subprocess # nosec
3
+ from pathlib import Path
3
4
  from typing import TYPE_CHECKING, Any
4
5
 
5
6
  from ruff.__main__ import find_ruff_bin
6
7
 
7
8
  from prospector.finder import FileFinder
8
9
  from prospector.message import Location, Message
9
- from prospector.tools.base import ToolBase
10
+ from prospector.tools.base import PEP8_IGNORE_LINE_CODE, ToolBase
10
11
 
11
12
  if TYPE_CHECKING:
12
13
  from prospector.config import ProspectorConfig
@@ -65,6 +66,8 @@ class RuffTool(ToolBase):
65
66
  if sub_message:
66
67
  message_str += f" [{', '.join(f'{k}: {v}' for k, v in sub_message.items())}]"
67
68
 
69
+ if message.get("filename") is None or found_files.is_excluded(Path(message.get("filename"))):
70
+ continue
68
71
  messages.append(
69
72
  Message(
70
73
  "ruff",
@@ -84,3 +87,9 @@ class RuffTool(ToolBase):
84
87
  )
85
88
  )
86
89
  return messages
90
+
91
+ def get_ignored_codes(self, line: str) -> list[str]:
92
+ match = PEP8_IGNORE_LINE_CODE.search(line)
93
+ if match:
94
+ return [e.strip() for e in match.group(1).split(",")]
95
+ return []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: prospector
3
- Version: 1.14.0
3
+ Version: 1.15.0
4
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
6
  License: GPLv2+
@@ -2,7 +2,7 @@ prospector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  prospector/__main__.py,sha256=-gdHYZxwq_P8er7HuZEBImY0pwaFq8uIa78dQdJsTTQ,71
3
3
  prospector/autodetect.py,sha256=Ok8S6jpDiGyhQlnRCMWpsLpSAIXWxA-NQphQuPaOm6o,3112
4
4
  prospector/blender.py,sha256=ldQSkfoEKv6pd72B9YCYdapeGUzgfhGzieAu7To3l6Y,4926
5
- prospector/blender_combinations.yaml,sha256=38M1G3mjnYXULhSOuwWYbeJncnaK6w1zqwr2W52bjyw,6624
5
+ prospector/blender_combinations.yaml,sha256=hQMYpwKHjP-DI9yjnNWcXOyWcDEf8U-I2Bg5-78BFV8,30816
6
6
  prospector/compat.py,sha256=p_2BOebzUcKbUAd7mW8rn6tIc10R96gJuZS71QI0XY4,360
7
7
  prospector/config/__init__.py,sha256=4nYshBncKUvZrwNKmp2bQ2mQ8uRS7GU20xPbiC-nJ9g,14793
8
8
  prospector/config/configuration.py,sha256=sNYR5Jc3P7tfIDXQoDMrOX4i2Yde0o9bc21ZXZNn6rw,14046
@@ -24,7 +24,7 @@ prospector/formatters/xunit.py,sha256=e5ObAWSLm-ekvWs8xsi-OaIL2yoYedlxuJdUhLZ8gk
24
24
  prospector/formatters/yaml.py,sha256=0RAL5BaaL9A0DfWZ-bdpK1mwgr8zJ_ULVwlnSXVPlDU,684
25
25
  prospector/message.py,sha256=HKXdO8bOezRKSnTtjqu0k04Cb7JgL0oPUWakuSBE9s4,3710
26
26
  prospector/pathutils.py,sha256=CyZIj4WXGill8OfnqRvcVqZYX0lzL3QcIxpkxCz-dkE,1219
27
- prospector/postfilter.py,sha256=3sZXhgyWy1Zs3qlqSchvd8a34j59150_nI1V8-ct-ls,2427
27
+ prospector/postfilter.py,sha256=BpmR1g1ZlgQB92_Uk6hRyYoIBUcivvcU8RGLUHXDdcU,2695
28
28
  prospector/profiles/__init__.py,sha256=q9zPLVEwo7qoouYFrmENsmByFrKKkr27Dd_Wo9btTJI,683
29
29
  prospector/profiles/exceptions.py,sha256=MDky4KXVwfOlW1yCbyp8Y07D8Kfz76jL3z-8T3WQIFI,1062
30
30
  prospector/profiles/profile.py,sha256=U8vDdyfka0_Ht9cYT2i_c-xbMcktSpS1h53cU7tGerk,17828
@@ -44,29 +44,29 @@ prospector/profiles/profiles/strictness_none.yaml,sha256=_Yf-eEl4cVXw6ePqx3V4mvG
44
44
  prospector/profiles/profiles/strictness_veryhigh.yaml,sha256=whQFEUtkySSEIriEwYOjSr-0SxICOWalNA9Y7FmXopQ,628
45
45
  prospector/profiles/profiles/strictness_verylow.yaml,sha256=YxZowcBtA3tAaHJGz2htTdAJ-AXmlHB-o4zEYKPRfJg,833
46
46
  prospector/profiles/profiles/test_warnings.yaml,sha256=arUcV9MnqiZJEHURH9bVRSYDhYUegNc-ltFYe_yQW44,23
47
- prospector/run.py,sha256=hjNyzY-wyedGwJspT80jCz4usk-HqL6FmqDcinASJZA,8403
48
- prospector/suppression.py,sha256=ecRCLcFNl-XygRnV6m2lqc4vLa0Kusb0mLkkYd6YMxw,6135
47
+ prospector/run.py,sha256=Sjh28jI-Bergzr3rxZp7QzRHP9Ue0SPdfcB0TEkMSDQ,8631
48
+ prospector/suppression.py,sha256=qT3TIe8a87mnXPOcRr6m58UodUREExBZxttTlWFTJbY,7654
49
49
  prospector/tools/__init__.py,sha256=9tDmxL_kn5jmAACeSi1jtSvT-9tI468Ccn1Up2wUFi0,2956
50
50
  prospector/tools/bandit/__init__.py,sha256=iU39U28_YP5QUm8sgU21Ps96czIIl6tSV7qtCxbFvms,3035
51
- prospector/tools/base.py,sha256=T1F-vq4rNcaToA4fXjZmcozkABpeiz0odFAMVMEJM1w,1838
51
+ prospector/tools/base.py,sha256=xL_uUbhZUyPrDU-2ntgmzhs-DW1e5sfDKb_OA7VtxKQ,2146
52
52
  prospector/tools/dodgy/__init__.py,sha256=howLCjFEheW_6ZoyQ15gLbiNNNUr0Pm2qNpLg3kleFY,1648
53
53
  prospector/tools/exceptions.py,sha256=Q-u4n6YzZuoMu17XkeKac1o1gBY36JK4MnvWaYrVYL0,170
54
54
  prospector/tools/mccabe/__init__.py,sha256=80-aYPqKCREeBqxiIUgsDvxc_GqYxHb5R0JduKHPRaE,3277
55
- prospector/tools/mypy/__init__.py,sha256=edd7hg7Cj1jP_Aoy7J3CzkjIqCrK1wu-lm5ygUQHV3g,3504
55
+ prospector/tools/mypy/__init__.py,sha256=G39v_IlcWkG7hm0R4qTwAoU2K-sWyqXHc-kgaawdqys,5092
56
56
  prospector/tools/profile_validator/__init__.py,sha256=bAkVG-fKtm3WaEv-We36wqzvtqWv4s06Z7YnRVG7UQ4,8326
57
57
  prospector/tools/pycodestyle/__init__.py,sha256=uMpUxqsPsryEsfyfGxpLzwoWUjIvfxIQke4Xvkfbi9A,5970
58
58
  prospector/tools/pydocstyle/__init__.py,sha256=WB-AT-c1FeUUUWATUzJbBLeREtu-lxT03bChh4nablo,2776
59
59
  prospector/tools/pyflakes/__init__.py,sha256=53NQFODU416KO991NxW14gChjagbSAhhfErx1ll7VUQ,5631
60
- prospector/tools/pylint/__init__.py,sha256=WoI23QXmGlumgZMRg1-tQJ8Tpzl9_KpLUQIKlb7vEkE,11108
60
+ prospector/tools/pylint/__init__.py,sha256=Nixin4odPsTj7q1C2Tud2mU5An1lCc7aKQdGAQLyf8g,11398
61
61
  prospector/tools/pylint/collector.py,sha256=7FHgO6OOLGD15_U4DERiXyEbSFnMjGUBeCwdmUlhO8I,1559
62
62
  prospector/tools/pylint/linter.py,sha256=YQ9SOna4WjbbauqSgUio6Ss8zN08PCr3aKdK9rMi7Ag,2143
63
63
  prospector/tools/pyright/__init__.py,sha256=USqauZofh-8ZSKGwXRXoaM2ItzfSFo2nGwPtLGEWICU,3346
64
64
  prospector/tools/pyroma/__init__.py,sha256=GPQRJZfbs_SI0RBTyySz-4SIuM__YoLfXAm7uYVXAS8,3151
65
- prospector/tools/ruff/__init__.py,sha256=4ieK1lWmJMW27LvLNcnkufZFexU46N2Cu5Qv_y-BIfk,3525
65
+ prospector/tools/ruff/__init__.py,sha256=r55pEbmjLFWmY1jiQ7aZ2OYBxkEAH5An3-CpL04rdc0,3915
66
66
  prospector/tools/utils.py,sha256=cRCogsMCH0lPBhdujPsIY0ovNAL6TAxBMohZRES02-4,1770
67
67
  prospector/tools/vulture/__init__.py,sha256=eaTh4X5onNlBMuz1x0rmcRn7x5XDVDgqftjIEd47eWI,3583
68
- prospector-1.14.0.dist-info/entry_points.txt,sha256=SxvCGt8MJTEZefHAvwnUc6jDetgCaaYY1Zpifuk8tqU,50
69
- prospector-1.14.0.dist-info/LICENSE,sha256=WoTRadDy8VbcIKoVzl5Q1QipuD_cexAf3ul4MaVLttc,18044
70
- prospector-1.14.0.dist-info/WHEEL,sha256=gSF7fibx4crkLz_A-IKR6kcuq0jJ64KNCkG8_bcaEao,88
71
- prospector-1.14.0.dist-info/METADATA,sha256=BnLIKymjwtohSKYyDAoaWKTQHWNoMA9RTVN4ka7v_As,9962
72
- prospector-1.14.0.dist-info/RECORD,,
68
+ prospector-1.15.0.dist-info/entry_points.txt,sha256=SxvCGt8MJTEZefHAvwnUc6jDetgCaaYY1Zpifuk8tqU,50
69
+ prospector-1.15.0.dist-info/LICENSE,sha256=WoTRadDy8VbcIKoVzl5Q1QipuD_cexAf3ul4MaVLttc,18044
70
+ prospector-1.15.0.dist-info/WHEEL,sha256=gSF7fibx4crkLz_A-IKR6kcuq0jJ64KNCkG8_bcaEao,88
71
+ prospector-1.15.0.dist-info/METADATA,sha256=hZAMrN74gIl-pGLRyaL7aItQmpqkM8e9aa5P1GMZKaY,9962
72
+ prospector-1.15.0.dist-info/RECORD,,