From ec08f1f590526ff3a797b1be500c482b15ca483a Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Fri, 3 Apr 2026 17:10:19 -0700 Subject: [PATCH 1/2] Let issubclass narrow Any Fixes #10680 --- mypy/checker.py | 12 +++++++----- test-data/unit/check-isinstance.test | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 8775f1ddef29..32c766dd5b55 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -7860,7 +7860,6 @@ def push_type_map(self, type_map: TypeMap, *, from_assignment: bool = True) -> N def infer_issubclass_maps(self, node: CallExpr, expr: Expression) -> tuple[TypeMap, TypeMap]: """Infer type restrictions for an expression in issubclass call.""" vartype = self.lookup_type(expr) - type = self.get_isinstance_type(node.args[1]) if isinstance(vartype, TypeVarType): vartype = vartype.upper_bound vartype = get_proper_type(vartype) @@ -7876,13 +7875,16 @@ def infer_issubclass_maps(self, node: CallExpr, expr: Expression) -> tuple[TypeM vartype = UnionType(union_list) elif isinstance(vartype, TypeType): vartype = vartype.item + elif isinstance(vartype, AnyType): + pass elif isinstance(vartype, Instance) and vartype.type.is_metaclass(): vartype = self.named_type("builtins.object") else: - # Any other object whose type we don't know precisely - # for example, Any or a custom metaclass. - return {}, {} # unknown type - yes_type, no_type = self.conditional_types_with_intersection(vartype, type, expr) + # Any other object which isn't a type + return {}, {} + + issubclass_type = self.get_isinstance_type(node.args[1]) + yes_type, no_type = self.conditional_types_with_intersection(vartype, issubclass_type, expr) yes_map, no_map = conditional_types_to_typemaps(expr, yes_type, no_type) yes_map, no_map = map(convert_to_typetype, (yes_map, no_map)) return yes_map, no_map diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index 310145dfc4ef..2fcea2d0865a 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -1867,6 +1867,25 @@ def directed_meet(cls0: ClassT, cls1: ClassT) -> ClassT | None: return None [builtins fixtures/isinstancelist.pyi] +[case testIssubclassAny] +# flags: --warn-unreachable +from typing import Any + +def f1(x: Any) -> None: + if issubclass(x, int): + reveal_type(x) # N: Revealed type is "type[builtins.int]" + else: + reveal_type(x) # N: Revealed type is "Any" + reveal_type(x) # N: Revealed type is "Any" + +def f2(x: Any) -> None: + if issubclass(x, list): + reveal_type(x) # N: Revealed type is "type[builtins.list[Any]]" + else: + reveal_type(x) # N: Revealed type is "Any" + reveal_type(x) # N: Revealed type is "Any" +[builtins fixtures/isinstancelist.pyi] + [case testIsinstanceTypeArgs] # flags: --warn-unreachable from typing import Iterable, TypeVar From 53818325e3610a387b1135318cd71961125abeee Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2026 00:13:21 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/checker.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index 32c766dd5b55..146559a6ae76 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -7884,7 +7884,9 @@ def infer_issubclass_maps(self, node: CallExpr, expr: Expression) -> tuple[TypeM return {}, {} issubclass_type = self.get_isinstance_type(node.args[1]) - yes_type, no_type = self.conditional_types_with_intersection(vartype, issubclass_type, expr) + yes_type, no_type = self.conditional_types_with_intersection( + vartype, issubclass_type, expr + ) yes_map, no_map = conditional_types_to_typemaps(expr, yes_type, no_type) yes_map, no_map = map(convert_to_typetype, (yes_map, no_map)) return yes_map, no_map