[med-svn] [Git][python-team/packages/mypy][upstream] New upstream version 0.942

Stefano Rivera (@stefanor) gitlab at salsa.debian.org
Sun Apr 3 03:09:45 BST 2022



Stefano Rivera pushed to branch upstream at Debian Python Team / packages / mypy


Commits:
495a349c by Stefano Rivera at 2022-04-02T19:17:16-04:00
New upstream version 0.942
- - - - -


20 changed files:

- PKG-INFO
- mypy.egg-info/PKG-INFO
- mypy/build.py
- mypy/checker.py
- mypy/checkpattern.py
- mypy/fastparse.py
- mypy/message_registry.py
- mypy/nodes.py
- mypy/plugins/attrs.py
- mypy/plugins/common.py
- mypy/plugins/dataclasses.py
- mypy/semanal.py
- mypy/version.py
- test-data/unit/check-attr.test
- test-data/unit/check-dataclasses.test
- test-data/unit/check-enum.test
- test-data/unit/check-overloading.test
- test-data/unit/check-python310.test
- test-data/unit/fine-grained.test
- test-requirements.txt


Changes:

=====================================
PKG-INFO
=====================================
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: mypy
-Version: 0.941
+Version: 0.942
 Summary: Optional static typing for Python
 Home-page: http://www.mypy-lang.org/
 Author: Jukka Lehtosalo


=====================================
mypy.egg-info/PKG-INFO
=====================================
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: mypy
-Version: 0.941
+Version: 0.942
 Summary: Optional static typing for Python
 Home-page: http://www.mypy-lang.org/
 Author: Jukka Lehtosalo


=====================================
mypy/build.py
=====================================
@@ -2959,12 +2959,16 @@ def process_graph(graph: Graph, manager: BuildManager) -> None:
         # Order the SCC's nodes using a heuristic.
         # Note that ascc is a set, and scc is a list.
         scc = order_ascc(graph, ascc)
-        # If builtins is in the list, move it last.  (This is a bit of
-        # a hack, but it's necessary because the builtins module is
-        # part of a small cycle involving at least {builtins, abc,
-        # typing}.  Of these, builtins must be processed last or else
-        # some builtin objects will be incompletely processed.)
+        # Make the order of the SCC that includes 'builtins' and 'typing',
+        # among other things, predictable. Various things may  break if
+        # the order changes.
         if 'builtins' in ascc:
+            scc = sorted(scc, reverse=True)
+            # If builtins is in the list, move it last.  (This is a bit of
+            # a hack, but it's necessary because the builtins module is
+            # part of a small cycle involving at least {builtins, abc,
+            # typing}.  Of these, builtins must be processed last or else
+            # some builtin objects will be incompletely processed.)
             scc.remove('builtins')
             scc.append('builtins')
         if manager.options.verbosity >= 2:


=====================================
mypy/checker.py
=====================================
@@ -600,7 +600,8 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
                     self.msg.overloaded_signatures_arg_specific(i + 1, defn.impl)
 
                 # Is the overload alternative's return type a subtype of the implementation's?
-                if not is_subtype_no_promote(sig1.ret_type, impl.ret_type):
+                if not (is_subtype_no_promote(sig1.ret_type, impl.ret_type) or
+                        is_subtype_no_promote(impl.ret_type, sig1.ret_type)):
                     self.msg.overloaded_signatures_ret_specific(i + 1, defn.impl)
 
     # Here's the scoop about generators and coroutines.
@@ -1439,12 +1440,7 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
             self.msg.invalid_signature_for_special_method(typ, context, '__setattr__')
 
     def check_match_args(self, var: Var, typ: Type, context: Context) -> None:
-        """Check that __match_args__ is final and contains literal strings"""
-
-        if not var.is_final:
-            self.note("__match_args__ must be final for checking of match statements to work",
-                      context, code=codes.LITERAL_REQ)
-
+        """Check that __match_args__ contains literal strings"""
         typ = get_proper_type(typ)
         if not isinstance(typ, TupleType) or \
                 not all([is_string_literal(item) for item in typ.items]):
