diff --git a/mypy/test/data.py b/mypy/test/data.py index 5b0ad84c0ba7..22c39af04ec1 100644 --- a/mypy/test/data.py +++ b/mypy/test/data.py @@ -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\d+):)? (?P.*)$", possible_err_comment.strip() + r"^([ENW])\s*:((?P\d+):)?(?P.*)$", possible_err_comment.strip() ) if m: if m.group(1) == "E": @@ -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: diff --git a/mypy/test/update_data.py b/mypy/test/update_data.py index 84b6383b3f0c..9269d3380543 100644 --- a/mypy/test/update_data.py +++ b/mypy/test/update_data.py @@ -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\s+)(?P# [EWN]: .+)$", source_line) + comment_match = re.search(r"(?P\s*)(?P#\s*[EWN]\s*:.+)$", source_line) if comment_match: source_line = source_line[: comment_match.start("indent")] # strip old comment if reports: diff --git a/test-data/unit/README.md b/test-data/unit/README.md index aaf774d1b62f..1ca66a60caac 100644 --- a/test-data/unit/README.md +++ b/test-data/unit/README.md @@ -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 diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index f713fe69bcd2..a9f81e54d5a6 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -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 diff --git a/test-data/unit/check-deprecated.test b/test-data/unit/check-deprecated.test index e1173ac425ba..0ceb3ce4a2c4 100644 --- a/test-data/unit/check-deprecated.test +++ b/test-data/unit/check-deprecated.test @@ -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 \ diff --git a/test-data/unit/check-error-comments.test b/test-data/unit/check-error-comments.test new file mode 100644 index 000000000000..948f7660fa59 --- /dev/null +++ b/test-data/unit/check-error-comments.test @@ -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") diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index 61bf08018722..a7564e476804 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -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] diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index 5bbb503a578a..e917e83e004b 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -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" @@ -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 diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index be5a6c655d8c..6676d23f087d 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -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]