[med-svn] [Git][python-team/packages/mypy][upstream] New upstream version 1.20.1
Michael R. Crusoe (@crusoe)
gitlab at salsa.debian.org
Wed Apr 15 14:09:02 BST 2026
Michael R. Crusoe pushed to branch upstream at Debian Python Team / packages / mypy
Commits:
af0395ef by Michael R. Crusoe at 2026-04-15T14:47:03+02:00
New upstream version 1.20.1
- - - - -
17 changed files:
- PKG-INFO
- 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
=====================================
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/-/commit/af0395ef714247c70008a3cfcd1f13ea09ee58e1
--
View it on GitLab: https://salsa.debian.org/python-team/packages/mypy/-/commit/af0395ef714247c70008a3cfcd1f13ea09ee58e1
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/c7e93e32/attachment-0001.htm>
More information about the debian-med-commit
mailing list