Skip to content

Commit a4fe1e2

Browse files
authored
Merge pull request #41 from patrick91/feature/error-codes
Add error code to Mypy message
2 parents b98868b + a8ff757 commit a4fe1e2

File tree

5 files changed

+37
-19
lines changed

5 files changed

+37
-19
lines changed

mypy_silent/cli.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from mypy_silent.maho import add_type_ignore_comment
77
from mypy_silent.maho import remove_type_ignore_comment
88
from mypy_silent.parser import FilePosition
9-
from mypy_silent.parser import get_info_form_mypy_output
9+
from mypy_silent.parser import get_info_from_mypy_output
1010
from mypy_silent.parser import UNUSED_IGNORE_MESSAGES
1111
from mypy_silent.utils import get_lines
1212

@@ -17,7 +17,7 @@ def mypy_silent(
1717
),
1818
) -> None:
1919
lines = get_lines(mypy_output_file)
20-
infos = get_info_form_mypy_output(lines)
20+
infos = get_info_from_mypy_output(lines)
2121
processed: Set[FilePosition] = set()
2222
for info in infos:
2323
if info.position in processed:
@@ -29,7 +29,7 @@ def mypy_silent(
2929
if info.message in UNUSED_IGNORE_MESSAGES:
3030
new_content = remove_type_ignore_comment(old_content)
3131
else:
32-
new_content = add_type_ignore_comment(old_content)
32+
new_content = add_type_ignore_comment(old_content, error_code=info.error_code)
3333
file_contents[info.position.line - 1] = new_content
3434
with open(info.position.filename, "w") as f:
3535
f.writelines(file_contents)

mypy_silent/maho.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1-
def add_type_ignore_comment(line: str) -> str:
1+
from typing import Optional
2+
3+
4+
def add_type_ignore_comment(line: str, error_code: Optional[str]) -> str:
25
# Workarounds for https://mypy.readthedocs.io/en/stable/common_issues.html#silencing-linters
6+
7+
type_ignore_comment = "# type: ignore"
8+
9+
if error_code:
10+
type_ignore_comment += f"[{error_code}]"
11+
312
if "# noqa" in line:
4-
return line.replace("# noqa", "# type: ignore # noqa", 1)
13+
return line.replace("# noqa", f"{type_ignore_comment} # noqa", 1)
514
content_without_crlf = line.rstrip("\r\n")
6-
return content_without_crlf + " # type: ignore" + line[len(content_without_crlf) :]
15+
return content_without_crlf + f" {type_ignore_comment}" + line[len(content_without_crlf) :]
716

817

918
def remove_type_ignore_comment(line: str) -> str:

mypy_silent/parser.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
from typing import FrozenSet
33
from typing import Iterable
44
from typing import NamedTuple
5+
from typing import Optional
56

67
from typing_extensions import Final
78

8-
UNUSED_IGNORE_MESSAGES: Final[FrozenSet[str]] = frozenset(
9-
{"error: unused 'type: ignore' comment", 'error: unused "type: ignore" comment'}
10-
)
9+
UNUSED_IGNORE_MESSAGES: Final[FrozenSet[str]] = frozenset({"error: unused 'type: ignore' comment", 'error: unused "type: ignore" comment'})
1110

1211

1312
class FilePosition(NamedTuple):
@@ -18,20 +17,22 @@ class FilePosition(NamedTuple):
1817
class MypyMessage(NamedTuple):
1918
position: FilePosition
2019
message: str
20+
error_code: Optional[str]
2121

2222

23-
_mypy_output_re = re.compile(r"^([^:]+):(\d+):(.+)$")
23+
_mypy_output_re = re.compile(r"^(?P<filename>[^:]+):(?P<line>\d+):(?P<message>.+?)(\[(?P<error_code>[a-z-]+)\])?$")
2424

2525

26-
def get_info_form_mypy_output(lines: Iterable[str]) -> Iterable[MypyMessage]:
26+
def get_info_from_mypy_output(lines: Iterable[str]) -> Iterable[MypyMessage]:
2727
for line in lines:
2828
line = line.strip()
2929
match = _mypy_output_re.match(line)
3030
if match:
3131
yield MypyMessage(
3232
position=FilePosition(
33-
filename=match.group(1).strip(),
34-
line=int(match.group(2)),
33+
filename=match.group("filename").strip(),
34+
line=int(match.group("line")),
3535
),
36-
message=match.group(3).strip(),
36+
message=match.group("message").strip(),
37+
error_code=match.group("error_code"),
3738
)

tests/test_maho.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
),
1616
)
1717
def test_add_type_ignore_comment(input: str, output: str) -> None:
18-
assert add_type_ignore_comment(input) == output
18+
assert add_type_ignore_comment(input, error_code=None) == output
19+
20+
21+
def test_add_type_ignore_comment_with_error_code() -> None:
22+
input = "host, port, protocol = m.groups()\r\n"
23+
output = "host, port, protocol = m.groups() # type: ignore[misc]\r\n"
24+
assert add_type_ignore_comment(input, error_code="misc") == output
1925

2026

2127
@pytest.mark.parametrize(

tests/test_parser.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
from mypy_silent.parser import FilePosition
6-
from mypy_silent.parser import get_info_form_mypy_output
6+
from mypy_silent.parser import get_info_from_mypy_output
77
from mypy_silent.parser import MypyMessage
88

99

@@ -14,20 +14,22 @@
1414
(
1515
[
1616
"utils/template.py:49: error: Cannot assign to a method",
17-
"utils/template.py:53: error: Statement is unreachable",
17+
"utils/template.py:53: error: Statement is unreachable [unreachable]",
1818
],
1919
[
2020
MypyMessage(
2121
position=FilePosition(filename="utils/template.py", line=49),
2222
message="error: Cannot assign to a method",
23+
error_code=None,
2324
),
2425
MypyMessage(
2526
position=FilePosition(filename="utils/template.py", line=53),
2627
message="error: Statement is unreachable",
28+
error_code="unreachable",
2729
),
2830
],
2931
),
3032
),
3133
)
32-
def test_get_info_form_mypy_output(input: List[str], output: List[MypyMessage]) -> None:
33-
assert list(get_info_form_mypy_output(input)) == output
34+
def test_get_info_from_mypy_output(input: List[str], output: List[MypyMessage]) -> None:
35+
assert list(get_info_from_mypy_output(input)) == output

0 commit comments

Comments
 (0)