Skip to content

Update update_data.py: make the space in error comments optional #19546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions mypy/test/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,9 +533,9 @@ def expand_errors(input: list[str], output: list[str], fnam: str) -> None:

for i in range(len(input)):
# The first in the split things isn't a comment
for possible_err_comment in input[i].split(" # ")[1:]:
for possible_err_comment in re.split(r"(?!\\)#\s*(?=[ENW]\s*:)", input[i])[1:]:
m = re.search(
r"^([ENW]):((?P<col>\d+):)? (?P<message>.*)$", possible_err_comment.strip()
r"^([ENW])\s*:((?P<col>\d+):)?(?P<message>.*)$", possible_err_comment.strip()
)
if m:
if m.group(1) == "E":
Expand All @@ -546,11 +546,12 @@ def expand_errors(input: list[str], output: list[str], fnam: str) -> None:
severity = "warning"
col = m.group("col")
message = m.group("message")
message = message.replace("\\#", "#") # adds back escaped # character
message = message.replace(r"\#", "#") # adds back escaped # character
# Message may, and probably does, include leading spaces
if col is None:
output.append(f"{fnam}:{i + 1}: {severity}: {message}")
output.append(f"{fnam}:{i + 1}: {severity}:{message}")
else:
output.append(f"{fnam}:{i + 1}:{col}: {severity}: {message}")
output.append(f"{fnam}:{i + 1}:{col}: {severity}:{message}")


def fix_win_path(line: str) -> str:
Expand Down
2 changes: 1 addition & 1 deletion mypy/test/update_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def _iter_fixes(
fix_lines = []
for lineno, source_line in enumerate(source_lines, start=1):
reports = reports_by_line.get((file_path, lineno))
comment_match = re.search(r"(?P<indent>\s+)(?P<comment># [EWN]: .+)$", source_line)
comment_match = re.search(r"(?P<indent>\s*)(?P<comment>#\s*[EWN]\s*:.+)$", source_line)
if comment_match:
source_line = source_line[: comment_match.start("indent")] # strip old comment
if reports:
Expand Down
16 changes: 11 additions & 5 deletions test-data/unit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,23 @@ with text "abc..."
- note a space after `E:` and `flags:`
- `# E:12` adds column number to the expected error
- use `\` to escape the `#` character and indicate that the rest of the line is part of
the error message
the error message (note that there is no support for using `\\` to escape a backslash itself
in this context; also, in all other contexts, such as line-continuation, the backslash is treated
as it normally would be in a python source file)
- repeating `# E: ` several times in one line indicates multiple expected errors in one line
- `W: ...` and `N: ...` works exactly like `E: ...`, but report a warning and a note respectively
- lines that don't contain the above should cause no type check errors
- lines that begin with `--` are test-file-format comments, and will not appear in the tested python
source code
- some test files are run in a special way by the test runner; this is typically documented in
test-file-format comments at the top of the test file
- optional `[builtins fixtures/...]` tells the type checker to use
`builtins` stubs from the indicated file (see Fixtures section below)
- optional `[out]` is an alternative to the `# E: ` notation: it indicates that
any text after it contains the expected type checking error messages.
Usually, `# E: ` is preferred because it makes it easier to associate the
errors with the code generating them at a glance, and to change the code of
the test without having to change line numbers in `[out]`
any text after it contains the expected type checking error messages.
Usually, `# E: ` is preferred because it makes it easier to associate the
errors with the code generating them at a glance, and to change the code of
the test without having to change line numbers in `[out]`
- an empty `[out]` section has no effect
- to add tests for a feature that hasn't been implemented yet, append `-xfail`
to the end of the test name
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ class A:
def __replace__(self, x: Optional[str]) -> Self: pass

class B(A):
def __replace__(self, x: str) -> Self: pass # E: \
def __replace__(self, x: str) -> Self: pass \
# E: Argument 1 of "__replace__" is incompatible with supertype "A"; supertype defines the argument type as "Optional[str]" [override] \
# N: This violates the Liskov substitution principle \
# N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
Expand Down
3 changes: 2 additions & 1 deletion test-data/unit/check-deprecated.test
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ from typing_extensions import deprecated
@deprecated("use f2 instead")
def f() -> None: ...

f # E: function __main__.f is deprecated: use f2 instead # type: ignore[deprecated]
f # type: ignore[deprecated]
f # E: function __main__.f is deprecated: use f2 instead
f(1) # E: function __main__.f is deprecated: use f2 instead \
# E: Too many arguments for "f"
f[1] # E: function __main__.f is deprecated: use f2 instead \
Expand Down
49 changes: 49 additions & 0 deletions test-data/unit/check-error-comments.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[case noErrorComment]
x: int = 1

[case prototypicalErrorComment]
x: int = "hi" # E: Incompatible types in assignment (expression has type "str", variable has type "int")

[case emptyLineErrorComment-xfail]
# E:

[case oddErrorComments]
x: int = "hi"#E: Incompatible types in assignment (expression has type "str", variable has type "int")
x2: int = "hi" #E: Incompatible types in assignment (expression has type "str", variable has type "int")
x3: int = "hi" # E: Incompatible types in assignment (expression has type "str", variable has type "int")
x4: int = "hi" # E : Incompatible types in assignment (expression has type "str", variable has type "int")
x5: int = "hi" # E : Incompatible types in assignment (expression has type "str", variable has type "int")
x6: int = "hi" # E : Incompatible types in assignment (expression has type "str", variable has type "int")
x7: int = "hi" # E : Incompatible types in assignment (expression has type "str", variable has type "int")
x8: int = "hi" \
# E : Incompatible types in assignment (expression has type "str", variable has type "int")
x82: int = "hi"\
# E : Incompatible types in assignment (expression has type "str", variable has type "int")

[case oddErrorCommentsNoteComment]
n: int
reveal_type(n) # N: Revealed type is "builtins.int"


[case oddErrorCommentsThatDontWork-xfail]
-- The space between the ":" and the message actually differs in the output, which we match against
-- so we can't just parse it and replace it; therefore, these do not work.
x: int = "hi"#E:Incompatible types in assignment (expression has type "str", variable has type "int")
x2: int = "hi" #E:Incompatible types in assignment (expression has type "str", variable has type "int")
x3: int = "hi" # E : Incompatible types in assignment (expression has type "str", variable has type "int")
x4: int = "hi" # E : Incompatible types in assignment (expression has type "str", variable has type "int")
x5: int = "hi" # E : Incompatible types in assignment (expression has type "str", variable has type "int")

[case oddErrorCommentsThatDontWorkCase-xfail]
-- I just didn't bother to implement these.
x: int = "hi" # e: Incompatible types in assignment (expression has type "str", variable has type "int")
x: int = "hi" # w: Incompatible types in assignment (expression has type "str", variable has type "int")
x: int = "hi" # n: Incompatible types in assignment (expression has type "str", variable has type "int")


[case oddErrorCommentsThatDontWorkCaseAndNoColon-xfail]
-- I didn't implement these. This is veering towards the ambiguous.
x: int = "hi" # e: Incompatible types in assignment (expression has type "str", variable has type "int")
x2: int = "hi" # E Incompatible types in assignment (expression has type "str", variable has type "int")
x3: int = "hi" # e Incompatible types in assignment (expression has type "str", variable has type "int")
x4: int = "hi" # e Incompatible types in assignment (expression has type "str", variable has type "int")
2 changes: 1 addition & 1 deletion test-data/unit/check-newsemanal.test
Original file line number Diff line number Diff line change
Expand Up @@ -2684,7 +2684,7 @@ class C:
) -> str:
return 0 # E: Incompatible return value type (got "int", expected "str")