@@ -1834,11 +1830,7 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
         if typ.is_protocol and typ.defn.type_vars:
             self.check_protocol_variance(defn)
         if not defn.has_incompatible_baseclass and defn.info.is_enum:
-            for base in defn.info.mro[1:-1]:  # we don't need self and `object`
-                if base.is_enum and base.fullname not in ENUM_BASES:
-                    self.check_final_enum(defn, base)
-            self.check_enum_bases(defn)
-            self.check_enum_new(defn)
+            self.check_enum(defn)
 
     def check_final_deletable(self, typ: TypeInfo) -> None:
         # These checks are only for mypyc. Only perform some checks that are easier
@@ -1896,6 +1888,24 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
             # all other bases have already been checked.
             break
 
+    def check_enum(self, defn: ClassDef) -> None:
+        assert defn.info.is_enum
+        if defn.info.fullname not in ENUM_BASES:
+            for sym in defn.info.names.values():
+                if (isinstance(sym.node, Var) and sym.node.has_explicit_value and
+                        sym.node.name == '__members__'):
+                    # `__members__` will always be overwritten by `Enum` and is considered
+                    # read-only so we disallow assigning a value to it
+                    self.fail(
+                        message_registry.ENUM_MEMBERS_ATTR_WILL_BE_OVERRIDEN, sym.node
+                    )
+        for base in defn.info.mro[1:-1]:  # we don't need self and `object`
+            if base.is_enum and base.fullname not in ENUM_BASES:
+                self.check_final_enum(defn, base)
+
+        self.check_enum_bases(defn)
+        self.check_enum_new(defn)
+
     def check_final_enum(self, defn: ClassDef, base: TypeInfo) -> None:
         for sym in base.names.values():
             if self.is_final_enum_value(sym):
@@ -2103,8 +2113,9 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
             self.msg.cant_override_final(name, base2.name, ctx)
         if is_final_node(first.node):
             self.check_if_final_var_override_writable(name, second.node, ctx)
-        # __slots__ and __deletable__ are special and the type can vary across class hierarchy.
-        if name in ('__slots__', '__deletable__'):
+        # Some attributes like __slots__ and __deletable__ are special, and the type can
+        # vary across class hierarchy.
+        if isinstance(second.node, Var) and second.node.allow_incompatible_override:
             ok = True
         if not ok:
             self.msg.base_class_definitions_incompatible(name, base1, base2,
@@ -2276,11 +2287,16 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
 
             # Defer PartialType's super type checking.
             if (isinstance(lvalue, RefExpr) and
-                    not (isinstance(lvalue_type, PartialType) and lvalue_type.type is None)):
+                    not (isinstance(lvalue_type, PartialType) and
+                         lvalue_type.type is None) and
+                    not (isinstance(lvalue, NameExpr) and lvalue.name == '__match_args__')):
                 if self.check_compatibility_all_supers(lvalue, lvalue_type, rvalue):
                     # We hit an error on this line; don't check for any others
                     return
 
+            if isinstance(lvalue, MemberExpr) and lvalue.name == '__match_args__':
+                self.fail(message_registry.CANNOT_MODIFY_MATCH_ARGS, lvalue)
+
             if lvalue_type:
                 if isinstance(lvalue_type, PartialType) and lvalue_type.type is None:
                     # Try to infer a proper type for a variable with a partial None type.
@@ -2377,7 +2393,8 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
 
             if inferred:
                 rvalue_type = self.expr_checker.accept(rvalue)
-                if not inferred.is_final:
+                if not (inferred.is_final or (isinstance(lvalue, NameExpr) and
+                                              lvalue.name == '__match_args__')):
                     rvalue_type = remove_instance_last_known_values(rvalue_type)
                 self.infer_variable_type(inferred, lvalue, rvalue_type, rvalue)
             self.check_assignment_to_slots(lvalue)
@@ -2460,16 +2477,12 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
             last_immediate_base = direct_bases[-1] if direct_bases else None
 
             for base in lvalue_node.info.mro[1:]:
