diff --git a/mypy/backports.py b/mypy/backports.py new file mode 100644 index 0000000000000..df5afcb2416f7 --- /dev/null +++ b/mypy/backports.py @@ -0,0 +1,18 @@ +import sys +from contextlib import contextmanager +from typing import Iterator + +if sys.version_info < (3, 6): + from collections import OrderedDict as OrderedDict # noqa: F401 +else: + # OrderedDict is kind of slow, so for most of our uses in Python 3.6 + # and later we'd rather just use dict + OrderedDict = dict + + +if sys.version_info < (3, 7): + @contextmanager + def nullcontext() -> Iterator[None]: + yield +else: + from contextlib import nullcontext as nullcontext # noqa: F401 diff --git a/mypy/checker.py b/mypy/checker.py index dde8a3441c35d..35dd2b246f936 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1995,10 +1995,9 @@ def is_raising_or_empty(self, s: Statement) -> bool: if isinstance(s.expr, EllipsisExpr): return True elif isinstance(s.expr, CallExpr): - self.expr_checker.msg.disable_errors() - typ = get_proper_type(self.expr_checker.accept( - s.expr, allow_none_return=True, always_allow_any=True)) - self.expr_checker.msg.enable_errors() + with self.expr_checker.msg.disable_errors(): + typ = get_proper_type(self.expr_checker.accept( + s.expr, allow_none_return=True, always_allow_any=True)) if isinstance(typ, UninhabitedType): return True @@ -3050,14 +3049,13 @@ def check_member_assignment(self, instance_type: Type, attribute_type: Type, # For non-overloaded setters, the result should be type-checked like a regular assignment. # Hence, we first only try to infer the type by using the rvalue as type context. type_context = rvalue - self.msg.disable_errors() - _, inferred_dunder_set_type = self.expr_checker.check_call( - dunder_set_type, - [TempNode(instance_type, context=context), type_context], - [nodes.ARG_POS, nodes.ARG_POS], - context, object_type=attribute_type, - callable_name=callable_name) - self.msg.enable_errors() + with self.msg.disable_errors(): + _, inferred_dunder_set_type = self.expr_checker.check_call( + dunder_set_type, + [TempNode(instance_type, context=context), type_context], + [nodes.ARG_POS, nodes.ARG_POS], + context, object_type=attribute_type, + callable_name=callable_name) # And now we in fact type check the call, to show errors related to wrong arguments # count, etc., replacing the type context for non-overloaded setters only. diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 3bfe0a306446f..f24b8dfc8ff93 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1,6 +1,6 @@ """Expression type checker. This file is conceptually part of TypeChecker.""" -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict, nullcontext from contextlib import contextmanager import itertools from typing import ( @@ -865,12 +865,11 @@ def check_union_call_expr(self, e: CallExpr, object_type: UnionType, member: str res = [] # type: List[Type] for typ in object_type.relevant_items(): # Member access errors are already reported when visiting the member expression. - self.msg.disable_errors() - item = analyze_member_access(member, typ, e, False, False, False, - self.msg, original_type=object_type, chk=self.chk, - in_literal_context=self.is_literal_context(), - self_type=typ) - self.msg.enable_errors() + with self.msg.disable_errors(): + item = analyze_member_access(member, typ, e, False, False, False, + self.msg, original_type=object_type, chk=self.chk, + in_literal_context=self.is_literal_context(), + self_type=typ) narrowed = self.narrow_type_from_binder(e.callee, item, skip_non_overlapping=True) if narrowed is None: continue @@ -1203,12 +1202,9 @@ def infer_function_type_arguments(self, callee_type: CallableType, # due to partial available context information at this time, but # these errors can be safely ignored as the arguments will be # inferred again later. - self.msg.disable_errors() - - arg_types = self.infer_arg_types_in_context( - callee_type, args, arg_kinds, formal_to_actual) - - self.msg.enable_errors() + with self.msg.disable_errors(): + arg_types = self.infer_arg_types_in_context( + callee_type, args, arg_kinds, formal_to_actual) arg_pass_nums = self.get_arg_infer_passes( callee_type.arg_types, formal_to_actual, len(args)) @@ -2798,10 +2794,6 @@ def check_boolean_op(self, e: OpExpr, context: Context) -> Type: if left_map is None: self.msg.redundant_left_operand(e.op, e.left) - # If right_map is None then we know mypy considers the right branch - # to be unreachable and therefore any errors found in the right branch - # should be suppressed. - # # Note that we perform these checks *before* we take into account # the analysis from the semanal phase below. We assume that nodes # marked as unreachable during semantic analysis were done so intentionally. @@ -2815,13 +2807,11 @@ def check_boolean_op(self, e: OpExpr, context: Context) -> Type: elif e.right_always: left_map = None - if right_map is None: - self.msg.disable_errors() - try: + # If right_map is None then we know mypy considers the right branch + # to be unreachable and therefore any errors found in the right branch + # should be suppressed. + with (self.msg.disable_errors() if right_map is None else nullcontext()): right_type = self.analyze_cond_branch(right_map, e.right, left_type) - finally: - if right_map is None: - self.msg.enable_errors() if right_map is None: # The boolean expression is statically known to be the left value diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 64e693d52c962..d97f10f14b7e8 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -268,7 +268,7 @@ def analyze_type_type_member_access(name: str, item = None fallback = mx.builtin_type('builtins.type') ignore_messages = mx.msg.copy() - ignore_messages.disable_errors() + ignore_messages.disable_errors().__enter__() if isinstance(typ.item, Instance): item = typ.item elif isinstance(typ.item, AnyType): diff --git a/mypy/errors.py b/mypy/errors.py index b3f99916b244d..e4cbcca36798c 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -1,7 +1,7 @@ import os.path import sys import traceback -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from collections import defaultdict from typing import Tuple, List, TypeVar, Set, Dict, Optional, TextIO, Callable diff --git a/mypy/join.py b/mypy/join.py index 53a1fce973dc1..2b574fa740a98 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -1,6 +1,6 @@ """Calculation of the least upper bound types (joins).""" -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import List, Optional from mypy.types import ( diff --git a/mypy/meet.py b/mypy/meet.py index 558de6ec92c9c..9d93c47832e40 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -1,4 +1,4 @@ -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import List, Optional, Tuple, Callable from mypy.join import ( diff --git a/mypy/messages.py b/mypy/messages.py index 0d10b9bef5d6e..e2f40f3a188b2 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -8,13 +8,14 @@ Historically we tried to avoid all message string literals in the type checker but we are moving away from this convention. """ +from contextlib import contextmanager -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict import re import difflib from textwrap import dedent -from typing import cast, List, Dict, Any, Sequence, Iterable, Tuple, Set, Optional, Union +from typing import cast, List, Dict, Any, Sequence, Iterable, Iterator, Tuple, Set, Optional, Union from typing_extensions import Final from mypy.erasetype import erase_type @@ -136,11 +137,13 @@ def add_errors(self, messages: 'MessageBuilder') -> None: for info in errs: self.errors.add_error_info(info) - def disable_errors(self) -> None: + @contextmanager + def disable_errors(self) -> Iterator[None]: self.disable_count += 1 - - def enable_errors(self) -> None: - self.disable_count -= 1 + try: + yield + finally: + self.disable_count -= 1 def is_errors(self) -> bool: return self.errors.is_errors() diff --git a/mypy/nodes.py b/mypy/nodes.py index a50c76ca06cd6..c849578c599e1 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2,7 +2,7 @@ import os from abc import abstractmethod -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from collections import defaultdict from typing import ( Any, TypeVar, List, Tuple, cast, Set, Dict, Union, Optional, Callable, Sequence, Iterator diff --git a/mypy/nullcontext.py b/mypy/nullcontext.py new file mode 100644 index 0000000000000..805350261c518 --- /dev/null +++ b/mypy/nullcontext.py @@ -0,0 +1,10 @@ +import sys +from contextlib import contextmanager +from typing import Iterator + +if sys.version_info < (3, 7): + @contextmanager + def nullcontext() -> Iterator[None]: + yield +else: + from contextlib import nullcontext as nullcontext, contextmanager # noqa: F401 diff --git a/mypy/options.py b/mypy/options.py index 9e41ad7d310d9..1e5d0d52f4975 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -1,4 +1,4 @@ -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict import re import pprint import sys diff --git a/mypy/ordered_dict.py b/mypy/ordered_dict.py index f1e78ac242f70..e69de29bb2d1d 100644 --- a/mypy/ordered_dict.py +++ b/mypy/ordered_dict.py @@ -1,9 +0,0 @@ -# OrderedDict is kind of slow, so for most of our uses in Python 3.6 -# and later we'd rather just use dict - -import sys - -if sys.version_info < (3, 6): - from collections import OrderedDict as OrderedDict -else: - OrderedDict = dict diff --git a/mypy/plugins/attrs.py b/mypy/plugins/attrs.py index 0c4b4b0c701f1..8e3f77527d945 100644 --- a/mypy/plugins/attrs.py +++ b/mypy/plugins/attrs.py @@ -1,6 +1,6 @@ """Plugin for supporting the attrs library (http://www.attrs.org)""" -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import Optional, Dict, List, cast, Tuple, Iterable from typing_extensions import Final diff --git a/mypy/semanal_typeddict.py b/mypy/semanal_typeddict.py index 0b0891d83fb65..14e62b5929bd1 100644 --- a/mypy/semanal_typeddict.py +++ b/mypy/semanal_typeddict.py @@ -1,6 +1,6 @@ """Semantic analysis of TypedDict definitions.""" -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import Optional, List, Set, Tuple from typing_extensions import Final diff --git a/mypy/type_visitor.py b/mypy/type_visitor.py index a0e6299a5a8a0..aa61e58d4c67c 100644 --- a/mypy/type_visitor.py +++ b/mypy/type_visitor.py @@ -12,7 +12,7 @@ """ from abc import abstractmethod -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import Generic, TypeVar, cast, Any, List, Callable, Iterable, Optional, Set, Sequence from mypy_extensions import trait, mypyc_attr diff --git a/mypy/typeanal.py b/mypy/typeanal.py index d9e7764ba3f8e..084d955f7c08d 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -3,7 +3,7 @@ import itertools from itertools import chain from contextlib import contextmanager -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import Callable, List, Optional, Set, Tuple, Iterator, TypeVar, Iterable, Sequence from typing_extensions import Final diff --git a/mypy/types.py b/mypy/types.py index d9c71fbcf7ee3..7aa83a75f431b 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -3,7 +3,7 @@ import copy import sys from abc import abstractmethod -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import ( Any, TypeVar, Dict, List, Tuple, cast, Set, Optional, Union, Iterable, NamedTuple, diff --git a/mypyc/codegen/emit.py b/mypyc/codegen/emit.py index e8b3c77be9d65..769888e5ad6ef 100644 --- a/mypyc/codegen/emit.py +++ b/mypyc/codegen/emit.py @@ -1,6 +1,6 @@ """Utilities for emitting C code.""" -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import List, Set, Dict, Optional, Callable, Union, Tuple import sys diff --git a/mypyc/codegen/emitclass.py b/mypyc/codegen/emitclass.py index 0cfaab07b5730..080e72ce3dcd6 100644 --- a/mypyc/codegen/emitclass.py +++ b/mypyc/codegen/emitclass.py @@ -2,7 +2,7 @@ from typing import Optional, List, Tuple, Dict, Callable, Mapping, Set -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from mypyc.common import PREFIX, NATIVE_PREFIX, REG_PREFIX, use_fastcall from mypyc.codegen.emit import Emitter, HeaderDeclaration diff --git a/mypyc/codegen/emitmodule.py b/mypyc/codegen/emitmodule.py index 476c435712bd4..ec89aa767ca1a 100644 --- a/mypyc/codegen/emitmodule.py +++ b/mypyc/codegen/emitmodule.py @@ -5,7 +5,7 @@ import os import json -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import List, Tuple, Dict, Iterable, Set, TypeVar, Optional from mypy.nodes import MypyFile diff --git a/mypyc/ir/class_ir.py b/mypyc/ir/class_ir.py index aeb0f8410c56c..6577c9a77e952 100644 --- a/mypyc/ir/class_ir.py +++ b/mypyc/ir/class_ir.py @@ -1,7 +1,7 @@ """Intermediate representation of classes.""" from typing import List, Optional, Set, Tuple, Dict, NamedTuple -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from mypyc.common import JsonDict from mypyc.ir.ops import Value, DeserMaps diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py index 0b2a6537c5ea7..e1a82287fe40a 100644 --- a/mypyc/irbuild/builder.py +++ b/mypyc/irbuild/builder.py @@ -13,7 +13,7 @@ from typing import Callable, Dict, List, Tuple, Optional, Union, Sequence, Set, Any from typing_extensions import overload -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from mypy.build import Graph from mypy.nodes import ( diff --git a/mypyc/irbuild/main.py b/mypyc/irbuild/main.py index 457b535cdbfe1..c11ff967f357b 100644 --- a/mypyc/irbuild/main.py +++ b/mypyc/irbuild/main.py @@ -20,7 +20,7 @@ def f(x: int) -> int: below, mypyc.irbuild.builder, and mypyc.irbuild.visitor. """ -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from typing import List, Dict, Callable, Any, TypeVar, cast from mypy.nodes import MypyFile, Expression, ClassDef diff --git a/mypyc/test/test_emitfunc.py b/mypyc/test/test_emitfunc.py index 11f46fc469190..5503c09d3c667 100644 --- a/mypyc/test/test_emitfunc.py +++ b/mypyc/test/test_emitfunc.py @@ -2,7 +2,7 @@ from typing import List, Optional -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from mypy.test.helpers import assert_string_arrays_equal diff --git a/mypyc/test/test_serialization.py b/mypyc/test/test_serialization.py index 338be1aedb85e..5737ccc7b6238 100644 --- a/mypyc/test/test_serialization.py +++ b/mypyc/test/test_serialization.py @@ -4,7 +4,7 @@ # contain its own tests so that pytest will rewrite the asserts... from typing import Any, Dict, Tuple -from mypy.ordered_dict import OrderedDict +from mypy.backports import OrderedDict from collections.abc import Iterable from mypyc.ir.ops import DeserMaps