Skip to content

Commit 31eb3f6

Browse files
committed
Better output on wrong argument given to Ruff
1 parent 45015ad commit 31eb3f6

File tree

9 files changed

+59
-24
lines changed

9 files changed

+59
-24
lines changed

prospector/blender.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,10 @@ def blend(messages: list[Message], blend_combos: Optional[list[list[tuple[str, s
8585
blend_combos = blend_combos or BLEND_COMBOS
8686

8787
# group messages by file and then line number
88-
msgs_grouped: dict[Path, dict[int, list[Message]]] = defaultdict(lambda: defaultdict(list))
88+
msgs_grouped: dict[Optional[Path], dict[Optional[int], list[Message]]] = defaultdict(lambda: defaultdict(list))
8989

9090
for message in messages:
91-
line = message.location.line
92-
msgs_grouped[message.location.path][-1 if line is None else line].append(
91+
msgs_grouped[message.location.path][message.location.line].append(
9392
message,
9493
)
9594

prospector/formatters/base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ def render(self, summary: bool = True, messages: bool = True, profile: bool = Fa
2828
raise NotImplementedError
2929

3030
def _make_path(self, location: Location) -> Path:
31-
return location.relative_path(self.paths_relative_to)
31+
path_ = location.relative_path(self.paths_relative_to)
32+
return Path() if path_ is None else path_
3233

3334
def _message_to_dict(self, message: Message) -> dict[str, Any]:
3435
loc = {

prospector/formatters/grouped.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from collections import defaultdict
22
from pathlib import Path
3+
from typing import Optional
34

45
from prospector.formatters.text import TextFormatter
56
from prospector.message import Message
@@ -15,10 +16,9 @@ def render_messages(self) -> str:
1516
"",
1617
]
1718

18-
groups: dict[Path, dict[int, list[Message]]] = defaultdict(lambda: defaultdict(list))
19+
groups: dict[Path, dict[Optional[int], list[Message]]] = defaultdict(lambda: defaultdict(list))
1920

2021
for message in self.messages:
21-
assert message.location.line is not None
2222
groups[self._make_path(message.location)][message.location.line].append(message)
2323

2424
for filename in sorted(groups.keys()):

prospector/formatters/pylint.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,26 @@ def render_messages(self) -> list[str]:
2828
# Missing function docstring
2929

3030
template_location = (
31-
"%(path)s"
31+
""
32+
if message.location.path is None
33+
else "%(path)s"
3234
if message.location.line is None
3335
else "%(path)s:%(line)s"
3436
if message.location.character is None
3537
else "%(path)s:%(line)s:%(character)s"
3638
)
3739
template_code = (
38-
"%(code)s(%(source)s)" if message.location.function is None else "[%(code)s(%(source)s), %(function)s]"
40+
"(%(source)s)"
41+
if message.code is None
42+
else "%(code)s(%(source)s)"
43+
if message.location.function is None
44+
else "[%(code)s(%(source)s), %(function)s]"
45+
)
46+
template = (
47+
f"{template_location}: {template_code}: %(message)s"
48+
if template_location
49+
else f"{template_code}: %(message)s"
3950
)
40-
template = f"{template_location}: {template_code}: %(message)s"
4151

4252
output.append(
4353
template

prospector/message.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33

44

55
class Location:
6+
_path: Optional[Path]
7+
68
def __init__(
79
self,
8-
path: Union[Path, str],
10+
path: Optional[Union[Path, str]],
911
module: Optional[str],
1012
function: Optional[str],
1113
line: Optional[int],
@@ -15,6 +17,8 @@ def __init__(
1517
self._path = path.absolute()
1618
elif isinstance(path, str):
1719
self._path = Path(path).absolute()
20+
elif path is None:
21+
self._path = None
1822
else:
1923
raise ValueError
2024
self.module = module or None
@@ -23,13 +27,15 @@ def __init__(
2327
self.character = None if character == -1 else character
2428

2529
@property
26-
def path(self) -> Path:
30+
def path(self) -> Optional[Path]:
2731
return self._path
2832

29-
def absolute_path(self) -> Path:
33+
def absolute_path(self) -> Optional[Path]:
3034
return self._path
3135

32-
def relative_path(self, root: Optional[Path]) -> Path:
36+
def relative_path(self, root: Optional[Path]) -> Optional[Path]:
37+
if self._path is None:
38+
return None
3339
return self._path.relative_to(root) if root else self._path
3440

3541
def __repr__(self) -> str:
@@ -46,6 +52,13 @@ def __eq__(self, other: object) -> bool:
4652
def __lt__(self, other: "Location") -> bool:
4753
if not isinstance(other, Location):
4854
raise ValueError
55+
56+
if self._path is None and other._path is None:
57+
return False
58+
if self._path is None:
59+
return True
60+
if other._path is None:
61+
return False
4962
if self._path == other._path:
5063
if self.line == other.line:
5164
return (self.character or -1) < (other.character or -1)

prospector/postfilter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def filter_messages(filepaths: List[Path], messages: List[Message]) -> List[Mess
2929
filtered = []
3030
for message in messages:
3131
# first get rid of the pylint informational messages
32-
relative_message_path = Path(message.location.path)
32+
relative_message_path = message.location.path
3333

3434
if message.source == "pylint" and message.code in (
3535
"suppressed-message",

prospector/suppression.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import warnings
2525
from collections import defaultdict
2626
from pathlib import Path
27+
from typing import Optional
2728

2829
from prospector import encoding
2930
from prospector.exceptions import FatalProspectorException
@@ -63,9 +64,11 @@ def get_noqa_suppressions(file_contents: list[str]) -> tuple[bool, set[int]]:
6364
}
6465

6566

66-
def _parse_pylint_informational(messages: list[Message]) -> tuple[set[Path], dict[Path, dict[int, list[str]]]]:
67-
ignore_files: set[Path] = set()
68-
ignore_messages: dict[Path, dict[int, list[str]]] = defaultdict(lambda: defaultdict(list))
67+
def _parse_pylint_informational(
68+
messages: list[Message],
69+
) -> tuple[set[Optional[Path]], dict[Optional[Path], dict[int, list[str]]]]:
70+
ignore_files: set[Optional[Path]] = set()
71+
ignore_messages: dict[Optional[Path], dict[int, list[str]]] = defaultdict(lambda: defaultdict(list))
6972

7073
for message in messages:
7174
if message.source == "pylint":
@@ -86,15 +89,15 @@ def _parse_pylint_informational(messages: list[Message]) -> tuple[set[Path], dic
8689

8790
def get_suppressions(
8891
filepaths: list[Path], messages: list[Message]
89-
) -> tuple[set[Path], dict[Path, set[int]], dict[Path, dict[int, set[tuple[str, str]]]]]:
92+
) -> tuple[set[Optional[Path]], dict[Path, set[int]], dict[Optional[Path], dict[int, set[tuple[str, str]]]]]:
9093
"""
9194
Given every message which was emitted by the tools, and the
9295
list of files to inspect, create a list of files to ignore,
9396
and a map of filepath -> line-number -> codes to ignore
9497
"""
95-
paths_to_ignore: set[Path] = set()
98+
paths_to_ignore: set[Optional[Path]] = set()
9699
lines_to_ignore: dict[Path, set[int]] = defaultdict(set)
97-
messages_to_ignore: dict[Path, dict[int, set[tuple[str, str]]]] = defaultdict(lambda: defaultdict(set))
100+
messages_to_ignore: dict[Optional[Path], dict[int, set[tuple[str, str]]]] = defaultdict(lambda: defaultdict(set))
98101

99102
# first deal with 'noqa' style messages
100103
for filepath in filepaths:
@@ -113,12 +116,12 @@ def get_suppressions(
113116
# now figure out which messages were suppressed by pylint
114117
pylint_ignore_files, pylint_ignore_messages = _parse_pylint_informational(messages)
115118
paths_to_ignore |= pylint_ignore_files
116-
for filepath, line in pylint_ignore_messages.items():
119+
for pylint_filepath, line in pylint_ignore_messages.items():
117120
for line_number, codes in line.items():
118121
for code in codes:
119-
messages_to_ignore[filepath][line_number].add(("pylint", code))
122+
messages_to_ignore[pylint_filepath][line_number].add(("pylint", code))
120123
if code in _PYLINT_EQUIVALENTS:
121124
for equivalent in _PYLINT_EQUIVALENTS[code]:
122-
messages_to_ignore[filepath][line_number].add(equivalent)
125+
messages_to_ignore[pylint_filepath][line_number].add(equivalent)
123126

124127
return paths_to_ignore, lines_to_ignore, messages_to_ignore

prospector/tools/ruff/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ def run(self, found_files: FileFinder) -> list[Message]:
4747
completed_process = subprocess.run( # noqa: S603
4848
[self.ruff_bin, *self.ruff_args, *found_files.python_modules], capture_output=True
4949
)
50+
if not completed_process.stdout:
51+
messages.append(
52+
Message(
53+
"ruff",
54+
"",
55+
Location(None, None, None, None, None),
56+
completed_process.stderr.decode(),
57+
)
58+
)
59+
return messages
5060
for message in json.loads(completed_process.stdout):
5161
sub_message = {}
5262
if message.get("url"):

tests/test_message.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ def test_strings_or_paths(self):
2525

2626
def test_bad_path_input(self):
2727
self.assertRaises(ValueError, Location, 3.2, "module", "func", 1, 2)
28-
self.assertRaises(ValueError, Location, None, "module", "func", 1, 2)
2928

3029

3130
class LocationOrderTest(TestCase):

0 commit comments

Comments
 (0)