-                # Only check __slots__ against the 'object'
-                # If a base class defines a Tuple of 3 elements, a child of
-                # this class should not be allowed to define it as a Tuple of
-                # anything other than 3 elements. The exception to this rule
-                # is __slots__, where it is allowed for any child class to
-                # redefine it.
-                if lvalue_node.name == "__slots__" and base.fullname != "builtins.object":
-                    continue
-                # We don't care about the type of "__deletable__".
-                if lvalue_node.name == "__deletable__":
+                # The type of "__slots__" and some other attributes usually doesn't need to
+                # be compatible with a base class. We'll still check the type of "__slots__"
+                # against "object" as an exception.
+                if (isinstance(lvalue_node, Var) and lvalue_node.allow_incompatible_override and
+                        not (lvalue_node.name == "__slots__" and
+                             base.fullname == "builtins.object")):
                     continue
 
                 if is_private(lvalue_node.name):


=====================================
mypy/checkpattern.py
=====================================
@@ -463,7 +463,8 @@ class PatternChecker(PatternVisitor[PatternType]):
         # Check class type
         #
         type_info = o.class_ref.node
-        assert type_info is not None
+        if type_info is None:
+            return PatternType(AnyType(TypeOfAny.from_error), AnyType(TypeOfAny.from_error), {})
         if isinstance(type_info, TypeAlias) and not type_info.no_args:
             self.msg.fail(message_registry.CLASS_PATTERN_GENERIC_TYPE_ALIAS, o)
             return self.early_non_match()


=====================================
mypy/fastparse.py
=====================================
@@ -486,6 +486,7 @@ class ASTConverter:
         ret: List[Statement] = []
         current_overload: List[OverloadPart] = []
         current_overload_name: Optional[str] = None
+        seen_unconditional_func_def = False
         last_if_stmt: Optional[IfStmt] = None
         last_if_overload: Optional[Union[Decorator, FuncDef, OverloadedFuncDef]] = None
         last_if_stmt_overload_name: Optional[str] = None
