[med-svn] [Git][python-team/packages/mypy][master] 7 commits: typo

Michael R. Crusoe (@crusoe) gitlab at salsa.debian.org
Wed Apr 15 14:08:40 BST 2026



Michael R. Crusoe pushed to branch master at Debian Python Team / packages / mypy


Commits:
1c40952d by Michael R. Crusoe at 2026-04-02T15:29:14+02:00
typo

- - - - -
fdfbe180 by Michael R. Crusoe at 2026-04-02T15:29:43+02:00
Upload to experimental

- - - - -
3dcad89d by Michael R. Crusoe at 2026-04-13T10:33:45+02:00
New upstream version

- - - - -
320e1c9d by Michael R. Crusoe at 2026-04-15T14:46:16+02:00
Merge branch 'debian/experimental'

- - - - -
af0395ef by Michael R. Crusoe at 2026-04-15T14:47:03+02:00
New upstream version 1.20.1
- - - - -
c1eda144 by Michael R. Crusoe at 2026-04-15T14:47:42+02:00
Update upstream source from tag 'upstream/1.20.1'

Update to upstream version '1.20.1'
with Debian dir fc6b9ec8a0df497ca0fb0a71e7a5f750b253e0cb
- - - - -
6fb0d61c by Michael R. Crusoe at 2026-04-15T15:07:19+02:00
upload to unstable

- - - - -


18 changed files:

- PKG-INFO
- debian/changelog
- mypy.egg-info/PKG-INFO
- mypy/build.py
- mypy/checker.py
- mypy/checkexpr.py
- mypy/checkpattern.py
- mypy/main.py
- mypy/metastore.py
- mypy/typeshed/stdlib/builtins.pyi
- mypy/version.py
- mypyc/test-data/run-base64.test
- test-data/unit/check-expressions.test
- test-data/unit/check-isinstance.test
- test-data/unit/check-narrowing.test
- test-data/unit/check-python310.test
- test-data/unit/check-statements.test
- test-data/unit/pythoneval.test


Changes:

=====================================
PKG-INFO
=====================================
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: mypy
-Version: 1.20.0
+Version: 1.20.1
 Summary: Optional static typing for Python
 Author-email: Jukka Lehtosalo <jukka.lehtosalo at iki.fi>
 License-Expression: MIT


=====================================
debian/changelog
=====================================
@@ -1,6 +1,13 @@
-mypy (1.20.0-1) UNRELEASED; urgency=medium
+mypy (1.20.1-1) unstable; urgency=medium
 
   * New upstream version
+
+ -- Michael R. Crusoe <crusoe at debian.org>  Wed, 15 Apr 2026 15:06:53 +0200
+
+mypy (1.20.0-0exp0) experimental; urgency=medium
+
+  * New upstream version
+  * Upload to experimental
   * Standards-Version: 4.7.4 (routine-update)
   * Remove patch librt_cache that is missing from debian/patches/series.
   * d/rules: skip testAllBase64Features_librt as per upstream's advice


=====================================
mypy.egg-info/PKG-INFO
=====================================
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: mypy
-Version: 1.20.0
+Version: 1.20.1
 Summary: Optional static typing for Python
 Author-email: Jukka Lehtosalo <jukka.lehtosalo at iki.fi>
 License-Expression: MIT


=====================================
mypy/build.py
=====================================
@@ -874,7 +874,7 @@ class BuildManager:
                 ]
             )
 
-        self.metastore = create_metastore(options, parallel_worker)
+        self.metastore = create_metastore(options)
 
         # a mapping from source files to their corresponding shadow files
         # for efficient lookup
@@ -1613,13 +1613,10 @@ def exclude_from_backups(target_dir: str) -> None:
         pass
 
 
-def create_metastore(options: Options, parallel_worker: bool = False) -> MetadataStore:
+def create_metastore(options: Options) -> MetadataStore:
     """Create the appropriate metadata store."""
     if options.sqlite_cache:
-        # We use this flag in both coordinator and workers to speed up commits,
-        # see mypy.metastore.connect_db() for details.
-        sync_off = options.num_workers > 0 or parallel_worker
-        mds: MetadataStore = SqliteMetadataStore(_cache_dir_prefix(options), sync_off=sync_off)
+        mds: MetadataStore = SqliteMetadataStore(_cache_dir_prefix(options))
     else:
         mds = FilesystemMetadataStore(_cache_dir_prefix(options))
     return mds