reveal_type(C.X) # E: # N: Revealed type is "def () -> __main__.X"
reveal_type(C.X) # N: Revealed type is "def () -> __main__.X"
reveal_type(C().str()) # N: Revealed type is "builtins.str"

[case testNewAnalyzerNameNotDefinedYetInClassBody]
Expand Down
17 changes: 11 additions & 6 deletions test-data/unit/check-type-aliases.test
Original file line number Diff line number Diff line change
Expand Up @@ -551,12 +551,7 @@ def take_id(x: Id[int]) -> None:
def id(x: Id[T]) -> T:
return x

# TODO: This doesn't work and maybe it should?
# Indirection = AnInt[T]
# y: Indirection[str]
# reveal_type(y) # E : Revealed type is "builtins.int"

# But this does
# Contrast with the TODO below
Indirection2 = FlexibleAlias[T, AnInt[T]]
z: Indirection2[str]
reveal_type(z) # N: Revealed type is "builtins.int"
Expand All @@ -567,6 +562,16 @@ reveal_type(w) # N: Revealed type is "builtins.int"

[builtins fixtures/dict.pyi]

[case testFlexibleAlias1Todo-xfail]
# TODO: This doesn't work and maybe it should?
# Contrast with the example above that mentions this todo
T = TypeVar('T')
AnInt = FlexibleAlias[T, int]
Indirection = AnInt[T]
y: Indirection[str]
reveal_type(y) # N : Revealed type is "builtins.int"


[case testFlexibleAlias2]
# flags: --always-true=BOGUS
from typing import TypeVar, Any
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-typeddict.test
Original file line number Diff line number Diff line change
Expand Up @@ -3652,7 +3652,7 @@ reveal_type(X) # N: Revealed type is "builtins.dict[builtins.str, def () -> bui
from typing_extensions import TypeAlias
X: TypeAlias = {"int": int, "str": str}
x: X
reveal_type(x) # N: # N: Revealed type is "TypedDict({'int': builtins.int, 'str': builtins.str})"
reveal_type(x) # N: Revealed type is "TypedDict({'int': builtins.int, 'str': builtins.str})"
[builtins fixtures/dict.pyi]
[typing fixtures/typing-typeddict.pyi]

Expand Down