fix: isinstance narrowing regression with dynamic tuple argument by Bahtya · Pull Request #21190 · python/mypy

and others added 2 commits

April 9, 2026 06:51
When isinstance is called with a dynamically-computed tuple of types
(e.g. isinstance(exc, tuple(expected_excs))), the second argument's
stored type gets widened to match the _ClassInfo recursive type alias
(type | types.UnionType | tuple[_ClassInfo, ...]). The union handler
in get_type_range_of_type then decomposes this into individual members,
producing TypeRange(object, ...) from bare 'type', which incorrectly
narrows the expression to 'object' instead of keeping its existing type.

Fix by checking if the simplified union result is just 'object' — which
indicates we've lost type precision — and returning None to fall back to
keeping the current type, matching the v1.19 behavior.

Also handle None sub-items explicitly (propagate uncertainty) and filter
out UninhabitedType entries before simplifying.

Fixes python#21181

Signed-off-by: bahtya <bahtyar153@qq.com>

Bahtya and others added 3 commits

April 9, 2026 19:27
- Add explicit None check in valid_ranges comprehension to satisfy type checker
- Store get_proper_type(item) result in variable to avoid calling it twice and enable proper type narrowing

This fixes the 3 type checking errors introduced by the isinstance narrowing fix:
- Item "None" of "TypeRange | None" has no attribute "item"
- "ProperType" has no attribute "type"

The logic remains the same, just restructured to pass strict type checking.
The make_simplified_union return type is already specific enough
for isinstance check, no need to unwrap further.

Bahtya