Skip to content

Commit fe1e571

Browse files
authored
Add a note on variable annotation within unchecked function (#13851)
Closes #3948 This however gives a note instead of an error, so that type checking result will be success. I also added an error code for the note so that people can opt-out if they want to.
1 parent 56258a6 commit fe1e571

10 files changed

+35
-8
lines changed

mypy/checker.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2643,6 +2643,9 @@ def visit_assignment_stmt(self, s: AssignmentStmt) -> None:
26432643
):
26442644
self.fail(message_registry.DEPENDENT_FINAL_IN_CLASS_BODY, s)
26452645

2646+
if s.unanalyzed_type and not self.in_checked_function():
2647+
self.msg.annotation_in_unchecked_function(context=s)
2648+
26462649
def check_type_alias_rvalue(self, s: AssignmentStmt) -> None:
26472650
if not (self.is_stub and isinstance(s.rvalue, OpExpr) and s.rvalue.op == "|"):
26482651
# We do this mostly for compatibility with old semantic analyzer.

mypy/errorcodes.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ def __str__(self) -> str:
137137
UNREACHABLE: Final = ErrorCode(
138138
"unreachable", "Warn about unreachable statements or expressions", "General"
139139
)
140+
ANNOTATION_UNCHECKED = ErrorCode(
141+
"annotation-unchecked", "Notify about type annotations in unchecked functions", "General"
142+
)
140143
PARTIALLY_DEFINED: Final[ErrorCode] = ErrorCode(
141144
"partially-defined",
142145
"Warn about variables that are defined only in some execution paths",

mypy/messages.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,14 @@ def add_fixture_note(self, fullname: str, ctx: Context) -> None:
21482148
ctx,
21492149
)
21502150

2151+
def annotation_in_unchecked_function(self, context: Context) -> None:
2152+
self.note(
2153+
"By default the bodies of untyped functions are not checked,"
2154+
" consider using --check-untyped-defs",
2155+
context,
2156+
code=codes.ANNOTATION_UNCHECKED,
2157+
)
2158+
21512159

21522160
def quote_type_string(type_string: str) -> str:
21532161
"""Quotes a type representation for use in messages."""

test-data/unit/check-classes.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,7 +1189,7 @@ reveal_type(Foo().Meta.name) # N: Revealed type is "builtins.str"
11891189

11901190
class A:
11911191
def __init__(self):
1192-
self.x = None # type: int
1192+
self.x = None # type: int # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs
11931193
a = None # type: A
11941194
a.x = 1
11951195
a.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
@@ -1201,7 +1201,7 @@ a.x = 1
12011201
a.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
12021202
class A:
12031203
def __init__(self):
1204-
self.x = None # type: int
1204+
self.x = None # type: int # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs
12051205

12061206

12071207
-- Special cases

test-data/unit/check-dataclasses.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1641,7 +1641,7 @@ A(a=func).a = func # E: Property "a" defined in "A" is read-only
16411641
# flags: --python-version 3.7
16421642
from dataclasses import dataclass
16431643

1644-
def foo():
1644+
def foo() -> None:
16451645
@dataclass
16461646
class Foo:
16471647
foo: int

test-data/unit/check-errorcodes.test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,3 +964,8 @@ class C(abc.ABC):
964964
T = TypeVar("T")
965965
def test(tp: Type[T]) -> T: ...
966966
test(C) # E: Only concrete class can be given where "Type[C]" is expected [type-abstract]
967+
968+
[case testUncheckedAnnotationSuppressed]
969+
# flags: --disable-error-code=annotation-unchecked
970+
def f():
971+
x: int = "no" # No warning here

test-data/unit/check-incremental.test

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3544,11 +3544,11 @@ class Bar(Baz): pass
35443544

35453545
[file c.py]
35463546
class Baz:
3547-
def __init__(self):
3547+
def __init__(self) -> None:
35483548
self.x = 12 # type: int
35493549
[file c.py.2]
35503550
class Baz:
3551-
def __init__(self):
3551+
def __init__(self) -> None:
35523552
self.x = 'lol' # type: str
35533553
[out]
35543554
[out2]
@@ -5730,6 +5730,7 @@ class C:
57305730
tmp/a.py:2: error: "object" has no attribute "xyz"
57315731

57325732
[case testIncrementalInvalidNamedTupleInUnannotatedFunction]
5733+
# flags: --disable-error-code=annotation-unchecked
57335734
import a
57345735

57355736
[file a.py]

test-data/unit/check-inference-context.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ if int():
814814
from typing import List
815815
class A:
816816
def __init__(self):
817-
self.x = [] # type: List[int]
817+
self.x = [] # type: List[int] # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs
818818
a = A()
819819
a.x = []
820820
a.x = [1]

test-data/unit/check-newsemanal.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2963,6 +2963,7 @@ def g() -> None:
29632963
reveal_type(y) # N: Revealed type is "__main__.G[Any]"
29642964

29652965
[case testNewAnalyzerRedefinedNonlocal]
2966+
# flags: --disable-error-code=annotation-unchecked
29662967
import typing
29672968

29682969
def f():
@@ -2977,7 +2978,7 @@ def g() -> None:
29772978

29782979
def foo() -> None:
29792980
nonlocal bar
2980-
bar = [] # type: typing.List[int] # E: Name "bar" already defined on line 11
2981+
bar = [] # type: typing.List[int] # E: Name "bar" already defined on line 12
29812982
[builtins fixtures/list.pyi]
29822983

29832984
[case testNewAnalyzerMoreInvalidTypeVarArgumentsDeferred]

test-data/unit/check-statements.test

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2186,7 +2186,7 @@ N = TypedDict('N', {'x': int})
21862186
[out]
21872187

21882188
[case testGlobalWithoutInitialization]
2189-
2189+
# flags: --disable-error-code=annotation-unchecked
21902190
from typing import List
21912191

21922192
def foo() -> None:
@@ -2200,3 +2200,9 @@ def foo2():
22002200
bar2 = [] # type: List[str]
22012201
bar2
22022202
[builtins fixtures/list.pyi]
2203+
2204+
[case testNoteUncheckedAnnotation]
2205+
def foo():
2206+
x: int = "no" # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs
2207+
y = "no" # type: int # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs
2208+
z: int # N: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs

0 commit comments

Comments
 (0)