diff --git a/mypy/checker.py b/mypy/checker.py index 4b6152432e47..077d78a1b97c 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -177,54 +177,56 @@ def check_first_pass(self) -> None: Deferred functions will be processed by check_second_pass(). """ - self.errors.set_file(self.path, self.tree.fullname()) - with self.enter_partial_types(): - with self.binder.top_frame_context(): - for d in self.tree.defs: - self.accept(d) + with experiments.strict_optional_set(self.options.strict_optional): + self.errors.set_file(self.path, self.tree.fullname()) + with self.enter_partial_types(): + with self.binder.top_frame_context(): + for d in self.tree.defs: + self.accept(d) - assert not self.current_node_deferred + assert not self.current_node_deferred - all_ = self.globals.get('__all__') - if all_ is not None and all_.type is not None: - all_node = all_.node - assert all_node is not None - seq_str = self.named_generic_type('typing.Sequence', - [self.named_type('builtins.str')]) - if self.options.python_version[0] < 3: + all_ = self.globals.get('__all__') + if all_ is not None and all_.type is not None: + all_node = all_.node + assert all_node is not None seq_str = self.named_generic_type('typing.Sequence', - [self.named_type('builtins.unicode')]) - if not is_subtype(all_.type, seq_str): - str_seq_s, all_s = self.msg.format_distinctly(seq_str, all_.type) - self.fail(messages.ALL_MUST_BE_SEQ_STR.format(str_seq_s, all_s), - all_node) + [self.named_type('builtins.str')]) + if self.options.python_version[0] < 3: + seq_str = self.named_generic_type('typing.Sequence', + [self.named_type('builtins.unicode')]) + if not is_subtype(all_.type, seq_str): + str_seq_s, all_s = self.msg.format_distinctly(seq_str, all_.type) + self.fail(messages.ALL_MUST_BE_SEQ_STR.format(str_seq_s, all_s), + all_node) def check_second_pass(self, todo: List[DeferredNode] = None) -> bool: """Run second or following pass of type checking. This goes through deferred nodes, returning True if there were any. """ - if not todo and not self.deferred_nodes: - return False - self.errors.set_file(self.path, self.tree.fullname()) - self.pass_num += 1 - if not todo: - todo = self.deferred_nodes - else: - assert not self.deferred_nodes - self.deferred_nodes = [] - done = set() # type: Set[Union[FuncDef, LambdaExpr, MypyFile]] - for node, type_name, active_typeinfo in todo: - if node in done: - continue - # This is useful for debugging: - # print("XXX in pass %d, class %s, function %s" % - # (self.pass_num, type_name, node.fullname() or node.name())) - done.add(node) - with self.errors.enter_type(type_name) if type_name else nothing(): - with self.scope.push_class(active_typeinfo) if active_typeinfo else nothing(): - self.check_partial(node) - return True + with experiments.strict_optional_set(self.options.strict_optional): + if not todo and not self.deferred_nodes: + return False + self.errors.set_file(self.path, self.tree.fullname()) + self.pass_num += 1 + if not todo: + todo = self.deferred_nodes + else: + assert not self.deferred_nodes + self.deferred_nodes = [] + done = set() # type: Set[Union[FuncDef, LambdaExpr, MypyFile]] + for node, type_name, active_typeinfo in todo: + if node in done: + continue + # This is useful for debugging: + # print("XXX in pass %d, class %s, function %s" % + # (self.pass_num, type_name, node.fullname() or node.name())) + done.add(node) + with self.errors.enter_type(type_name) if type_name else nothing(): + with self.scope.push_class(active_typeinfo) if active_typeinfo else nothing(): + self.check_partial(node) + return True def check_partial(self, node: Union[FuncDef, LambdaExpr, MypyFile]) -> None: if isinstance(node, MypyFile): @@ -1498,6 +1500,12 @@ def check_multi_assignment(self, lvalues: List[Lvalue], rvalue_type = self.expr_checker.accept(rvalue) # TODO maybe elsewhere; redundant undefined_rvalue = False + if isinstance(rvalue_type, UnionType): + # If this is an Optional type in non-strict Optional code, unwrap it. + relevant_items = rvalue_type.relevant_items() + if len(relevant_items) == 1: + rvalue_type = relevant_items[0] + if isinstance(rvalue_type, AnyType): for lv in lvalues: if isinstance(lv, StarExpr): @@ -1525,7 +1533,16 @@ def check_multi_assignment_from_tuple(self, lvalues: List[Lvalue], rvalue: Expre if not undefined_rvalue: # Infer rvalue again, now in the correct type context. lvalue_type = self.lvalue_type_for_inference(lvalues, rvalue_type) - rvalue_type = cast(TupleType, self.expr_checker.accept(rvalue, lvalue_type)) + reinferred_rvalue_type = self.expr_checker.accept(rvalue, lvalue_type) + + if isinstance(reinferred_rvalue_type, UnionType): + # If this is an Optional type in non-strict Optional code, unwrap it. + relevant_items = reinferred_rvalue_type.relevant_items() + if len(relevant_items) == 1: + reinferred_rvalue_type = relevant_items[0] + + assert isinstance(reinferred_rvalue_type, TupleType) + rvalue_type = reinferred_rvalue_type left_rv_types, star_rv_types, right_rv_types = self.split_around_star( rvalue_type.items, star_index, len(lvalues)) @@ -2161,7 +2178,7 @@ def get_types_from_except_handler(self, typ: Type, n: Expression) -> List[Type]: elif isinstance(typ, UnionType): return [ union_typ - for item in typ.items + for item in typ.relevant_items() for union_typ in self.get_types_from_except_handler(item, n) ] elif isinstance(typ, Instance) and is_named_instance(typ, 'builtins.tuple'): @@ -2627,7 +2644,7 @@ def partition_by_callable(type: Optional[Type]) -> Tuple[List[Type], List[Type]] if isinstance(type, UnionType): callables = [] uncallables = [] - for subtype in type.items: + for subtype in type.relevant_items(): subcallables, subuncallables = partition_by_callable(subtype) callables.extend(subcallables) uncallables.extend(subuncallables) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 00c95cb2e6d4..1603ccec42ff 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -560,7 +560,7 @@ def check_call(self, callee: Type, args: List[Expression], self.msg.disable_type_names += 1 results = [self.check_call(subtype, args, arg_kinds, context, arg_names, arg_messages=arg_messages) - for subtype in callee.items] + for subtype in callee.relevant_items()] self.msg.disable_type_names -= 1 return (UnionType.make_simplified_union([res[0] for res in results]), callee) @@ -596,7 +596,7 @@ def analyze_type_type_callee(self, item: Type, context: Context) -> Type: return res if isinstance(item, UnionType): return UnionType([self.analyze_type_type_callee(item, context) - for item in item.items], item.line) + for item in item.relevant_items()], item.line) if isinstance(item, TypeVarType): # Pretend we're calling the typevar's upper bound, # i.e. its constructor (a poor approximation for reality, @@ -1982,7 +1982,7 @@ def infer_lambda_type_using_context(self, e: LambdaExpr) -> Tuple[Optional[Calla ctx = self.type_context[-1] if isinstance(ctx, UnionType): - callables = [t for t in ctx.items if isinstance(t, CallableType)] + callables = [t for t in ctx.relevant_items() if isinstance(t, CallableType)] if len(callables) == 1: ctx = callables[0] @@ -2284,7 +2284,7 @@ def has_member(self, typ: Type, member: str) -> bool: elif isinstance(typ, AnyType): return True elif isinstance(typ, UnionType): - result = all(self.has_member(x, member) for x in typ.items) + result = all(self.has_member(x, member) for x in typ.relevant_items()) return result elif isinstance(typ, TupleType): return self.has_member(typ.fallback, member) @@ -2659,10 +2659,10 @@ def overload_arg_similarity(actual: Type, formal: Type) -> int: return 2 if isinstance(actual, UnionType): return max(overload_arg_similarity(item, formal) - for item in actual.items) + for item in actual.relevant_items()) if isinstance(formal, UnionType): return max(overload_arg_similarity(actual, item) - for item in formal.items) + for item in formal.relevant_items()) if isinstance(formal, TypeType): if isinstance(actual, TypeType): # Since Type[T] is covariant, check if actual = Type[A] is diff --git a/mypy/checkmember.py b/mypy/checkmember.py index d3f58a3a5917..c8dc69bdfbe4 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -115,7 +115,7 @@ def analyze_member_access(name: str, results = [analyze_member_access(name, subtype, node, is_lvalue, is_super, is_operator, builtin_type, not_ready_callback, msg, original_type=original_type, chk=chk) - for subtype in typ.items] + for subtype in typ.relevant_items()] msg.disable_type_names -= 1 return UnionType.make_simplified_union(results) elif isinstance(typ, TupleType): diff --git a/mypy/constraints.py b/mypy/constraints.py index d65a418df37b..7f07574bcf7a 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -254,9 +254,6 @@ class CompleteTypeVisitor(TypeQuery[bool]): def __init__(self) -> None: super().__init__(all) - def visit_none_type(self, t: NoneTyp) -> bool: - return experiments.STRICT_OPTIONAL - def visit_uninhabited_type(self, t: UninhabitedType) -> bool: return False diff --git a/mypy/experiments.py b/mypy/experiments.py index 8ac437eb68ea..03a4cebbbca1 100644 --- a/mypy/experiments.py +++ b/mypy/experiments.py @@ -1,3 +1,13 @@ -from typing import Optional, Tuple +from contextlib import contextmanager +from typing import Optional, Tuple, Iterator STRICT_OPTIONAL = False find_occurrences = None # type: Optional[Tuple[str, str]] + + +@contextmanager +def strict_optional_set(value: bool) -> Iterator[None]: + global STRICT_OPTIONAL + saved = STRICT_OPTIONAL + STRICT_OPTIONAL = value + yield + STRICT_OPTIONAL = saved diff --git a/mypy/meet.py b/mypy/meet.py index f0dcd8b56e34..f9bdd2d4779f 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -31,7 +31,7 @@ def narrow_declared_type(declared: Type, narrowed: Type) -> Type: return declared if isinstance(declared, UnionType): return UnionType.make_simplified_union([narrow_declared_type(x, narrowed) - for x in declared.items]) + for x in declared.relevant_items()]) elif not is_overlapping_types(declared, narrowed, use_promotions=True): if experiments.STRICT_OPTIONAL: return UninhabitedType() @@ -39,7 +39,7 @@ def narrow_declared_type(declared: Type, narrowed: Type) -> Type: return NoneTyp() elif isinstance(narrowed, UnionType): return UnionType.make_simplified_union([narrow_declared_type(declared, x) - for x in narrowed.items]) + for x in narrowed.relevant_items()]) elif isinstance(narrowed, AnyType): return narrowed elif isinstance(declared, (Instance, TupleType)): @@ -99,10 +99,10 @@ class C(A, B): ... return t.type in s.type.mro or s.type in t.type.mro if isinstance(t, UnionType): return any(is_overlapping_types(item, s) - for item in t.items) + for item in t.relevant_items()) if isinstance(s, UnionType): return any(is_overlapping_types(t, item) - for item in s.items) + for item in s.relevant_items()) if isinstance(t, TypeType) and isinstance(s, TypeType): # If both types are TypeType, compare their inner types. return is_overlapping_types(t.item, s.item, use_promotions) diff --git a/mypy/options.py b/mypy/options.py index fac8fe6d4459..ab8b223a150c 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -31,9 +31,10 @@ class Options: "ignore_errors", "strict_boolean", "no_implicit_optional", + "strict_optional", } - OPTIONS_AFFECTING_CACHE = PER_MODULE_OPTIONS | {"strict_optional", "quick_and_dirty"} + OPTIONS_AFFECTING_CACHE = PER_MODULE_OPTIONS | {"quick_and_dirty"} def __init__(self) -> None: # -- build options -- diff --git a/mypy/semanal.py b/mypy/semanal.py index c6749d25a92c..b40af448d018 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -90,6 +90,7 @@ from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError from mypy.sametypes import is_same_type from mypy.options import Options +from mypy import experiments from mypy.plugin import Plugin from mypy import join @@ -276,32 +277,33 @@ def visit_file(self, file_node: MypyFile, fnam: str, options: Options, self.globals = file_node.names self.patches = patches - if 'builtins' in self.modules: - self.globals['__builtins__'] = SymbolTableNode( - MODULE_REF, self.modules['builtins'], self.cur_mod_id) + with experiments.strict_optional_set(options.strict_optional): + if 'builtins' in self.modules: + self.globals['__builtins__'] = SymbolTableNode( + MODULE_REF, self.modules['builtins'], self.cur_mod_id) - for name in implicit_module_attrs: - v = self.globals[name].node - if isinstance(v, Var): - v.type = self.anal_type(v.type) - v.is_ready = True + for name in implicit_module_attrs: + v = self.globals[name].node + if isinstance(v, Var): + v.type = self.anal_type(v.type) + v.is_ready = True - defs = file_node.defs - for d in defs: - self.accept(d) + defs = file_node.defs + for d in defs: + self.accept(d) - if self.cur_mod_id == 'builtins': - remove_imported_names_from_symtable(self.globals, 'builtins') - for alias_name in type_aliases: - self.globals.pop(alias_name.split('.')[-1], None) + if self.cur_mod_id == 'builtins': + remove_imported_names_from_symtable(self.globals, 'builtins') + for alias_name in type_aliases: + self.globals.pop(alias_name.split('.')[-1], None) - if '__all__' in self.globals: - for name, g in self.globals.items(): - if name not in self.all_exports: - g.module_public = False + if '__all__' in self.globals: + for name, g in self.globals.items(): + if name not in self.all_exports: + g.module_public = False - del self.options - del self.patches + del self.options + del self.patches def refresh_partial(self, node: Union[MypyFile, FuncItem]) -> None: """Refresh a stale target in fine-grained incremental mode.""" @@ -3612,52 +3614,54 @@ def visit_file(self, file: MypyFile, fnam: str, mod_id: str, options: Options) - defs = file.defs - # Add implicit definitions of module '__name__' etc. - for name, t in implicit_module_attrs.items(): - # unicode docstrings should be accepted in Python 2 - if name == '__doc__': - if self.pyversion >= (3, 0): - typ = UnboundType('__builtins__.str') # type: Type + with experiments.strict_optional_set(options.strict_optional): + # Add implicit definitions of module '__name__' etc. + for name, t in implicit_module_attrs.items(): + # unicode docstrings should be accepted in Python 2 + if name == '__doc__': + if self.pyversion >= (3, 0): + typ = UnboundType('__builtins__.str') # type: Type + else: + typ = UnionType([UnboundType('__builtins__.str'), + UnboundType('__builtins__.unicode')]) else: - typ = UnionType([UnboundType('__builtins__.str'), - UnboundType('__builtins__.unicode')]) - else: - assert t is not None, 'type should be specified for {}'.format(name) - typ = UnboundType(t) - v = Var(name, typ) - v._fullname = self.sem.qualified_name(name) - self.sem.globals[name] = SymbolTableNode(GDEF, v, self.sem.cur_mod_id) - - for d in defs: - d.accept(self) - - # Add implicit definition of literals/keywords to builtins, as we - # cannot define a variable with them explicitly. - if mod_id == 'builtins': - literal_types = [ - ('None', NoneTyp()), - # reveal_type is a mypy-only function that gives an error with the type of its arg - ('reveal_type', AnyType()), - ] # type: List[Tuple[str, Type]] - - # TODO(ddfisher): This guard is only needed because mypy defines - # fake builtins for its tests which often don't define bool. If - # mypy is fast enough that we no longer need those, this - # conditional check should be removed. - if 'bool' in self.sem.globals: - bool_type = self.sem.named_type('bool') - literal_types.extend([ - ('True', bool_type), - ('False', bool_type), - ('__debug__', bool_type), - ]) - - for name, typ in literal_types: + assert t is not None, 'type should be specified for {}'.format(name) + typ = UnboundType(t) v = Var(name, typ) v._fullname = self.sem.qualified_name(name) self.sem.globals[name] = SymbolTableNode(GDEF, v, self.sem.cur_mod_id) - del self.sem.options + for d in defs: + d.accept(self) + + # Add implicit definition of literals/keywords to builtins, as we + # cannot define a variable with them explicitly. + if mod_id == 'builtins': + literal_types = [ + ('None', NoneTyp()), + # reveal_type is a mypy-only function that gives an error with + # the type of its arg. + ('reveal_type', AnyType()), + ] # type: List[Tuple[str, Type]] + + # TODO(ddfisher): This guard is only needed because mypy defines + # fake builtins for its tests which often don't define bool. If + # mypy is fast enough that we no longer need those, this + # conditional check should be removed. + if 'bool' in self.sem.globals: + bool_type = self.sem.named_type('bool') + literal_types.extend([ + ('True', bool_type), + ('False', bool_type), + ('__debug__', bool_type), + ]) + + for name, typ in literal_types: + v = Var(name, typ) + v._fullname = self.sem.qualified_name(name) + self.sem.globals[name] = SymbolTableNode(GDEF, v, self.sem.cur_mod_id) + + del self.sem.options def visit_block(self, b: Block) -> None: if b.is_unreachable: @@ -3851,7 +3855,8 @@ def __init__(self, modules: Dict[str, MypyFile], errors: Errors) -> None: def visit_file(self, file_node: MypyFile, fnam: str, options: Options) -> None: self.errors.set_file(fnam, file_node.fullname()) self.options = options - self.accept(file_node) + with experiments.strict_optional_set(options.strict_optional): + self.accept(file_node) def refresh_partial(self, node: Union[MypyFile, FuncItem]) -> None: """Refresh a stale target in fine-grained incremental mode.""" diff --git a/mypy/subtypes.py b/mypy/subtypes.py index ebd6a1d13d3c..589e9b812a3e 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -549,7 +549,7 @@ def restrict_subtype_away(t: Type, s: Type) -> Type: if isinstance(t, UnionType): # Since runtime type checks will ignore type arguments, erase the types. erased_s = erase_type(s) - new_items = [item for item in t.items + new_items = [item for item in t.relevant_items() if (not is_proper_subtype(erase_type(item), erased_s) or isinstance(item, AnyType))] return UnionType.make_union(new_items) diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 00b5c9fc52c9..f0442ad25aed 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -179,8 +179,6 @@ def visit_unbound_type(self, t: UnboundType) -> Type: return self.tuple_type(self.anal_array(t.args)) elif fullname == 'typing.Union': items = self.anal_array(t.args) - if not experiments.STRICT_OPTIONAL: - items = [item for item in items if not isinstance(item, NoneTyp)] return UnionType.make_union(items) elif fullname == 'typing.Optional': if len(t.args) != 1: @@ -780,12 +778,11 @@ def make_optional_type(t: Type) -> Type: is called during semantic analysis and simplification only works during type checking. """ - if not experiments.STRICT_OPTIONAL: - return t if isinstance(t, NoneTyp): return t - if isinstance(t, UnionType): + elif isinstance(t, UnionType): items = [item for item in union_items(t) if not isinstance(item, NoneTyp)] return UnionType(items + [NoneTyp()], t.line, t.column) - return UnionType([t, NoneTyp()], t.line, t.column) + else: + return UnionType([t, NoneTyp()], t.line, t.column) diff --git a/mypy/types.py b/mypy/types.py index d9ae8bf5fc4d..9966e8f96d3a 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -15,6 +15,7 @@ ) from mypy.sharedparse import argument_elide_name from mypy.util import IdMapper +from mypy import experiments T = TypeVar('T') @@ -1083,7 +1084,14 @@ def has_readable_member(self, name: str) -> bool: """ return all((isinstance(x, UnionType) and x.has_readable_member(name)) or (isinstance(x, Instance) and x.type.has_readable_member(name)) - for x in self.items) + for x in self.relevant_items()) + + def relevant_items(self) -> List[Type]: + """Removes NoneTypes from Unions when strict Optional checking is off.""" + if experiments.STRICT_OPTIONAL: + return self.items + else: + return [i for i in self.items if not isinstance(i, NoneTyp)] def serialize(self) -> JsonDict: return {'.class': 'UnionType', diff --git a/test-data/unit/check-class-namedtuple.test b/test-data/unit/check-class-namedtuple.test index 0447edb2df67..710f750369ff 100644 --- a/test-data/unit/check-class-namedtuple.test +++ b/test-data/unit/check-class-namedtuple.test @@ -408,7 +408,7 @@ class HasNone(NamedTuple): x: int y: Optional[int] = None -reveal_type(HasNone(1)) # E: Revealed type is 'Tuple[builtins.int, builtins.int, fallback=__main__.HasNone]' +reveal_type(HasNone(1)) # E: Revealed type is 'Tuple[builtins.int, Union[builtins.int, builtins.None], fallback=__main__.HasNone]' class Parameterized(NamedTuple): x: int diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 4f282a0d0fa0..d4cfb028ed11 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -383,6 +383,105 @@ if z: # E: Condition must be a boolean pass [builtins fixtures/bool.pyi] + +[case testPerFileStrictOptionalBasic] +# flags: --config-file tmp/mypy.ini +import standard, optional + +[file standard.py] +x = 0 +x = None +[file optional.py] +x = 0 +x = None # E: Incompatible types in assignment (expression has type None, variable has type "int") + +[file mypy.ini] +[[mypy] +strict_optional = False +[[mypy-optional] +strict_optional = True + + +[case testPerFileStrictOptionalBasicImportStandard] +# flags: --config-file tmp/mypy.ini +import standard, optional + +[file standard.py] +from typing import Optional +def f(x: int) -> None: pass +an_int = 0 # type: int +optional_int = None # type: Optional[int] +f(an_int) # ints can be used as ints +f(optional_int) # optional ints can be used as ints in this file + +[file optional.py] +import standard +def f(x: int) -> None: pass +standard.an_int = None # E: Incompatible types in assignment (expression has type None, variable has type "int") +standard.optional_int = None # OK -- explicitly declared as optional +f(standard.an_int) # ints can be used as ints +f(standard.optional_int) # E: Argument 1 to "f" has incompatible type None; expected "int" + +[file mypy.ini] +[[mypy] +strict_optional = False +[[mypy-optional] +strict_optional = True + + +[case testPerFileStrictOptionalBasicImportOptional] +# flags: --config-file tmp/mypy.ini +import standard, optional + +[file standard.py] +import optional +def f(x: int) -> None: pass +f(optional.x) # OK -- in non-strict Optional context +f(optional.y) # OK -- in non-strict Optional context + +[file optional.py] +from typing import Optional +def f(x: int) -> None: pass +x = 0 # type: Optional[int] +y = None # type: None + +[file mypy.ini] +[[mypy] +strict_optional = False +[[mypy-optional] +strict_optional = True + +[case testPerFileStrictOptionalListItemImportOptional] +# flags: --config-file tmp/mypy.ini +import standard, optional + +[file standard.py] +import optional +from typing import List +def f(x: List[int]) -> None: pass +f(optional.x) # OK -- in non-strict Optional context +f(optional.y) # OK -- in non-strict Optional context + +[file optional.py] +from typing import Optional, List +def f(x: List[int]) -> None: pass +x = [] # type: List[Optional[int]] +y = [] # type: List[int] + +[file mypy.ini] +[[mypy] +strict_optional = False +[[mypy-optional] +strict_optional = True +[builtins fixtures/list.pyi] + +[case testPerFileStrictOptionalComplicatedList] +from typing import Union, Optional, List + +def f() -> None: + x = [] # type: Union[List[Optional[str]], str] +[builtins fixtures/list.pyi] + [case testDisallowImplicitTypesIgnoreMissingTypes] # flags: --ignore-missing-imports --disallow-any=unimported from missing import MyType diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index 75ebaa081e44..beab7102882c 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -1233,7 +1233,7 @@ from typing import Optional def h(a: bool, x: object) -> Optional[int]: if a or isinstance(x, int): return None - return x # E: Incompatible return value type (got "object", expected "int") + return x # E: Incompatible return value type (got "object", expected "Optional[int]") [builtins fixtures/isinstance.pyi] [out] diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test index 6ab2d0fed017..7dfd22557f9d 100644 --- a/test-data/unit/check-unions.test +++ b/test-data/unit/check-unions.test @@ -129,7 +129,7 @@ from typing import Optional def f(x: Optional[int]) -> None: pass f(1) f(None) -f('') # E: Argument 1 to "f" has incompatible type "str"; expected "int" +f('') # E: Argument 1 to "f" has incompatible type "str"; expected "Optional[int]" [case testUnionSimplificationGenericFunction] from typing import TypeVar, Union, List diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test index a1333b69c5c1..294c0a107e5e 100644 --- a/test-data/unit/cmdline.test +++ b/test-data/unit/cmdline.test @@ -325,9 +325,9 @@ mypy.ini: [mypy]: ignore_missing_imports: Not a boolean: nah [file mypy.ini] [[mypy] [[mypy-*] -strict_optional = True +python_version = 3.4 [out] -mypy.ini: [mypy-*]: Per-module sections should only specify per-module flags (strict_optional) +mypy.ini: [mypy-*]: Per-module sections should only specify per-module flags (python_version) [case testAnyExprReportDivisionByZero] # cmd: mypy --any-exprs-report=out -c 'pass' diff --git a/test-data/unit/semanal-types.test b/test-data/unit/semanal-types.test index c1ec57f205de..d3db29acba65 100644 --- a/test-data/unit/semanal-types.test +++ b/test-data/unit/semanal-types.test @@ -1407,7 +1407,7 @@ MypyFile:1( f Args( Var(x)) - def (x: builtins.int) + def (x: Union[builtins.int, builtins.None]) Block:2( PassStmt:2()))) @@ -1421,7 +1421,7 @@ MypyFile:1( f Args( Var(x)) - def (x: Union[builtins.int, builtins.str]) + def (x: Union[builtins.int, builtins.None, builtins.str]) Block:2( PassStmt:2()))) @@ -1448,7 +1448,7 @@ MypyFile:1( AssignmentStmt:2( NameExpr(x [__main__.x]) IntExpr(1) - builtins.int)) + Union[builtins.int, builtins.None])) [case testInvalidOptionalType] from typing import Optional