=====================================
mypy/checker.py
=====================================
@@ -5393,6 +5393,8 @@ class TypeChecker(NodeVisitor[None], TypeCheckerSharedApi, SplittingVisitor):
             if isinstance(ttype, AnyType):
                 all_types.append(ttype)
                 continue
+            if isinstance(ttype, UninhabitedType):
+                continue
 
             if isinstance(ttype, FunctionLike):
                 item = ttype.items[0]
@@ -6674,8 +6676,8 @@ class TypeChecker(NodeVisitor[None], TypeCheckerSharedApi, SplittingVisitor):
         # If we have found non-trivial restrictions from the regular comparisons,
         # then return soon. Otherwise try to infer restrictions involving `len(x)`.
         # TODO: support regular and len() narrowing in the same chain.
-        if any(m != ({}, {}) for m in partial_type_maps):
-            return reduce_conditional_maps(partial_type_maps)
+        if any(len(m[0]) or len(m[1]) for m in partial_type_maps):
+            return reduce_conditional_maps(partial_type_maps, use_meet=True)
         else:
             # Use meet for `and` maps to get correct results for chained checks
             # like `if 1 < len(x) < 4: ...`
@@ -6803,11 +6805,14 @@ class TypeChecker(NodeVisitor[None], TypeCheckerSharedApi, SplittingVisitor):
                     # It is correct to always narrow here. It improves behaviour on tests and
                     # detects many inaccurate type annotations on primer.
                     # However, because mypy does not currently check unreachable code, it feels
-                    # risky to narrow to unreachable without --warn-unreachable.
+                    # risky to narrow to unreachable without --warn-unreachable or not
+                    # at module level
                     # See also this specific primer comment, where I force primer to run with
                     # --warn-unreachable to see what code we would stop checking:
                     # https://github.com/python/mypy/pull/20660#issuecomment-3865794148
-                    if self.options.warn_unreachable or not is_unreachable_map(if_map):
+                    if (
+                        self.options.warn_unreachable and len(self.scope.stack) != 1
+                    ) or not is_unreachable_map(if_map):
                         all_if_maps.append(if_map)
 
         # Handle narrowing for operands with custom __eq__ methods specially
@@ -6896,6 +6901,14 @@ class TypeChecker(NodeVisitor[None], TypeCheckerSharedApi, SplittingVisitor):
                 expr_in_type_expr = type_expr.expr
             else:
                 continue
+
+            p_expr_type = get_proper_type(operand_types[i])
+            if isinstance(p_expr_type, TypeType) and isinstance(p_expr_type.item, TypeVarType):
+                # This mirrors logic in comparison_type_narrowing_helper
+                # In theory, this is like `i not in narrowable_indices`, except that
+                # narrowable_indices filters all type(x) narrowing as it's a call
+                continue
+
             for j in expr_indices:
                 if i == j:
                     continue
@@ -8731,7 +8744,13 @@ def reduce_and_conditional_type_maps(ms: list[TypeMap], *, use_meet: bool) -> Ty
     return result
 
 
-BUILTINS_CUSTOM_EQ_CHECKS: Final = {"builtins.bytearray", "builtins.memoryview"}
+BUILTINS_CUSTOM_EQ_CHECKS: Final = {
+    "builtins.bytearray",
+    "builtins.memoryview",
+    "builtins.frozenset",
+    "_collections_abc.dict_keys",
+    "_collections_abc.dict_items",
+}
 
 
 def has_custom_eq_checks(t: Type) -> bool:
@@ -8741,7 +8760,7 @@ def has_custom_eq_checks(t: Type) -> bool:
         # custom_special_method has special casing for builtins.* and typing.* that make the
         # above always return False. So here we return True if the a value of a builtin type
         # will ever compare equal to value of another type, e.g. a bytes value can compare equal