@@ -498,6 +499,7 @@ class ASTConverter:
             if (
                 isinstance(stmt, IfStmt)
                 and len(stmt.body[0].body) == 1
+                and seen_unconditional_func_def is False
                 and (
                     isinstance(stmt.body[0].body[0], (Decorator, OverloadedFuncDef))
                     or current_overload_name is not None
@@ -527,6 +529,8 @@ class ASTConverter:
                     self.fail_merge_overload(last_if_unknown_truth_value)
                     last_if_unknown_truth_value = None
                 current_overload.append(stmt)
+                if isinstance(stmt, FuncDef):
+                    seen_unconditional_func_def = True
             elif (
                 current_overload_name is not None
                 and isinstance(stmt, IfStmt)
@@ -583,6 +587,7 @@ class ASTConverter:
                 # most of mypy/mypyc assumes that all the functions in an OverloadedFuncDef are
                 # related, but multiple underscore functions next to each other aren't necessarily
                 # related
+                seen_unconditional_func_def = False
                 if isinstance(stmt, Decorator) and not unnamed_function(stmt.name):
                     current_overload = [stmt]
                     current_overload_name = stmt.name


=====================================
mypy/message_registry.py
=====================================
@@ -204,6 +204,11 @@ CANNOT_ACCESS_FINAL_INSTANCE_ATTR: Final = (
 )
 CANNOT_MAKE_DELETABLE_FINAL: Final = ErrorMessage("Deletable attribute cannot be final")
 
+# Enum
+ENUM_MEMBERS_ATTR_WILL_BE_OVERRIDEN: Final = ErrorMessage(
+    'Assigned "__members__" will be overriden by "Enum" internally'
+)
+
 # ClassVar
 CANNOT_OVERRIDE_INSTANCE_VAR: Final = ErrorMessage(
     'Cannot override instance variable (previously declared on base class "{}") with class '
@@ -245,3 +250,4 @@ CLASS_PATTERN_KEYWORD_MATCHES_POSITIONAL: Final = (
 CLASS_PATTERN_DUPLICATE_KEYWORD_PATTERN: Final = 'Duplicate keyword pattern "{}"'
 CLASS_PATTERN_UNKNOWN_KEYWORD: Final = 'Class "{}" has no attribute "{}"'
 MULTIPLE_ASSIGNMENTS_IN_PATTERN: Final = 'Multiple assignments to name "{}" in pattern'
+CANNOT_MODIFY_MATCH_ARGS: Final = 'Cannot assign to "__match_args__"'


=====================================
mypy/nodes.py
=====================================
@@ -852,7 +852,7 @@ VAR_FLAGS: Final = [
     'is_classmethod', 'is_property', 'is_settable_property', 'is_suppressed_import',
     'is_classvar', 'is_abstract_var', 'is_final', 'final_unset_in_class', 'final_set_in_init',
     'explicit_self_type', 'is_ready', 'from_module_getattr',
-    'has_explicit_value',
+    'has_explicit_value', 'allow_incompatible_override',
 ]
 
 
@@ -884,6 +884,7 @@ class Var(SymbolNode):
                  'explicit_self_type',
                  'from_module_getattr',
                  'has_explicit_value',
+                 'allow_incompatible_override',
                  )
 
     def __init__(self, name: str, type: 'Optional[mypy.types.Type]' = None) -> None:
@@ -931,6 +932,8 @@ class Var(SymbolNode):
         # Var can be created with an explicit value `a = 1` or without one `a: int`,
         # we need a way to tell which one is which.
         self.has_explicit_value = False
+        # If True, subclasses can override this with an incompatible type.
+        self.allow_incompatible_override = False
 
     @property
     def name(self) -> str:


=====================================
mypy/plugins/attrs.py
=====================================
@@ -744,6 +744,7 @@ def _add_attrs_magic_attribute(ctx: 'mypy.plugin.ClassDefContext',
     var.info = ctx.cls.info
     var.is_classvar = True
     var._fullname = f"{ctx.cls.fullname}.{MAGIC_ATTR_CLS_NAME}"
+    var.allow_incompatible_override = True
     ctx.cls.info.names[MAGIC_ATTR_NAME] = SymbolTableNode(
         kind=MDEF,
         node=var,
@@ -778,7 +779,6 @@ def _add_match_args(ctx: 'mypy.plugin.ClassDefContext',
             cls=ctx.cls,
             name='__match_args__',
             typ=match_args,
-            final=True,
         )
 
 


=====================================
mypy/plugins/common.py
=====================================
@@ -5,7 +5,7 @@ from mypy.nodes import (
     FuncDef, PassStmt, RefExpr, SymbolTableNode, Var, JsonDict,
 )
 from mypy.plugin import CheckerPluginInterface, ClassDefContext, SemanticAnalyzerPluginInterface
-from mypy.semanal import set_callable_name
+from mypy.semanal import set_callable_name, ALLOW_INCOMPATIBLE_OVERRIDE
 from mypy.types import (
     CallableType, Overloaded, Type, TypeVarType, deserialize_type, get_proper_type,
 )
@@ -163,6 +163,7 @@ def add_attribute_to_class(
         typ: Type,
         final: bool = False,
         no_serialize: bool = False,
+        override_allow_incompatible: bool = False,
 ) -> None:
     """
     Adds a new attribute to a class definition.
@@ -180,6 +181,10 @@ def add_attribute_to_class(
     node = Var(name, typ)
     node.info = info
     node.is_final = final
+    if name in ALLOW_INCOMPATIBLE_OVERRIDE:
+        node.allow_incompatible_override = True
+    else:
+        node.allow_incompatible_override = override_allow_incompatible
     node._fullname = info.fullname + '.' + name
     info.names[name] = SymbolTableNode(
         MDEF,


=====================================
mypy/plugins/dataclasses.py
=====================================
@@ -227,7 +227,7 @@ class DataclassTransformer:
             literals: List[Type] = [LiteralType(attr.name, str_type)
                         for attr in attributes if attr.is_in_init]
             match_args_type = TupleType(literals, ctx.api.named_type("builtins.tuple"))
-            add_attribute_to_class(ctx.api, ctx.cls, "__match_args__", match_args_type, final=True)
+            add_attribute_to_class(ctx.api, ctx.cls, "__match_args__", match_args_type)
 
         self._add_dataclass_fields_magic_attribute()
 


=====================================
mypy/semanal.py
=====================================
@@ -116,6 +116,7 @@ from mypy.plugin import (
 )
 from mypy.util import (
     correct_relative_import, unmangle, module_prefix, is_typeshed_file, unnamed_function,
+    is_dunder,
 )
 from mypy.scope import Scope
 from mypy.semanal_shared import (
@@ -152,6 +153,10 @@ FUTURE_IMPORTS: Final = {
 # available very early on.
 CORE_BUILTIN_CLASSES: Final = ["object", "bool", "function"]
 
+# Subclasses can override these Var attributes with incompatible types. This can also be
+# set for individual attributes using 'allow_incompatible_override' of Var.
+ALLOW_INCOMPATIBLE_OVERRIDE: Final = ('__slots__', '__deletable__', '__match_args__')
+
 
 # Used for tracking incomplete references
 Tag: _TypeAlias = int
@@ -2473,8 +2478,9 @@ class SemanticAnalyzer(NodeVisitor[None],
                     cur_node = self.type.names.get(lval.name, None)
                     if (cur_node and isinstance(cur_node.node, Var) and
                             not (isinstance(s.rvalue, TempNode) and s.rvalue.no_rhs)):
-                        cur_node.node.is_final = True
-                        s.is_final_def = True
+                        # Double underscored members are writable on an `Enum`.
+                        # (Except read-only `__members__` but that is handled in type checker)
+                        cur_node.node.is_final = s.is_final_def = not is_dunder(cur_node.node.name)
 
                 # Special case: deferred initialization of a final attribute in __init__.
                 # In this case we just pretend this is a valid final definition to suppress
@@ -2908,18 +2914,20 @@ class SemanticAnalyzer(NodeVisitor[None],
         self, lvalue: NameExpr, kind: int, inferred: bool, has_explicit_value: bool,
     ) -> Var:
         """Return a Var node for an lvalue that is a name expression."""
-        v = Var(lvalue.name)
+        name = lvalue.name
+        v = Var(name)
         v.set_line(lvalue)
         v.is_inferred = inferred
         if kind == MDEF:
             assert self.type is not None
             v.info = self.type
             v.is_initialized_in_class = True
+            v.allow_incompatible_override = name in ALLOW_INCOMPATIBLE_OVERRIDE
         if kind != LDEF:
-            v._fullname = self.qualified_name(lvalue.name)
+            v._fullname = self.qualified_name(name)
         else:
             # fullanme should never stay None
-            v._fullname = lvalue.name
+            v._fullname = name
         v.is_ready = False  # Type not inferred yet
         v.has_explicit_value = has_explicit_value
         return v


=====================================
mypy/version.py
=====================================
@@ -5,7 +5,7 @@ from mypy import git
 # - Release versions have the form "0.NNN".
 # - Dev versions have the form "0.NNN+dev" (PLUS sign to conform to PEP 440).
 # - For 1.0 we'll switch back to 1.2.3 form.
-__version__ = '0.941'
+__version__ = '0.942'
 base_version = __version__
 
 mypy_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))


=====================================
test-data/unit/check-attr.test
=====================================
@@ -1539,3 +1539,19 @@ n: NoMatchArgs
 reveal_type(n.__match_args__)  # E: "NoMatchArgs" has no attribute "__match_args__" \
                                # N: Revealed type is "Any"
 [builtins fixtures/attr.pyi]
+
+[case testAttrsMultipleInheritance]
+# flags: --python-version 3.10
+import attr
+
+ at attr.s
+class A:
+    x = attr.ib(type=int)
+
+ at attr.s
+class B:
+    y = attr.ib(type=int)
+
+class AB(A, B):
+    pass
+[builtins fixtures/attr.pyi]


=====================================
test-data/unit/check-dataclasses.test
=====================================
@@ -1536,3 +1536,19 @@ A(a=1, b=2)
 A(1)
 A(a="foo")  # E: Argument "a" to "A" has incompatible type "str"; expected "int"
 [builtins fixtures/dataclasses.pyi]
+
+[case testDataclassesMultipleInheritanceWithNonDataclass]
+# flags: --python-version 3.10
+from dataclasses import dataclass
+
+ at dataclass
+class A:
+    prop_a: str
+
+ at dataclass
+class B:
+    prop_b: bool
+
+class Derived(A, B):
+    pass
+[builtins fixtures/dataclasses.pyi]


=====================================
test-data/unit/check-enum.test
=====================================
@@ -2029,3 +2029,54 @@ class C(Enum):
 
 C._ignore_ # E: "Type[C]" has no attribute "_ignore_"
 [typing fixtures/typing-medium.pyi]
+
+[case testCanOverrideDunderAttributes]
+import typing
+from enum import Enum, Flag
+
+class BaseEnum(Enum):
+    __dunder__ = 1
+    __labels__: typing.Dict[int, str]
+
+class Override(BaseEnum):
+    __dunder__ = 2
+    __labels__ = {1: "1"}
+
+Override.__dunder__ = 3
+BaseEnum.__dunder__ = 3
+Override.__labels__ = {2: "2"}
+
+class FlagBase(Flag):
+    __dunder__ = 1
+    __labels__: typing.Dict[int, str]
+
+class FlagOverride(FlagBase):
+    __dunder__ = 2
+    __labels = {1: "1"}
+
+FlagOverride.__dunder__ = 3
+FlagBase.__dunder__ = 3
+FlagOverride.__labels__ = {2: "2"}
+[builtins fixtures/dict.pyi]
+
+[case testCanNotInitialize__members__]
+import typing
+from enum import Enum
+
+class WritingMembers(Enum):
+    __members__: typing.Dict[Enum, Enum] = {}  # E: Assigned "__members__" will be overriden by "Enum" internally
+
+class OnlyAnnotatedMembers(Enum):
+    __members__: typing.Dict[Enum, Enum]
+[builtins fixtures/dict.pyi]
+
+[case testCanOverrideDunderOnNonFirstBaseEnum]
+import typing
+from enum import Enum
+
+class Some:
+    __labels__: typing.Dict[int, str]
+
+class A(Some, Enum):
+    __labels__ = {1: "1"}
+[builtins fixtures/dict.pyi]


=====================================
test-data/unit/check-overloading.test
=====================================
@@ -6302,3 +6302,50 @@ if True:
     def f12(x): ...
 reveal_type(f12(A()))  # N: Revealed type is "__main__.A"
 [typing fixtures/typing-medium.pyi]
+
+[case testOverloadIfUnconditionalFuncDef]
+# flags: --always-true True --always-false False
+from typing import overload
+
+class A: ...
+class B: ...
+
+# -----
+# Don't merge conditional FuncDef after unconditional one
+# -----
+
+ at overload
+def f1(x: A) -> A: ...
+ at overload
+def f1(x: B) -> B: ...
+def f1(x): ...
+
+ at overload
+def f2(x: A) -> A: ...
+if True:
+    @overload
+    def f2(x: B) -> B: ...
+def f2(x): ...
+if True:
+    def f2(x): ...  # E: Name "f2" already defined on line 17
+
+[case testOverloadItemHasMoreGeneralReturnType]
+from typing import overload
+
+ at overload
+def f() -> object: ...
+
+ at overload
+def f(x: int) -> object: ...
+
+def f(x: int = 0) -> int:
+    return x
+
+ at overload
+def g() -> object: ...
+
+ at overload
+def g(x: int) -> str: ...
+
+def g(x: int = 0) -> int:  # E: Overloaded function implementation cannot produce return type of signature 2
+    return x


=====================================
test-data/unit/check-python310.test
=====================================
@@ -567,6 +567,20 @@ match m:
         reveal_type(m)  # N: Revealed type is "builtins.tuple[Any, ...]"
 [builtins fixtures/primitives.pyi]
 
+[case testMatchInvalidClassPattern]
+m: object
+
+match m:
+    case xyz(y):  # E: Name "xyz" is not defined
+        reveal_type(m)  # N: Revealed type is "Any"
+        reveal_type(y)  # E: Cannot determine type of "y" \
+                        # N: Revealed type is "Any"
+
+match m:
+    case xyz(z=x):  # E: Name "xyz" is not defined
+        reveal_type(x)  # E: Cannot determine type of "x" \
+                        # N: Revealed type is "Any"
+
 [case testMatchClassPatternCaptureDataclass]
 from dataclasses import dataclass
 
@@ -881,7 +895,7 @@ reveal_type(z)  # N: Revealed type is "builtins.int*"
 
 [case testMatchNonFinalMatchArgs]
 class A:
-    __match_args__ = ("a", "b")  # N: __match_args__ must be final for checking of match statements to work
+    __match_args__ = ("a", "b")
     a: str
     b: int
 
@@ -889,8 +903,8 @@ m: object
 
 match m:
     case A(i, j):
-        reveal_type(i)  # N: Revealed type is "Any"
-        reveal_type(j)  # N: Revealed type is "Any"
+        reveal_type(i)  # N: Revealed type is "builtins.str"
+        reveal_type(j)  # N: Revealed type is "builtins.int"
 [builtins fixtures/tuple.pyi]
 
 [case testMatchAnyTupleMatchArgs]
@@ -1528,3 +1542,37 @@ class A:
 class B:
     def __enter__(self) -> B: ...
     def __exit__(self, x, y, z) -> None: ...
+
+[case testOverrideMatchArgs]
+class AST:
+   __match_args__ = ()
+
+class stmt(AST): ...
+
+class AnnAssign(stmt):
+   __match_args__ = ('target', 'annotation', 'value', 'simple')
+   target: str
+   annotation: int
+   value: str
+   simple: int
+
+reveal_type(AST.__match_args__)  # N: Revealed type is "Tuple[]"
+reveal_type(stmt.__match_args__)  # N: Revealed type is "Tuple[]"
+reveal_type(AnnAssign.__match_args__)  # N: Revealed type is "Tuple[Literal['target']?, Literal['annotation']?, Literal['value']?, Literal['simple']?]"
+
+AnnAssign.__match_args__ = ('a', 'b', 'c', 'd')  # E: Cannot assign to "__match_args__"
+__match_args__ = 0
+
+def f(x: AST) -> None:
+    match x:
+        case AST():
+            reveal_type(x)  # N: Revealed type is "__main__.AST"
+    match x:
+        case stmt():
+            reveal_type(x)  # N: Revealed type is "__main__.stmt"
+    match x:
+        case AnnAssign(a, b, c, d):
+            reveal_type(a)  # N: Revealed type is "builtins.str"
+            reveal_type(b)  # N: Revealed type is "builtins.int"
+            reveal_type(c)  # N: Revealed type is "builtins.str"
+[builtins fixtures/tuple.pyi]


=====================================
test-data/unit/fine-grained.test
=====================================
@@ -2084,6 +2084,7 @@ a.py:5: error: "list" expects 1 type argument, but 2 given
 ==
 
 [case testPreviousErrorInOverloadedFunction]
+# flags: --strict-optional
 import a
 [file a.py]
 from typing import overload


=====================================
test-requirements.txt
=====================================
@@ -2,7 +2,7 @@
 -r build-requirements.txt
 attrs>=18.0
 flake8==3.9.2
-flake8-bugbear
+flake8-bugbear==22.3.20
 flake8-pyi>=20.5
 lxml>=4.4.0; python_version<'3.11'
 psutil>=4.0



View it on GitLab: https://salsa.debian.org/python-team/packages/mypy/-/commit/495a349c0a2959ff795fe24bd20145b5dc8a84a0

-- 
View it on GitLab: https://salsa.debian.org/python-team/packages/mypy/-/commit/495a349c0a2959ff795fe24bd20145b5dc8a84a0
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20220403/459e5202/attachment-0001.htm>


More information about the debian-med-commit mailing list