Skip to content

Commit 47cae93

Browse files
AA-TurnerAdam Turner
andauthored
Emit end line/column in JSON format for span tracking (#20734)
Recently, mypy gained the ability to output errors/notes as structured data in JSON format. This data, though, lacks the `end_line` and `end_column` information from mypy's `ErrorTuple`, which makes it harder to use for e.g. IDE integrations. This is a fairly simple PR to just expose those fields in the JSON. I updated the constructor of `MypyError` to put the new arguments in the middle rather than at the end because I understand that this is an internal type, so we're free to make changes like this -- please correct me if I'm wrong here. I just updated the existing tests rather than adding new ones, hopefully this is fine! A cc @JelleZijlstra as reviewer of #11396 Co-authored-by: Adam Turner <turner@hudson-trading.com>
1 parent ab5fe7f commit 47cae93

File tree

4 files changed

+25
-8
lines changed

4 files changed

+25
-8
lines changed

mypy/error_formatter.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def report_error(self, error: "MypyError") -> str:
2626
"file": error.file_path,
2727
"line": error.line,
2828
"column": error.column,
29+
"end_line": error.end_line,
30+
"end_column": error.end_column,
2931
"message": error.message,
3032
"hint": None if len(error.hints) == 0 else "\n".join(error.hints),
3133
"code": None if error.errorcode is None else error.errorcode.code,

mypy/errors.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,13 +1480,17 @@ def __init__(
14801480
file_path: str,
14811481
line: int,
14821482
column: int,
1483+
end_line: int,
1484+
end_column: int,
14831485
message: str,
14841486
errorcode: ErrorCode | None,
14851487
severity: Literal["error", "note"],
14861488
) -> None:
14871489
self.file_path = file_path
14881490
self.line = line
14891491
self.column = column
1492+
self.end_line = end_line
1493+
self.end_column = end_column
14901494
self.message = message
14911495
self.errorcode = errorcode
14921496
self.severity = severity
@@ -1502,7 +1506,7 @@ def create_errors(error_tuples: list[ErrorTuple]) -> list[MypyError]:
15021506
latest_error_at_location: dict[_ErrorLocation, MypyError] = {}
15031507

15041508
for error_tuple in error_tuples:
1505-
file_path, line, column, _, _, severity, message, errorcode = error_tuple
1509+
file_path, line, column, end_line, end_column, severity, message, errorcode = error_tuple
15061510
if file_path is None:
15071511
continue
15081512

@@ -1512,14 +1516,25 @@ def create_errors(error_tuples: list[ErrorTuple]) -> list[MypyError]:
15121516
error = latest_error_at_location.get(error_location)
15131517
if error is None:
15141518
# This is purely a note, with no error correlated to it
1515-
error = MypyError(file_path, line, column, message, errorcode, severity="note")
1519+
error = MypyError(
1520+
file_path,
1521+
line,
1522+
column,
1523+
end_line,
1524+
end_column,
1525+
message,
1526+
errorcode,
1527+
severity="note",
1528+
)
15161529
errors.append(error)
15171530
continue
15181531

15191532
error.hints.append(message)
15201533

15211534
else:
1522-
error = MypyError(file_path, line, column, message, errorcode, severity="error")
1535+
error = MypyError(
1536+
file_path, line, column, end_line, end_column, message, errorcode, severity="error"
1537+
)
15231538
errors.append(error)
15241539
error_location = (file_path, line, column)
15251540
latest_error_at_location[error_location] = error

test-data/unit/check-incremental.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7655,7 +7655,7 @@ def wrong() -> int:
76557655
[out]
76567656
main:2: error: Missing return statement
76577657
[out2]
7658-
{"file": "main", "line": 2, "column": 0, "message": "Missing return statement", "hint": null, "code": "return", "severity": "error"}
7658+
{"file": "main", "line": 2, "column": 0, "end_line": 4, "end_column": 16, "message": "Missing return statement", "hint": null, "code": "return", "severity": "error"}
76597659

76607660
[case testReExportAllInStubIncremental]
76617661
from m1 import C

test-data/unit/outputjson.test

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def foo() -> None:
1818

1919
foo(1)
2020
[out]
21-
{"file": "main", "line": 5, "column": 0, "message": "Too many arguments for \"foo\"", "hint": null, "code": "call-arg", "severity": "error"}
21+
{"file": "main", "line": 5, "column": 0, "end_line": 5, "end_column": 6, "message": "Too many arguments for \"foo\"", "hint": null, "code": "call-arg", "severity": "error"}
2222

2323
[case testOutputJsonWithHint]
2424
# flags: --output=json
@@ -39,6 +39,6 @@ foo('42')
3939
def bar() -> None: ...
4040
bar('42')
4141
[out]
42-
{"file": "main", "line": 12, "column": 12, "message": "Revealed type is \"Overload(def (), def (x: builtins.int))\"", "hint": null, "code": "misc", "severity": "note"}
43-
{"file": "main", "line": 14, "column": 0, "message": "No overload variant of \"foo\" matches argument type \"str\"", "hint": "Possible overload variants:\n def foo() -> None\n def foo(x: int) -> None", "code": "call-overload", "severity": "error"}
44-
{"file": "main", "line": 17, "column": 0, "message": "Too many arguments for \"bar\"", "hint": null, "code": "call-arg", "severity": "error"}
42+
{"file": "main", "line": 12, "column": 12, "end_line": 12, "end_column": 15, "message": "Revealed type is \"Overload(def (), def (x: builtins.int))\"", "hint": null, "code": "misc", "severity": "note"}
43+
{"file": "main", "line": 14, "column": 0, "end_line": 14, "end_column": 9, "message": "No overload variant of \"foo\" matches argument type \"str\"", "hint": "Possible overload variants:\n def foo() -> None\n def foo(x: int) -> None", "code": "call-overload", "severity": "error"}
44+
{"file": "main", "line": 17, "column": 0, "end_line": 17, "end_column": 9, "message": "Too many arguments for \"bar\"", "hint": null, "code": "call-arg", "severity": "error"}

0 commit comments

Comments
 (0)