-        # to a bytearray value. We also include builtins collections, see testNarrowingCollections
+        # to a bytearray value.
         or (
             isinstance(pt := get_proper_type(t), Instance)
             and pt.type.fullname in BUILTINS_CUSTOM_EQ_CHECKS


=====================================
mypy/checkexpr.py
=====================================
@@ -236,8 +236,6 @@ OVERLAPPING_TYPES_ALLOWLIST: Final = [
     "builtins.frozenset",
     "typing.KeysView",
     "typing.ItemsView",
-    "builtins._dict_keys",
-    "builtins._dict_items",
     "_collections_abc.dict_keys",
     "_collections_abc.dict_items",
 ]
@@ -3709,8 +3707,22 @@ class ExpressionChecker(ExpressionVisitor[Type], ExpressionCheckerSharedApi):
             elif operator == "is" or operator == "is not":
                 right_type = self.accept(right)  # validate the right operand
                 sub_result = self.bool_type()
-                if not self.chk.can_skip_diagnostics and self.dangerous_comparison(
-                    left_type, right_type, identity_check=True
+                if (
+                    not self.chk.can_skip_diagnostics
+                    and self.dangerous_comparison(left_type, right_type, identity_check=True)
+                    # Allow dangerous identity comparisons with objects explicitly typed as Any
+                    and not (
+                        isinstance(left, NameExpr)
+                        and isinstance(left.node, Var)
+                        and not left.node.is_inferred
+                        and isinstance(get_proper_type(left.node.type), AnyType)
+                    )
+                    and not (
+                        isinstance(right, NameExpr)
+                        and isinstance(right.node, Var)
+                        and not right.node.is_inferred
+                        and isinstance(get_proper_type(right.node.type), AnyType)
+                    )
                 ):
                     # Show the most specific literal types possible
                     left_type = try_getting_literal(left_type)


=====================================
mypy/checkpattern.py
=====================================
@@ -378,9 +378,15 @@ class PatternChecker(PatternVisitor[PatternType]):
             # tuples, so we instead try to narrow the entire type.
             # TODO: use more precise narrowing when possible (e.g. for identical shapes).
             new_tuple_type = TupleType(new_inner_types, current_type.partial_fallback)
-            new_type, rest_type = self.chk.conditional_types_with_intersection(
+            new_type, _ = self.chk.conditional_types_with_intersection(
                 new_tuple_type, [get_type_range(current_type)], o, default=new_tuple_type
             )
+            if (
+                star_position is not None
+                and required_patterns <= len(inner_types) - 1
+                and all(is_uninhabited(rest) for rest in rest_inner_types)
+            ):
+                rest_type = UninhabitedType()
         else:
             new_inner_type = UninhabitedType()
             for typ in new_inner_types:
@@ -460,7 +466,7 @@ class PatternChecker(PatternVisitor[PatternType]):
             # so we only restore the type of the star item.
             res = []
             for i, t in enumerate(types):
-                if i != star_pos:
+                if i != star_pos or is_uninhabited(t):
                     res.append(t)
                 else:
                     res.append(UnpackType(self.chk.named_generic_type("builtins.tuple", [t])))


=====================================
mypy/main.py
=====================================
@@ -599,7 +599,6 @@ def define_options(
     add_invertible_flag(
         "--warn-unused-configs",
         default=False,
-        strict_flag=True,
         help="Warn about unused '[mypy-<pattern>]' or '[[tool.mypy.overrides]]' config sections",
         group=config_group,
     )


=====================================
mypy/metastore.py
=====================================
@@ -154,21 +154,20 @@ CREATE INDEX IF NOT EXISTS path_idx on files2(path);
 """
 
 
-def connect_db(db_file: str, sync_off: bool = False) -> sqlite3.Connection:
+def connect_db(db_file: str) -> sqlite3.Connection:
     import sqlite3.dbapi2
 
     db = sqlite3.dbapi2.connect(db_file)
-    if sync_off:
-        # This is a bit unfortunate (as we may get corrupt cache after e.g. Ctrl + C),
-        # but without this flag, commits are *very* slow, especially when using HDDs,
-        # see https://www.sqlite.org/faq.html#q19 for details.
-        db.execute("PRAGMA synchronous=OFF")
+    # This is a bit unfortunate (as we may get corrupt cache after e.g. Ctrl + C),
+    # but without this flag, commits are *very* slow, especially when using HDDs,
+    # see https://www.sqlite.org/faq.html#q19 for details.
+    db.execute("PRAGMA synchronous=OFF")
     db.executescript(SCHEMA)
     return db
 
 
 class SqliteMetadataStore(MetadataStore):
-    def __init__(self, cache_dir_prefix: str, sync_off: bool = False) -> None:
+    def __init__(self, cache_dir_prefix: str) -> None:
         # We check startswith instead of equality because the version
         # will have already been appended by the time the cache dir is
         # passed here.
@@ -177,7 +176,7 @@ class SqliteMetadataStore(MetadataStore):
             return
 
         os.makedirs(cache_dir_prefix, exist_ok=True)
-        self.db = connect_db(os_path_join(cache_dir_prefix, "cache.db"), sync_off=sync_off)
+        self.db = connect_db(os_path_join(cache_dir_prefix, "cache.db"))
 
     def _query(self, name: str, field: str) -> Any:
         # Raises FileNotFound for consistency with the file system version


=====================================
mypy/typeshed/stdlib/builtins.pyi
=====================================
@@ -1142,7 +1142,13 @@ class dict(MutableMapping[_KT, _VT]):
     def __reversed__(self) -> Iterator[_KT]: ...
     __hash__: ClassVar[None]  # type: ignore[assignment]
     def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...
+    @overload
+    def __or__(self, value: dict[_KT, _VT], /) -> dict[_KT, _VT]: ...
+    @overload
     def __or__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ...
+    @overload
+    def __ror__(self, value: dict[_KT, _VT], /) -> dict[_KT, _VT]: ...
+    @overload
     def __ror__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ...
     # dict.__ior__ should be kept roughly in line with MutableMapping.update()
     @overload  # type: ignore[misc]


=====================================
mypy/version.py
=====================================
@@ -8,7 +8,7 @@ from mypy import git
 # - Release versions have the form "1.2.3".
 # - Dev versions have the form "1.2.3+dev" (PLUS sign to conform to PEP 440).
 # - Before 1.0 we had the form "0.NNN".
-__version__ = "1.20.0"
+__version__ = "1.20.1"
 base_version = __version__
 
 mypy_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))


=====================================
mypyc/test-data/run-base64.test
=====================================
@@ -146,9 +146,10 @@ def test_decode_with_extra_data_after_padding() -> None:
     check_decode(b"====", encoded=True)
     check_decode(b"eA===", encoded=True)
     check_decode(b"eHk==", encoded=True)
-    check_decode(b"eA==x", encoded=True)
-    check_decode(b"eHk=x", encoded=True)
-    check_decode(b"eA==abc=======efg", encoded=True)
+    # TODO: behavior in these cases changed in Python 3.14.4, we should match that.
+    # check_decode(b"eA==x", encoded=True)
+    # check_decode(b"eHk=x", encoded=True)
+    # check_decode(b"eA==abc=======efg", encoded=True)
 
 def test_decode_wrappers() -> None:
     funcs: list[Any] = [b64decode, urlsafe_b64decode]


=====================================
test-data/unit/check-expressions.test
=====================================
@@ -2380,6 +2380,51 @@ if 1 in ('x', 'y'):  # E: Non-overlapping container check (element type: "int",
 [builtins fixtures/tuple.pyi]
 [typing fixtures/typing-full.pyi]
 
+[case testStrictEqualityWithAnySentinel]
+# flags: --strict-equality
+from __future__ import annotations
+from typing import Any, cast
+
+class A: ...
+class B: ...
+
+sentinel: Any = object()
+
+def f1(a: A = sentinel, b: B = sentinel):
+    if a is sentinel and b is sentinel:
+        raise
+
+
+def f2(a: A | None = sentinel, b: B | None = sentinel):
+    if a is sentinel and b is sentinel:
+        raise
+
+
+sentinel_strict = object()
+
+def f3(a: A = sentinel_strict, b: B = sentinel_strict):  # E: Incompatible default for parameter "a" (default has type "object", parameter has type "A") \
+                                                         # E: Incompatible default for parameter "b" (default has type "object", parameter has type "B")
+    if a is sentinel_strict and b is sentinel_strict:  # E: Non-overlapping identity check (left operand type: "B", right operand type: "A")
+        raise
+
+
+def f4(a: A | None = sentinel_strict, b: B | None = sentinel_strict):  # E: Incompatible default for parameter "a" (default has type "object", parameter has type "A | None") \
+                                                                       # E: Incompatible default for parameter "b" (default has type "object", parameter has type "B | None")
+    if a is sentinel_strict and b is sentinel_strict:  # E: Non-overlapping identity check (left operand type: "B | None", right operand type: "A | None")
+        raise
+
+
+sentinel_inferred = cast(Any, object())
+
+def f5(a: A = sentinel_inferred, b: B = sentinel_inferred):
+    if a is sentinel_inferred and b is sentinel_inferred:  # E: Non-overlapping identity check (left operand type: "B", right operand type: "A")
+        raise
+
+def f6(a: A | None = sentinel_inferred, b: B | None = sentinel_inferred):
+    if a is sentinel_inferred and b is sentinel_inferred:  # E: Non-overlapping identity check (left operand type: "B | None", right operand type: "A | None")
+        raise
+[builtins fixtures/bool.pyi]
+
 [case testOverlappingAnyTypeWithoutStrictOptional]
 # flags: --no-strict-optional --strict-equality
 from typing import Any, Optional


=====================================
test-data/unit/check-isinstance.test
=====================================
@@ -2134,27 +2134,22 @@ else:
 # flags: --warn-unreachable
 from typing import List, Optional
 
-x: List[str]
-y: Optional[int]
-
-if y in x:
-    reveal_type(y)  # E: Statement is unreachable
-else:
-    reveal_type(y)  # N: Revealed type is "builtins.int | None"
+def f(x: List[str], y: Optional[int]) -> None:
+    if y in x:
+        reveal_type(y)  # E: Statement is unreachable
+    else:
+        reveal_type(y)  # N: Revealed type is "builtins.int | None"
 [builtins fixtures/list.pyi]
 
 [case testNarrowTypeAfterInListNested]
 # flags: --warn-unreachable
 from typing import List, Optional, Any
 
-x: Optional[int]
-lst: Optional[List[int]]
-nested_any: List[List[Any]]
-
-if lst in nested_any:
-    reveal_type(lst) # N: Revealed type is "builtins.list[builtins.int]"
-if x in nested_any:
-    reveal_type(x) # E: Statement is unreachable
+def f(x: Optional[int], lst: Optional[List[int]], nested_any: List[List[Any]]) -> None:
+    if lst in nested_any:
+        reveal_type(lst) # N: Revealed type is "builtins.list[builtins.int]"
+    if x in nested_any:
+        reveal_type(x) # E: Statement is unreachable
 [builtins fixtures/list.pyi]
 
 [case testNarrowTypeAfterInTuple]


=====================================
test-data/unit/check-narrowing.test
=====================================
@@ -2802,13 +2802,13 @@ while x is not None and b():
 [case testAvoidFalseNonOverlappingEqualityCheckInLoop1]
 # flags: --allow-redefinition-new --local-partial-types --strict-equality --warn-unreachable
 
-x = 1
-while True:
-    if x == str():
-        break
-    x = str()
-    if x == int():  # E: Non-overlapping equality check (left operand type: "str", right operand type: "int")
-        break  # E: Statement is unreachable
+def f(x: int) -> None:
+    while True:
+        if x == str():
+            break
+        x = str()
+        if x == int():  # E: Non-overlapping equality check (left operand type: "str", right operand type: "int")
+            break  # E: Statement is unreachable
 [builtins fixtures/primitives.pyi]
 
 [case testAvoidFalseNonOverlappingEqualityCheckInLoop2]
@@ -2818,11 +2818,11 @@ class A: ...
 class B: ...
 class C: ...
 
-x = A()
-while True:
-    if x == C():  # E: Non-overlapping equality check (left operand type: "A | B", right operand type: "C")
-        break  # E: Statement is unreachable
-    x = B()
+def f(x: A) -> None:
+    while True:
+        if x == C():  # E: Non-overlapping equality check (left operand type: "A | B", right operand type: "C")
+            break  # E: Statement is unreachable
+        x = B()
 [builtins fixtures/primitives.pyi]
 
 [case testAvoidFalseNonOverlappingEqualityCheckInLoop3]
@@ -3264,6 +3264,39 @@ def bad_but_should_pass(has_key: bool, key: bool, s: tuple[bool, ...]) -> None:
         reveal_type(key)  # N: Revealed type is "builtins.bool"
 [builtins fixtures/primitives.pyi]
 
+[case testNarrowChainedComparisonMeet]
+# flags: --strict-equality --warn-unreachable
+from __future__ import annotations
+from typing import Any
+
+def f1(a: str | None, b: str | None) -> None:
+    if None is not a == b:
+        reveal_type(a)  # N: Revealed type is "builtins.str"
+        reveal_type(b)  # N: Revealed type is "builtins.str | None"
+
+    if (None is not a) and (a == b):
+        reveal_type(a)  # N: Revealed type is "builtins.str"
+        reveal_type(b)  # N: Revealed type is "builtins.str"
+
+def f2(a: Any | None, b: str | None) -> None:
+    if None is not a == b:
+        reveal_type(a)  # N: Revealed type is "Any"
+        reveal_type(b)  # N: Revealed type is "builtins.str | None"
+
+    if (None is not a) and (a == b):
+        reveal_type(a)  # N: Revealed type is "Any"
+        reveal_type(b)  # N: Revealed type is "builtins.str | None"
+
+def f3(a: str | None, b: Any | None) -> None:
+    if None is not a == b:
+        reveal_type(a)  # N: Revealed type is "builtins.str"
+        reveal_type(b)  # N: Revealed type is "Any | builtins.str | None"
+
+    if (None is not a) and (a == b):
+        reveal_type(a)  # N: Revealed type is "builtins.str"
+        reveal_type(b)  # N: Revealed type is "Any | builtins.str"
+[builtins fixtures/primitives.pyi]
+
 [case testNarrowTypeObject]
 # flags: --strict-equality --warn-unreachable
 from typing import Any
@@ -3362,6 +3395,30 @@ def f(x: str, y: Any, z: object):
         reveal_type(z) # N: Revealed type is "builtins.str"
 [builtins fixtures/primitives.pyi]
 
+[case testTypeEqualsCheckWideningSelf]
+# flags: --strict-equality --warn-unreachable
+from typing import Any
+from typing_extensions import Self
+
+class A:
+    def f(self: Self, y: Any, z: object):
+        if type(self) is type(y):
+            reveal_type(self) # N: Revealed type is "Self`0"
+            reveal_type(y) # N: Revealed type is "Self`0"
+
+        if type(self) is type(z):
+            reveal_type(self) # N: Revealed type is "Self`0"
+            reveal_type(z) # N: Revealed type is "Self`0"
+
+        if type(self) == type(y):
+            reveal_type(self) # N: Revealed type is "Self`0"
+            reveal_type(y) # N: Revealed type is "Self`0"
+
+        if type(self) == type(z):
+            reveal_type(self) # N: Revealed type is "Self`0"
+            reveal_type(z) # N: Revealed type is "Self`0"
+[builtins fixtures/primitives.pyi]
+
 [case testTypeEqualsCheckUsingIs]
 # flags: --strict-equality --warn-unreachable
 from typing import Any


=====================================
test-data/unit/check-python310.test
=====================================
@@ -87,11 +87,11 @@ b: int
 import b
 
 class A: ...
-m: A
 
-match m:
-    case b.b:
-        reveal_type(m)  # E: Statement is unreachable
+def f(m: A) -> None:
+    match m:
+        case b.b:
+            reveal_type(m)  # E: Statement is unreachable
 [file b.py]
 class B: ...
 b: B
@@ -100,11 +100,10 @@ b: B
 # flags: --strict-equality --warn-unreachable
 import b
 
-m: int
-
-match m:
-    case b.b:
-        reveal_type(m)  # E: Statement is unreachable
+def f(m: int) -> None:
+    match m:
+        case b.b:
+            reveal_type(m)  # E: Statement is unreachable
 [file b.py]
 b: str
 [builtins fixtures/primitives.pyi]
@@ -3006,6 +3005,36 @@ match m3:
         reveal_type(c3)  # N: Revealed type is "builtins.int"
 [builtins fixtures/tuple.pyi]
 
+[case testMatchSequencePatternVariadicTuple]
+# flags: --strict-equality --warn-unreachable
+from typing_extensions import Unpack
+
+def f1(m: tuple[int, Unpack[tuple[str, ...]], int]) -> None:
+    match m:
+        case (a1, b1):
+            reveal_type(m)  # N: Revealed type is "tuple[builtins.int, builtins.int]"
+        case (a2, b2, c2):
+            reveal_type(m)  # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.int]"
+        case (a3, b3, c3, d3):
+            reveal_type(m)  # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.str, builtins.int]"
+        case (a4, *b4, c4):
+            reveal_type(m)  # N: Revealed type is "tuple[builtins.int, Unpack[builtins.tuple[builtins.str, ...]], builtins.int]"
+        case _:
+            reveal_type(m)  # E: Statement is unreachable
+
+
+def f2(m: tuple[int] | tuple[str, str] | tuple[int, Unpack[tuple[str, ...]], int]):
+    match m:
+        case (x,):
+            reveal_type(m)  # N: Revealed type is "tuple[builtins.int]"
+        case (x, y):
+            reveal_type(m)  # N: Revealed type is "tuple[builtins.str, builtins.str] | tuple[builtins.int, builtins.int]"
+        case (x, y, z):
+            reveal_type(m)  # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.int]"
+        case _:
+            reveal_type(m)  # N: Revealed type is "tuple[builtins.int, Unpack[builtins.tuple[builtins.str, ...]], builtins.int]"
+[builtins fixtures/tuple.pyi]
+
 [case testMatchSequencePatternTypeVarTupleNotTooShort]
 from typing import Tuple
 from typing_extensions import Unpack, TypeVarTuple
@@ -3151,13 +3180,14 @@ def nested_in_dict(d: dict[str, Any]) -> int:
 # flags: --warn-unreachable
 from typing import Literal
 
-def x() -> tuple[Literal["test"]]: ...
+def f() -> None:
+    def x() -> tuple[Literal["test"]]: ...
 
-match x():
-    case (x,) if x == "test":  # E: Incompatible types in capture pattern (pattern captures type "Literal['test']", variable has type "Callable[[], tuple[Literal['test']]]")
-        reveal_type(x)  # E: Statement is unreachable
-    case foo:
-        foo
+    match x():
+        case (x,) if x == "test":  # E: Incompatible types in capture pattern (pattern captures type "Literal['test']", variable has type "Callable[[], tuple[Literal['test']]]")
+            reveal_type(x)  # E: Statement is unreachable
+        case foo:
+            foo
 
 [builtins fixtures/dict.pyi]
 


=====================================
test-data/unit/check-statements.test
=====================================
@@ -802,7 +802,7 @@ def error_in_variadic(exc: Tuple[int, ...]) -> None:
 [builtins fixtures/tuple.pyi]
 
 [case testExceptWithMultipleTypes5]
-from typing import Tuple, Type, Union
+from typing import Tuple, Type, Union, Never
 
 class E1(BaseException): pass
 class E2(BaseException): pass
@@ -849,7 +849,38 @@ def error_in_tuple_union(exc: Tuple[Union[Type[E1], Type[E2]], Union[Type[E3], i
         pass
     except exc as e:  # E: Exception type must be derived from BaseException (or be a tuple of exception classes)
         pass
+[builtins fixtures/tuple.pyi]
+
+[case testExceptWithMultipleTypes6_no_parallel]
+# For no_parallel, see:
+# https://github.com/mypyc/ast_serialize/issues/50
+from typing import Never
+
+def random() -> bool: ...
+
+def error_in_empty_tuple() -> None:
+    try:
+        pass
+    except () as e:  # E: Need type annotation for "e"
+        pass
 
+def error_in_empty_tuple_annotated(exc: tuple[()]) -> None:
+    try:
+        pass
+    except exc as e:  # E: Need type annotation for "e"
+        pass
+
+def error_in_conditional_empty_tuple() -> None:
+    try:
+        pass
+    except (BaseException if random() else ()) as e:
+        pass
+
+def error_in_never(exc: Never) -> None:
+    try:
+        pass
+    except exc as e:  # E: Need type annotation for "e"
+        pass
 [builtins fixtures/tuple.pyi]
 
 [case testExceptWithAnyTypes]


=====================================
test-data/unit/pythoneval.test
=====================================
@@ -2229,3 +2229,17 @@ def f(x: int, y: list[str]):
     x in y
 [out]
 _testStrictEqualityWithList.py:3: error: Non-overlapping container check (element type: "int", container item type: "str")
+
+[case testDictOrUnionEdgeCases]
+from typing import Mapping, Sequence, Union
+
+d: dict[str, list[str]]
+m: Mapping[str, Sequence[str]] = d | d
+
+A = dict[str, Union[A, int]]
+d1: A
+d2: A
+d3: A = d1 | d2
+reveal_type(d1 | d2)
+[out]
+_testDictOrUnionEdgeCases.py:10: note: Revealed type is "dict[str, dict[str, ... | int] | int]"



View it on GitLab: https://salsa.debian.org/python-team/packages/mypy/-/compare/d2b7ba7c388582c00af55160f408b12e44f286f3...6fb0d61ca10302f04bf65492b70bd64857c479ce

-- 
View it on GitLab: https://salsa.debian.org/python-team/packages/mypy/-/compare/d2b7ba7c388582c00af55160f408b12e44f286f3...6fb0d61ca10302f04bf65492b70bd64857c479ce
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/20260415/82cf44e8/attachment-0001.htm>


More information about the debian-med-commit mailing list