diff --git a/mypy/checker.py b/mypy/checker.py index 229c1f087228..16bbc1c982a6 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -2643,6 +2643,9 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None: ): self.fail(message_registry.DEPENDENT_FINAL_IN_CLASS_BODY, s) + if s.unanalyzed_type and not self.in_checked_function(): + self.msg.annotation_in_unchecked_function(context=s) + def check_type_alias_rvalue(self, s: AssignmentStmt) -> None: if not (self.is_stub and isinstance(s.rvalue, OpExpr) and s.rvalue.op == "|"): # We do this mostly for compatibility with old semantic analyzer. diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index 0d6a328693d4..fd0ee619a47d 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -137,6 +137,9 @@ def __str__(self) -> str: UNREACHABLE: Final = ErrorCode( "unreachable", "Warn about unreachable statements or expressions", "General" ) +ANNOTATION_UNCHECKED = ErrorCode( + "annotation-unchecked", "Notify about type annotations in unchecked functions", "General" +) PARTIALLY_DEFINED: Final[ErrorCode] = ErrorCode( "partially-defined", "Warn about variables that are defined only in some execution paths", diff --git a/mypy/messages.py b/mypy/messages.py index f3aa1898bfd8..75e5134d1242 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -2148,6 +2148,14 @@ def add_fixture_note(self, fullname: str, ctx: Context) -> None: ctx, ) + def annotation_in_unchecked_function(self, context: Context) -> None: + self.note( + "By default the bodies of untyped functions are not checked," + " consider using --check-untyped-defs", + context, + code=codes.ANNOTATION_UNCHECKED, + ) + def quote_type_string(type_string: str) -> str: """Quotes a type representation for use in messages.""" diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index ae7d02f9edfc..b16387f194d4 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -1189,7 +1189,7 @@ reveal_type(Foo().Meta.name) # N: Revealed type is "builtins.str" class A: def __init__(self): - self.x = None # type: int + self.x = None # type: int # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs a = None # type: A a.x = 1 a.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int") @@ -1201,7 +1201,7 @@ a.x = 1 a.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int") class A: def __init__(self): - self.x = None # type: int + self.x = None # type: int # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs -- Special cases diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 4b2ff1af2151..3ec4c60e6929 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -1641,7 +1641,7 @@ A(a=func).a = func # E: Property "a" defined in "A" is read-only # flags: --python-version 3.7 from dataclasses import dataclass -def foo(): +def foo() -> None: @dataclass class Foo: foo: int diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 4cd8e58f037d..ceae45956069 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -964,3 +964,8 @@ class C(abc.ABC): T = TypeVar("T") def test(tp: Type[T]) -> T: ... test(C) # E: Only concrete class can be given where "Type[C]" is expected [type-abstract] + +[case testUncheckedAnnotationSuppressed] +# flags: --disable-error-code=annotation-unchecked +def f(): + x: int = "no" # No warning here diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index ac005001b135..b258c57b961c 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -3544,11 +3544,11 @@ class Bar(Baz): pass [file c.py] class Baz: - def __init__(self): + def __init__(self) -> None: self.x = 12 # type: int [file c.py.2] class Baz: - def __init__(self): + def __init__(self) -> None: self.x = 'lol' # type: str [out] [out2] @@ -5730,6 +5730,7 @@ class C: tmp/a.py:2: error: "object" has no attribute "xyz" [case testIncrementalInvalidNamedTupleInUnannotatedFunction] +# flags: --disable-error-code=annotation-unchecked import a [file a.py] diff --git a/test-data/unit/check-inference-context.test b/test-data/unit/check-inference-context.test index 3bab79f5aec2..2e26f54c6e93 100644 --- a/test-data/unit/check-inference-context.test +++ b/test-data/unit/check-inference-context.test @@ -814,7 +814,7 @@ if int(): from typing import List class A: def __init__(self): - self.x = [] # type: List[int] + self.x = [] # type: List[int] # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs a = A() a.x = [] a.x = [1] diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index a52be03e31ce..97cf1ef1494d 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -2963,6 +2963,7 @@ def g() -> None: reveal_type(y) # N: Revealed type is "__main__.G[Any]" [case testNewAnalyzerRedefinedNonlocal] +# flags: --disable-error-code=annotation-unchecked import typing def f(): @@ -2977,7 +2978,7 @@ def g() -> None: def foo() -> None: nonlocal bar - bar = [] # type: typing.List[int] # E: Name "bar" already defined on line 11 + bar = [] # type: typing.List[int] # E: Name "bar" already defined on line 12 [builtins fixtures/list.pyi] [case testNewAnalyzerMoreInvalidTypeVarArgumentsDeferred] diff --git a/test-data/unit/check-statements.test b/test-data/unit/check-statements.test index 9b571cb20c0d..4be5060996e2 100644 --- a/test-data/unit/check-statements.test +++ b/test-data/unit/check-statements.test @@ -2186,7 +2186,7 @@ N = TypedDict('N', {'x': int}) [out] [case testGlobalWithoutInitialization] - +# flags: --disable-error-code=annotation-unchecked from typing import List def foo() -> None: @@ -2200,3 +2200,9 @@ def foo2(): bar2 = [] # type: List[str] bar2 [builtins fixtures/list.pyi] + +[case testNoteUncheckedAnnotation] +def foo(): + x: int = "no" # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs + y = "no" # type: int # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs + z: int # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs