Enable local partial types by default
Local partial types prevent inferring the variable type from two
separate scopes. For example, this is no longer accepted:
```
class A:
x = [] # Need type annotation here
def f(self) -> None:
self.x.append(1)
```
Also, initialization with just `None` is usually not allowed and
requires a type annotation:
```
x = None # Error
y: None = None # OK
z: Optional[str] = None # OK
```
The mypy daemon only supports local partial types. This makes the
daemon and non-daemon modes behave consistently.
Add the `--no-local-partial-types` flag to revert to the old behavior.
Also make local partial types behavior closer to the old behavior
in a few cases:
- allow `x = f(...)` even if the return type of `f(...)` is `None` when
`f` is generic
- allow `x = None` in an enum class body
- allor for loop index variable to have an inferred `None` type
diff --git a/mypy/checker.py b/mypy/checker.py
index fce7e7d..772ab8b 100644
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -133,9 +133,9 @@
('is_upper_bound', bool), # False => precise type
])
-# Keeps track of partial types in a single scope. In fine-grained incremental
-# mode partial types initially defined at the top level cannot be completed in
-# a function, and we use the 'is_function' attribute to enforce this.
+# Keeps track of partial types in a single scope. By default, partial
+# types initially defined at the top level cannot be completed in a
+# function, and we use the 'is_function' attribute to enforce this.
PartialTypeScope = NamedTuple('PartialTypeScope', [('map', Dict[Var, Context]),
('is_function', bool),
('is_local', bool),
@@ -1715,7 +1715,8 @@
for base in typ.mro[1:]:
if base.is_final:
self.fail(message_registry.CANNOT_INHERIT_FROM_FINAL.format(base.name), defn)
- with self.tscope.class_scope(defn.info), self.enter_partial_types(is_class=True):
+ with self.tscope.class_scope(typ), self.enter_partial_types(is_class=True,
+ is_enum=typ.is_enum):
old_binder = self.binder
self.binder = ConditionalTypeBinder()
with self.binder.top_frame_context():
@@ -2042,11 +2043,11 @@
self.fail(message_registry.DEPENDENT_FINAL_IN_CLASS_BODY, s)
def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type: bool = True,
- new_syntax: bool = False) -> None:
+ new_syntax: bool = False, *, for_stmt: bool = False) -> None:
"""Type check a single assignment: lvalue = rvalue."""
if isinstance(lvalue, TupleExpr) or isinstance(lvalue, ListExpr):
self.check_assignment_to_multiple_lvalues(lvalue.items, rvalue, rvalue,
- infer_lvalue_type)
+ infer_lvalue_type, for_stmt=for_stmt)
else:
self.try_infer_partial_generic_type_from_assignment(lvalue, rvalue, '=')
lvalue_type, index_lvalue, inferred = self.check_lvalue(lvalue)
@@ -2082,7 +2083,7 @@
# None initializers preserve the partial None type.
return
- if is_valid_inferred_type(rvalue_type):
+ if is_valid_inferred_type(rvalue_type, for_stmt):
var = lvalue_type.var
partial_types = self.find_partial_types(var)
if partial_types is not None:
@@ -2099,7 +2100,7 @@
else:
# Try to infer a partial type. No need to check the return value, as
# an error will be reported elsewhere.
- self.infer_partial_type(lvalue_type.var, lvalue, rvalue_type)
+ self.infer_partial_type(lvalue_type.var, lvalue, rvalue_type, rvalue)
# Handle None PartialType's super type checking here, after it's resolved.
if (isinstance(lvalue, RefExpr) and
self.check_compatibility_all_supers(lvalue, lvalue_type, rvalue)):
@@ -2146,7 +2147,7 @@
rvalue_type = self.expr_checker.accept(rvalue)
if not inferred.is_final:
rvalue_type = remove_instance_last_known_values(rvalue_type)
- self.infer_variable_type(inferred, lvalue, rvalue_type, rvalue)
+ self.infer_variable_type(inferred, lvalue, rvalue_type, rvalue, for_stmt=for_stmt)
# (type, operator) tuples for augmented assignments supported with partial types
partial_type_augmented_ops = {
@@ -2475,7 +2476,9 @@
def check_assignment_to_multiple_lvalues(self, lvalues: List[Lvalue], rvalue: Expression,
context: Context,
- infer_lvalue_type: bool = True) -> None:
+ infer_lvalue_type: bool = True,
+ *,
+ for_stmt: bool) -> None:
if isinstance(rvalue, TupleExpr) or isinstance(rvalue, ListExpr):
# Recursively go into Tuple or List expression rhs instead of
# using the type of rhs, because this allowed more fine grained
@@ -2545,7 +2548,8 @@
for lv, rv in lr_pairs:
self.check_assignment(lv, rv, infer_lvalue_type)
else:
- self.check_multi_assignment(lvalues, rvalue, context, infer_lvalue_type)
+ self.check_multi_assignment(lvalues, rvalue, context, infer_lvalue_type,
+ for_stmt=for_stmt)
def check_rvalue_count_in_assignment(self, lvalues: List[Lvalue], rvalue_count: int,
context: Context) -> bool:
@@ -2565,7 +2569,9 @@
context: Context,
infer_lvalue_type: bool = True,
rv_type: Optional[Type] = None,
- undefined_rvalue: bool = False) -> None:
+ undefined_rvalue: bool = False,
+ *,
+ for_stmt: bool) -> None:
"""Check the assignment of one rvalue to a number of lvalues."""
# Infer the type of an ordinary rvalue expression.
@@ -2584,22 +2590,24 @@
lv = lv.expr
temp_node = self.temp_node(AnyType(TypeOfAny.from_another_any,
source_any=rvalue_type), context)
- self.check_assignment(lv, temp_node, infer_lvalue_type)
+ self.check_assignment(lv, temp_node, infer_lvalue_type, for_stmt=for_stmt)
elif isinstance(rvalue_type, TupleType):
self.check_multi_assignment_from_tuple(lvalues, rvalue, rvalue_type,
- context, undefined_rvalue, infer_lvalue_type)
+ context, undefined_rvalue, infer_lvalue_type,
+ for_stmt=for_stmt)
elif isinstance(rvalue_type, UnionType):
self.check_multi_assignment_from_union(lvalues, rvalue, rvalue_type, context,
- infer_lvalue_type)
+ infer_lvalue_type, for_stmt=for_stmt)
elif isinstance(rvalue_type, Instance) and rvalue_type.type.fullname == 'builtins.str':
self.msg.unpacking_strings_disallowed(context)
else:
self.check_multi_assignment_from_iterable(lvalues, rvalue_type,
- context, infer_lvalue_type)
+ context, infer_lvalue_type,
+ for_stmt=for_stmt)
def check_multi_assignment_from_union(self, lvalues: List[Expression], rvalue: Expression,
rvalue_type: UnionType, context: Context,
- infer_lvalue_type: bool) -> None:
+ infer_lvalue_type: bool, *, for_stmt: bool) -> None:
"""Check assignment to multiple lvalue targets when rvalue type is a Union[...].
For example:
@@ -2622,7 +2630,7 @@
# the inferred lvalue types for each union item.
self.check_multi_assignment(lvalues, rvalue, context,
infer_lvalue_type=infer_lvalue_type,
- rv_type=item, undefined_rvalue=True)
+ rv_type=item, undefined_rvalue=True, for_stmt=for_stmt)
for t, lv in zip(transposed, self.flatten_lvalues(lvalues)):
t.append(self.type_map.pop(lv, AnyType(TypeOfAny.special_form)))
union_types = tuple(make_simplified_union(col) for col in transposed)
@@ -2667,7 +2675,8 @@
def check_multi_assignment_from_tuple(self, lvalues: List[Lvalue], rvalue: Expression,
rvalue_type: TupleType, context: Context,
undefined_rvalue: bool,
- infer_lvalue_type: bool = True) -> None:
+ infer_lvalue_type: bool = True, *,
+ for_stmt: bool) -> None:
if self.check_rvalue_count_in_assignment(lvalues, len(rvalue_type.items), context):
star_index = next((i for i, lv in enumerate(lvalues)
if isinstance(lv, StarExpr)), len(lvalues))
@@ -2690,7 +2699,7 @@
if isinstance(reinferred_rvalue_type, UnionType):
self.check_multi_assignment_from_union(lvalues, rvalue,
reinferred_rvalue_type, context,
- infer_lvalue_type)
+ infer_lvalue_type, for_stmt=for_stmt)
return
if isinstance(reinferred_rvalue_type, AnyType) and self.current_node_deferred:
# Doing more inference in deferred nodes can be hard, so give up for now.
@@ -2702,14 +2711,17 @@
rvalue_type.items, star_index, len(lvalues))
for lv, rv_type in zip(left_lvs, left_rv_types):
- self.check_assignment(lv, self.temp_node(rv_type, context), infer_lvalue_type)
+ self.check_assignment(lv, self.temp_node(rv_type, context), infer_lvalue_type,
+ for_stmt=for_stmt)
if star_lv:
list_expr = ListExpr([self.temp_node(rv_type, context)
for rv_type in star_rv_types])
list_expr.set_line(context.get_line())
- self.check_assignment(star_lv.expr, list_expr, infer_lvalue_type)
+ self.check_assignment(star_lv.expr, list_expr, infer_lvalue_type,
+ for_stmt=for_stmt)
for lv, rv_type in zip(right_lvs, right_rv_types):
- self.check_assignment(lv, self.temp_node(rv_type, context), infer_lvalue_type)
+ self.check_assignment(lv, self.temp_node(rv_type, context), infer_lvalue_type,
+ for_stmt=for_stmt)
def lvalue_type_for_inference(self, lvalues: List[Lvalue], rvalue_type: TupleType) -> Type:
star_index = next((i for i, lv in enumerate(lvalues)
@@ -2771,7 +2783,8 @@
def check_multi_assignment_from_iterable(self, lvalues: List[Lvalue], rvalue_type: Type,
context: Context,
- infer_lvalue_type: bool = True) -> None:
+ infer_lvalue_type: bool = True, *,
+ for_stmt: bool) -> None:
rvalue_type = get_proper_type(rvalue_type)
if self.type_is_iterable(rvalue_type) and isinstance(rvalue_type, Instance):
item_type = self.iterable_item_type(rvalue_type)
@@ -2779,10 +2792,10 @@
if isinstance(lv, StarExpr):
items_type = self.named_generic_type('builtins.list', [item_type])
self.check_assignment(lv.expr, self.temp_node(items_type, context),
- infer_lvalue_type)
+ infer_lvalue_type, for_stmt=for_stmt)
else:
self.check_assignment(lv, self.temp_node(item_type, context),
- infer_lvalue_type)
+ infer_lvalue_type, for_stmt=for_stmt)
else:
self.msg.type_not_iterable(rvalue_type, context)
@@ -2841,24 +2854,25 @@
return False
def infer_variable_type(self, name: Var, lvalue: Lvalue,
- init_type: Type, context: Context) -> None:
+ init_type: Type, init_expr: Expression, *, for_stmt: bool) -> None:
"""Infer the type of initialized variables from initializer type."""
init_type = get_proper_type(init_type)
if isinstance(init_type, DeletedType):
- self.msg.deleted_as_rvalue(init_type, context)
- elif not is_valid_inferred_type(init_type) and not self.no_partial_types:
+ self.msg.deleted_as_rvalue(init_type, context=init_expr)
+ elif not is_valid_inferred_type(
+ init_type, for_stmt=for_stmt) and not self.no_partial_types:
# We cannot use the type of the initialization expression for full type
# inference (it's not specific enough), but we might be able to give
# partial type which will be made more specific later. A partial type
# gets generated in assignment like 'x = []' where item type is not known.
- if not self.infer_partial_type(name, lvalue, init_type):
- self.msg.need_annotation_for_var(name, context, self.options.python_version)
+ if not self.infer_partial_type(name, lvalue, init_type, init_expr):
+ self.msg.need_annotation_for_var(name, init_expr, self.options.python_version)
self.set_inference_error_fallback_type(name, lvalue, init_type)
elif (isinstance(lvalue, MemberExpr) and self.inferred_attribute_types is not None
and lvalue.def_var and lvalue.def_var in self.inferred_attribute_types
and not is_same_type(self.inferred_attribute_types[lvalue.def_var], init_type)):
# Multiple, inconsistent types inferred for an attribute.
- self.msg.need_annotation_for_var(name, context, self.options.python_version)
+ self.msg.need_annotation_for_var(name, init_expr, self.options.python_version)
name.type = AnyType(TypeOfAny.from_error)
else:
# Infer type of the target.
@@ -2868,9 +2882,14 @@
self.set_inferred_type(name, lvalue, init_type)
- def infer_partial_type(self, name: Var, lvalue: Lvalue, init_type: Type) -> bool:
+ def infer_partial_type(self, name: Var, lvalue: Lvalue, init_type: Type,
+ init_expr: Expression) -> bool:
init_type = get_proper_type(init_type)
if isinstance(init_type, NoneType):
+ if isinstance(init_expr, CallExpr):
+ # In cases like 'x = f()', we don't infer a partial type but None.
+ self.set_inferred_type(name, lvalue, init_type)
+ return True
partial_type = PartialType(None, name)
elif isinstance(init_type, Instance):
fullname = init_type.type.fullname
@@ -3536,7 +3555,9 @@
def analyze_index_variables(self, index: Expression, item_type: Type,
infer_lvalue_type: bool, context: Context) -> None:
"""Type check or infer for loop or list comprehension index vars."""
- self.check_assignment(index, self.temp_node(item_type, context), infer_lvalue_type)
+ self.check_assignment(
+ index, self.temp_node(item_type, context), infer_lvalue_type, for_stmt=True
+ )
def visit_del_stmt(self, s: DelStmt) -> None:
if isinstance(s.expr, IndexExpr):
@@ -4687,7 +4708,7 @@
@contextmanager
def enter_partial_types(self, *, is_function: bool = False,
- is_class: bool = False) -> Iterator[None]:
+ is_class: bool = False, is_enum: bool = False) -> Iterator[None]:
"""Enter a new scope for collecting partial types.
Also report errors for (some) variables which still have partial
@@ -4699,12 +4720,13 @@
# Don't complain about not being able to infer partials if it is
# at the toplevel (with allow_untyped_globals) or if it is in an
- # untyped function being checked with check_untyped_defs.
+ # untyped function being checked with check_untyped_defs, or in an
+ # enum class (None is a valid value for an item).
permissive = (self.options.allow_untyped_globals and not is_local) or (
self.options.check_untyped_defs
and self.dynamic_funcs
and self.dynamic_funcs[-1]
- )
+ ) or is_enum
partial_types, _, _ = self.partial_types.pop()
if not self.current_node_deferred:
@@ -5433,7 +5455,7 @@
return False, method
-def is_valid_inferred_type(typ: Type) -> bool:
+def is_valid_inferred_type(typ: Type, for_stmt: bool = False) -> bool:
"""Is an inferred type valid?
Examples of invalid types include the None type or List[<uninhabited>].
@@ -5442,11 +5464,15 @@
invalid. When doing strict Optional checking, only None and types that are
incompletely defined (i.e. contain UninhabitedType) are invalid.
"""
- if isinstance(get_proper_type(typ), (NoneType, UninhabitedType)):
+ proper_type = get_proper_type(typ)
+ if isinstance(proper_type, (NoneType, UninhabitedType)):
# With strict Optional checking, we *may* eventually infer NoneType when
# the initializer is None, but we only do that if we can't infer a
# specific Optional type. This resolution happens in
# leave_partial_types when we pop a partial types scope.
+ if for_stmt and isinstance(proper_type, NoneType):
+ # For statements shouldn't produce partial types.
+ return True
return False
return not typ.accept(NothingSeeker())
diff --git a/mypy/dmypy_server.py b/mypy/dmypy_server.py
index eb53935..ad1b9d4 100644
--- a/mypy/dmypy_server.py
+++ b/mypy/dmypy_server.py
@@ -143,6 +143,8 @@
sys.exit("dmypy: start/restart should not disable incremental mode")
if options.follow_imports not in ('skip', 'error', 'normal'):
sys.exit("dmypy: follow-imports=silent not supported")
+ if not options.local_partial_types:
+ sys.exit("dmypy: disabling local-partial-types not supported")
return options
diff --git a/mypy/main.py b/mypy/main.py
index 40c5f39..5dd4142 100644
--- a/mypy/main.py
+++ b/mypy/main.py
@@ -778,7 +778,7 @@
parser.add_argument('--semantic-analysis-only', action='store_true', help=argparse.SUPPRESS)
# --local-partial-types disallows partial types spanning module top level and a function
# (implicitly defined in fine-grained incremental mode)
- parser.add_argument('--local-partial-types', action='store_true', help=argparse.SUPPRESS)
+ add_invertible_flag('--local-partial-types', default=False, help=argparse.SUPPRESS)
# --logical-deps adds some more dependencies that are not semantically needed, but
# may be helpful to determine relative importance of classes and functions for overall
# type precision in a code base. It also _removes_ some deps, so this flag should be never
diff --git a/mypy/options.py b/mypy/options.py
index 026046a..03c6c2d 100644
--- a/mypy/options.py
+++ b/mypy/options.py
@@ -277,7 +277,7 @@
self.dump_deps = False
self.logical_deps = False
# If True, partial types can't span a module top level and a function
- self.local_partial_types = False
+ self.local_partial_types = True
# Some behaviors are changed when using Bazel (https://bazel.build).
self.bazel = False
# If True, export inferred types for all expressions as BuildResult.types
diff --git a/test-data/stdlib-samples/3.2/shutil.py b/test-data/stdlib-samples/3.2/shutil.py
index e7b5e5a..98ff6fd 100644
--- a/test-data/stdlib-samples/3.2/shutil.py
+++ b/test-data/stdlib-samples/3.2/shutil.py
@@ -65,7 +65,7 @@
if sys.platform == "win32":
_WindowsError = WindowsError
else:
- _WindowsError = None
+ _WindowsError = None # type: None
# Function aliases to be patched in test cases
diff --git a/test-data/unit/check-basic.test b/test-data/unit/check-basic.test
index 4fa77b1..6cdd4dd 100644
--- a/test-data/unit/check-basic.test
+++ b/test-data/unit/check-basic.test
@@ -399,7 +399,7 @@
pass
[case testNoneHasBool]
-none = None
+none: None = None
b = none.__bool__()
reveal_type(b) # N: Revealed type is 'builtins.bool'
[builtins fixtures/bool.pyi]
diff --git a/test-data/unit/check-callable.test b/test-data/unit/check-callable.test
index 31a8923..76f5d95 100644
--- a/test-data/unit/check-callable.test
+++ b/test-data/unit/check-callable.test
@@ -429,7 +429,6 @@
[builtins fixtures/callable.pyi]
[case testCallableTuple]
-
from typing import NamedTuple
Thing = NamedTuple('Thing', [('s', str), ('n', int)])
@@ -440,26 +439,24 @@
i, s = o
i + s # E: Unsupported operand types for + ("str" and "int")
o(1,2,3)
-
[builtins fixtures/callable.pyi]
[case testCallableNoArgs]
-
if callable(): # E: Missing positional argument "x" in call to "callable"
pass
-
[builtins fixtures/callable.pyi]
[case testCallableWithNoneArgs]
-
-fn = None
+fn = None # E: Need type annotation for "fn"
if callable(fn):
fn()
+fn2: None = None
+if callable(fn2):
+ fn2()
[builtins fixtures/callable.pyi]
[case testCallableUnionOfNoneAndCallable]
-
from typing import Union, Callable
def f() -> int:
diff --git a/test-data/unit/check-columns.test b/test-data/unit/check-columns.test
index 43ff972..577d41e 100644
--- a/test-data/unit/check-columns.test
+++ b/test-data/unit/check-columns.test
@@ -235,6 +235,7 @@
[builtins fixtures/dict.pyi]
[case testColumnCannotDetermineType]
+# flags: --no-local-partial-types
(x) # E:2: Cannot determine type of 'x'
x = None
diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test
index 800c33c..5ddedbc 100644
--- a/test-data/unit/check-errorcodes.test
+++ b/test-data/unit/check-errorcodes.test
@@ -462,7 +462,7 @@
[case testErrorCodeCannotDetermineType]
y = x # E: Cannot determine type of 'x' [has-type]
reveal_type(y) # N: Revealed type is 'Any'
-x = None
+x = None # E: Need type annotation for "x" [var-annotated]
[case testErrorCodeRedundantCast]
# flags: --warn-redundant-casts
diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test
index 8e57ca2..ef10173 100644
--- a/test-data/unit/check-functions.test
+++ b/test-data/unit/check-functions.test
@@ -2201,7 +2201,7 @@
class A:
def f(self) -> None:
# In particular, test that the error message contains "g" of "A".
- self.g() # E: Too few arguments for "g" of "A"
+ self.g() # E: Too few arguments for "g" of "A"
self.g(1)
@dec
def g(self, x: str) -> None: pass
@@ -2525,7 +2525,7 @@
[out]
[case testNoComplainInferredNone]
-# flags: --no-strict-optional
+# flags: --no-strict-optional --no-local-partial-types
from typing import TypeVar, Optional
T = TypeVar('T')
def X(val: T) -> T: ...
@@ -2540,7 +2540,7 @@
from typing import TypeVar, Optional
T = TypeVar('T')
def X(val: T) -> T: ...
-x_in = None
+x_in = X(None)
def Y(x: Optional[str] = X(x_in)): ...
xx: Optional[int] = X(x_in)
diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test
index 1b198f6..12825a5 100644
--- a/test-data/unit/check-inference.test
+++ b/test-data/unit/check-inference.test
@@ -979,7 +979,6 @@
[builtins fixtures/for.pyi]
[case testInferenceOfFor2]
-
a, b, c = None, None, None # type: (A, B, C)
for x, (y, z) in [(A(), (B(), C()))]:
b = x # Fail
@@ -1000,11 +999,11 @@
class C: pass
[builtins fixtures/for.pyi]
[out]
-main:4: error: Incompatible types in assignment (expression has type "A", variable has type "B")
-main:5: error: Incompatible types in assignment (expression has type "B", variable has type "C")
-main:6: error: Incompatible types in assignment (expression has type "C", variable has type "A")
-main:10: error: Need more than 2 values to unpack (3 expected)
-main:12: error: '__main__.B' object is not iterable
+main:3: error: Incompatible types in assignment (expression has type "A", variable has type "B")
+main:4: error: Incompatible types in assignment (expression has type "B", variable has type "C")
+main:5: error: Incompatible types in assignment (expression has type "C", variable has type "A")
+main:9: error: Need more than 2 values to unpack (3 expected)
+main:11: error: '__main__.B' object is not iterable
[case testInferenceOfFor3]
@@ -1525,12 +1524,14 @@
[builtins fixtures/dict.pyi]
[case testInferDictInitializedToEmptyAndUpdatedFromMethod]
+# flags: --no-local-partial-types
map = {}
def add() -> None:
map[1] = 2
[builtins fixtures/dict.pyi]
[case testInferDictInitializedToEmptyAndUpdatedFromMethodUnannotated]
+# flags: --no-local-partial-types
map = {}
def add():
map[1] = 2
@@ -1720,7 +1721,7 @@
[builtins fixtures/dict.pyi]
[case testInferAttributeInitializedToNoneAndAssignedClassBody]
-# flags: --strict-optional
+# flags: --strict-optional --no-local-partial-types
class C:
a = None
def __init__(self) -> None:
@@ -1755,7 +1756,7 @@
[builtins fixtures/dict.pyi]
[case testInferFromEmptyDictWhenUsingInSpecialCase]
-d = None
+d = None # E: Need type annotation for "d"
if 'x' in d: # E: "None" has no attribute "__iter__" (not iterable)
pass
reveal_type(d) # N: Revealed type is 'None'
@@ -1864,7 +1865,7 @@
[out]
[case testPartiallyInitializedVariableDoesNotEscapeScope2]
-x = None
+x = None # E: Need type annotation for "x"
def f() -> None:
x = None
x = 1
@@ -1891,19 +1892,19 @@
main:7: error: "None" not callable
[case testGlobalInitializedToNoneSetFromFunction]
+# flags: --no-local-partial-types
a = None
def f():
global a
a = 42
-[out]
[case testGlobalInitializedToNoneSetFromMethod]
+# flags: --no-local-partial-types
a = None
class C:
def m(self):
global a
a = 42
-[out]
-- More partial type errors
-- ------------------------
@@ -1911,13 +1912,11 @@
[case testPartialTypeErrorSpecialCase1]
# This used to crash.
class A:
- x = None
+ x = None # E: Need type annotation for "x"
def f(self) -> None:
for a in self.x:
pass
[builtins fixtures/for.pyi]
-[out]
-main:5: error: "None" has no attribute "__iter__" (not iterable)
[case testPartialTypeErrorSpecialCase2]
# This used to crash.
@@ -1932,13 +1931,11 @@
[case testPartialTypeErrorSpecialCase3]
class A:
- x = None
+ x = None # E: Need type annotation for "x"
def f(self) -> None:
for a in A.x:
pass
[builtins fixtures/for.pyi]
-[out]
-main:4: error: "None" has no attribute "__iter__" (not iterable)
-- Multipass
@@ -1975,7 +1972,7 @@
class A:
def f(self) -> None:
- self.g() # E: Too few arguments for "g" of "A"
+ self.g() # E: Too few arguments for "g" of "A"
self.g(1)
@dec
def g(self, x: str) -> None: pass
@@ -2281,9 +2278,9 @@
[case testNoCrashOnPartialMember]
class C:
- x = None
+ x = None # E: Need type annotation for "x"
def __init__(self) -> None:
- self.x = [] # E: Need type annotation for "x" (hint: "x: List[<type>] = ...")
+ self.x = []
[builtins fixtures/list.pyi]
[out]
@@ -2305,7 +2302,7 @@
def f() -> Tuple[T]:
...
-x = None
+x = None # E: Need type annotation for "x"
if int():
(x,) = f()
[builtins fixtures/tuple.pyi]
diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test
index a83df1f..eadd249 100644
--- a/test-data/unit/check-literal.test
+++ b/test-data/unit/check-literal.test
@@ -1326,7 +1326,7 @@
bool3: bool = True
none1: Literal[None] = None
-none2 = None
+none2 = None # E: Need type annotation for "none2"
none3: None = None
reveal_type(int1) # N: Revealed type is 'Literal[1]'
@@ -1356,7 +1356,7 @@
a = 1
b = "foo"
c = True
-d = None
+d = None # E: Need type annotation for "d"
w = a # E: Incompatible types in assignment (expression has type "int", variable has type "Literal[1]")
x = b # E: Incompatible types in assignment (expression has type "str", variable has type "Literal['foo']")
@@ -2456,13 +2456,13 @@
var1: Final = 1
var2: Final = "foo"
var3: Final = True
-var4: Final = None
+var4: Final = None # E: Need type annotation for "var4"
class Foo:
classvar1: Final = 1
classvar2: Final = "foo"
classvar3: Final = True
- classvar4: Final = None
+ classvar4: Final = None # E: Need type annotation for "classvar4"
def __init__(self) -> None:
self.instancevar1: Final = 1
@@ -2487,11 +2487,11 @@
reveal_type(Foo.classvar1) # N: Revealed type is 'Literal[1]?'
reveal_type(Foo.classvar2) # N: Revealed type is 'Literal['foo']?'
reveal_type(Foo.classvar3) # N: Revealed type is 'Literal[True]?'
-reveal_type(Foo.classvar4) # N: Revealed type is 'None'
+reveal_type(Foo.classvar4) # N: Revealed type is 'Any'
force1(reveal_type(Foo.classvar1)) # N: Revealed type is 'Literal[1]'
force2(reveal_type(Foo.classvar2)) # N: Revealed type is 'Literal['foo']'
force3(reveal_type(Foo.classvar3)) # N: Revealed type is 'Literal[True]'
-force4(reveal_type(Foo.classvar4)) # N: Revealed type is 'None'
+force4(reveal_type(Foo.classvar4)) # N: Revealed type is 'Any'
f = Foo()
reveal_type(f.instancevar1) # N: Revealed type is 'Literal[1]?'
diff --git a/test-data/unit/check-optional.test b/test-data/unit/check-optional.test
index 8d05459..3bd1806 100644
--- a/test-data/unit/check-optional.test
+++ b/test-data/unit/check-optional.test
@@ -1,7 +1,7 @@
-- Tests for strict Optional behavior
[case testImplicitNoneType]
-x = None
+x = None # E: Need type annotation for "x"
x() # E: "None" not callable
[case testImplicitNoneTypeInNestedFunction]
@@ -315,7 +315,7 @@
[out]
[case testNoneAndStringIsNone]
-a = None
+a: None = None
b = "foo"
reveal_type(a and b) # N: Revealed type is 'None'
@@ -627,7 +627,7 @@
[case testInvalidBooleanBranchIgnored]
from typing import Optional
-x = None
+x: None = None
x is not None and x + 42
[builtins fixtures/isinstance.pyi]
diff --git a/test-data/unit/check-protocols.test b/test-data/unit/check-protocols.test
index b7f4fd5..a01c31e 100644
--- a/test-data/unit/check-protocols.test
+++ b/test-data/unit/check-protocols.test
@@ -266,7 +266,7 @@
return 0
class C:
- __my_hash__ = None
+ __my_hash__: None = None
var: MyHashable = C() # E: Incompatible types in assignment (expression has type "C", variable has type "MyHashable")
@@ -289,7 +289,7 @@
x = 0 # type: int
class C:
- x = None
+ x: None = None
x: P = C() # Error!
def f(x: P) -> None: pass
@@ -2083,7 +2083,7 @@
def execute(self, stmt: Any, *args: Any, **kwargs: Any) -> None: ...
def cool(self) -> None: ...
-def func1(arg: A) -> None: ...
+def func1(arg: A) -> None: ...
def func2(arg: Optional[A]) -> None: ...
x: B
@@ -2571,6 +2571,7 @@
[case testPartialTypeProtocol]
+# flags: --no-local-partial-types
from typing import Protocol
class Flapper(Protocol):
diff --git a/test-data/unit/check-python2.test b/test-data/unit/check-python2.test
index fe51cb4..d9028a4 100644
--- a/test-data/unit/check-python2.test
+++ b/test-data/unit/check-python2.test
@@ -358,7 +358,7 @@
pass
[case testNoneHasNoBoolInPython2]
-none = None
+none = None # type: None
b = none.__bool__() # E: "None" has no attribute "__bool__"
[case testDictWithoutTypeCommentInPython2]
diff --git a/test-data/unit/deps.test b/test-data/unit/deps.test
index 8c074ab..4383299 100644
--- a/test-data/unit/deps.test
+++ b/test-data/unit/deps.test
@@ -1,6 +1,6 @@
-- Test cases for generating dependencies between ASTs nodes.
--
--- The dependencies are used for fined-grained incremental checking and
+-- The dependencies are used for fined-grained incremental checking in
-- the daemon mode.
--
-- The output of each test case includes the dependency map for whitelisted
@@ -600,7 +600,7 @@
class C: pass
class A:
- x = None
+ x = None # type: ignore
def f(self) -> None:
self.x = C()
@@ -609,14 +609,14 @@
<m.A> -> m.A
<m.C.__init__> -> m.A.f
<m.C.__new__> -> m.A.f
-<m.C> -> <m.A.x>, m.A.f, m.C
+<m.C> -> m.A.f, m.C
[case testPartialNoneTypeAttributeCrash2]
# flags: --strict-optional
class C: pass
class A:
- x = None
+ x = None # type: ignore
def f(self) -> None:
self.x = C()
@@ -625,7 +625,7 @@
<m.A> -> m.A
<m.C.__init__> -> m.A.f
<m.C.__new__> -> m.A.f
-<m.C> -> <m.A.x>, m.A.f, m.C
+<m.C> -> m.A.f, m.C
[case testRelativeImport]
import pkg # Magic package name in test runner