Skip to content

Comments

[ty] Add narrowing for isinstance() and issubclass() checks that use PEP-604 unions#21334

Merged
AlexWaygood merged 2 commits intomainfrom
alex/isinstance-pep-604
Nov 8, 2025
Merged

[ty] Add narrowing for isinstance() and issubclass() checks that use PEP-604 unions#21334
AlexWaygood merged 2 commits intomainfrom
alex/isinstance-pep-604

Conversation

@AlexWaygood
Copy link
Member

Summary

Fixes astral-sh/ty#122. Following @sharkdp's recent changes, this is now trivial!

Test Plan

Added mdtests

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Nov 8, 2025
@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 8, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 8, 2025

mypy_primer results

Changes were detected when running on open source projects
websockets (https://github.com/aaugustin/websockets)
- src/websockets/asyncio/connection.py:487:45: error[invalid-argument-type] Argument to bound method `send_text` is incorrect: Expected `bytes | bytearray | memoryview[Unknown]`, found `(Iterable[str | bytes | bytearray | memoryview[Unknown]] & ~str) | bytes | bytearray | memoryview[Unknown] | (AsyncIterable[str | bytes | bytearray | memoryview[Unknown]] & ~str)`
- src/websockets/asyncio/connection.py:489:47: error[invalid-argument-type] Argument to bound method `send_binary` is incorrect: Expected `bytes | bytearray | memoryview[Unknown]`, found `(Iterable[str | bytes | bytearray | memoryview[Unknown]] & ~str) | bytes | bytearray | memoryview[Unknown] | (AsyncIterable[str | bytes | bytearray | memoryview[Unknown]] & ~str)`
- src/websockets/sync/connection.py:486:45: error[invalid-argument-type] Argument to bound method `send_text` is incorrect: Expected `bytes | bytearray | memoryview[Unknown]`, found `(Iterable[str | bytes | bytearray | memoryview[Unknown]] & ~str) | bytes | bytearray | memoryview[Unknown]`
- src/websockets/sync/connection.py:488:47: error[invalid-argument-type] Argument to bound method `send_binary` is incorrect: Expected `bytes | bytearray | memoryview[Unknown]`, found `(Iterable[str | bytes | bytearray | memoryview[Unknown]] & ~str) | bytes | bytearray | memoryview[Unknown]`
- Found 42 diagnostics
+ Found 38 diagnostics

starlette (https://github.com/encode/starlette)
- starlette/responses.py:255:25: warning[possibly-missing-attribute] Attribute `encode` may be missing on object of type `str | bytes | memoryview[Unknown]`
- starlette/schemas.py:55:26: error[unresolved-attribute] Object of type `BaseRoute` has no attribute `routes`
- Found 226 diagnostics
+ Found 224 diagnostics

pytest (https://github.com/pytest-dev/pytest)
- src/_pytest/_code/source.py:30:59: error[not-iterable] Object of type `~AlwaysFalsy & ~Source` is not iterable
+ src/_pytest/_code/source.py:30:35: error[unresolved-attribute] Object of type `object` has no attribute `rstrip`
- src/_pytest/_code/source.py:31:59: error[not-iterable] Object of type `~AlwaysFalsy & ~Source` is not iterable
+ src/_pytest/_code/source.py:31:35: error[unresolved-attribute] Object of type `object` has no attribute `rstrip`
- src/_pytest/_code/source.py:161:26: error[unresolved-attribute] Object of type `AST` has no attribute `decorator_list`
- src/_pytest/_code/source.py:163:27: error[unresolved-attribute] Object of type `AST` has no attribute `lineno`
- src/_pytest/assertion/rewrite.py:745:17: error[invalid-assignment] Object of type `tuple[@Todo, AST | Sentinel]` is not assignable to attribute `scope` of type `tuple[AST, ...]`
- src/_pytest/doctest.py:329:13: error[invalid-assignment] Object of type `list[Unknown | BaseException]` is not assignable to `Sequence[DocTestFailure | UnexpectedException] | None`
- src/_pytest/python.py:1042:45: error[invalid-argument-type] Argument to function `_ascii_escaped_by_config` is incorrect: Expected `str | bytes`, found `object`
- src/_pytest/skipping.py:294:56: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | UnionType | tuple[Unknown, ...]`, found `type[BaseException] | tuple[type[BaseException], ...] | AbstractRaises[BaseException]`
- testing/test_assertrewrite.py:140:28: error[unsupported-operator] Operator `<=` is not supported for types `int` and `None`, in comparing `tuple[Literal[3], Literal[0]]` with `Unknown | tuple[Unknown | int | None, Unknown | int | None]`
+ testing/test_assertrewrite.py:140:28: error[unsupported-operator] Operator `<=` is not supported for types `int` and `None`, in comparing `tuple[Literal[3], Literal[0]]` with `Unknown | tuple[int | None, int | None]`
- testing/test_assertrewrite.py:140:38: error[unsupported-operator] Operator `<=` is not supported for types `None` and `int`, in comparing `Unknown | tuple[Unknown | int | None, Unknown | int | None]` with `tuple[Literal[6], Literal[3]]`
+ testing/test_assertrewrite.py:140:38: error[unsupported-operator] Operator `<=` is not supported for types `None` and `int`, in comparing `Unknown | tuple[int | None, int | None]` with `tuple[Literal[6], Literal[3]]`
- Found 479 diagnostics
+ Found 473 diagnostics

Tanjun (https://github.com/FasterSpeeding/Tanjun)
- tanjun/_internal/__init__.py:465:12: error[unresolved-attribute] Object of type `PartialCommand | CommandBuilder` has no attribute `description`
- tanjun/_internal/__init__.py:465:31: error[unresolved-attribute] Object of type `(PartialCommand & ~AlwaysFalsy) | (CommandBuilder & ~AlwaysFalsy)` has no attribute `description`
- tanjun/_internal/__init__.py:465:52: error[unresolved-attribute] Object of type `PartialCommand | CommandBuilder` has no attribute `description_localizations`
- tanjun/_internal/__init__.py:465:85: error[unresolved-attribute] Object of type `(PartialCommand & ~AlwaysFalsy) | (CommandBuilder & ~AlwaysFalsy)` has no attribute `description_localizations`
- tanjun/_internal/__init__.py:468:16: error[unresolved-attribute] Object of type `PartialCommand | CommandBuilder` has no attribute `options`
- tanjun/_internal/__init__.py:469:22: error[unresolved-attribute] Object of type `(PartialCommand & ~AlwaysFalsy) | (CommandBuilder & ~AlwaysFalsy)` has no attribute `options`
- Found 156 diagnostics
+ Found 150 diagnostics

xarray (https://github.com/pydata/xarray)
- xarray/backends/h5netcdf_.py:465:16: error[invalid-return-type] Return type does not match returned value: expected `str | ReadBuffer[Unknown] | AbstractDataStore`, found `str | PathLike[Any] | ReadBuffer[Unknown] | ... omitted 3 union elements`
+ xarray/backends/h5netcdf_.py:465:16: error[invalid-return-type] Return type does not match returned value: expected `str | ReadBuffer[Unknown] | AbstractDataStore`, found `str | (PathLike[Any] & ~bytes) | ReadBuffer[Unknown] | AbstractDataStore`
- xarray/backends/h5netcdf_.py:509:22: error[no-matching-overload] No overload of function `splitext` matches arguments
- xarray/backends/netCDF4_.py:729:36: error[invalid-argument-type] Argument to function `_has_netcdf_ext` is incorrect: Expected `str | PathLike[Unknown]`, found `str | PathLike[Any] | ReadBuffer[Unknown] | ... omitted 3 union elements`
- xarray/backends/netCDF4_.py:732:43: error[non-subscriptable] Cannot subscript object of type `PathLike[Any]` with no `__getitem__` method
- xarray/backends/netCDF4_.py:732:43: error[non-subscriptable] Cannot subscript object of type `ReadBuffer[Unknown]` with no `__getitem__` method
- xarray/backends/netCDF4_.py:732:43: error[non-subscriptable] Cannot subscript object of type `AbstractDataStore` with no `__getitem__` method
- xarray/backends/scipy_.py:326:16: error[invalid-return-type] Return type does not match returned value: expected `str | ReadBuffer[Unknown] | AbstractDataStore`, found `str | PathLike[Any] | ReadBuffer[Unknown] | ... omitted 3 union elements`
+ xarray/backends/scipy_.py:326:16: error[invalid-return-type] Return type does not match returned value: expected `str | ReadBuffer[Unknown] | AbstractDataStore`, found `str | (PathLike[Any] & ~bytes) | ReadBuffer[Unknown] | AbstractDataStore`
- xarray/coding/cftime_offsets.py:783:30: error[invalid-argument-type] Argument to function `delta_to_tick` is incorrect: Expected `timedelta`, found `(str & ~BaseCFTimeOffset) | (timedelta & ~BaseCFTimeOffset) | (DateOffset & ~BaseCFTimeOffset)`
- xarray/coding/cftime_offsets.py:787:13: error[no-matching-overload] No overload of function `match` matches arguments
- xarray/computation/fit.py:407:9: error[invalid-assignment] Object of type `list[Unknown | Iterable[str | DataArray] | DataArray]` is not assignable to `Iterable[str | DataArray] | DataArray`
- xarray/core/dataset.py:8499:18: error[not-iterable] Object of type `Hashable` is not iterable
- xarray/core/dataset.py:8626:18: error[not-iterable] Object of type `Hashable` is not iterable
- xarray/core/datatree_render.py:295:31: error[index-out-of-bounds] Index 0 is out of bounds for string `Literal[""]` with length 0
- xarray/core/indexing.py:806:53: error[invalid-argument-type] Argument to function `_outer_to_vectorized_indexer` is incorrect: Expected `BasicIndexer | OuterIndexer`, found `ExplicitIndexer`
- xarray/core/indexing.py:1178:41: error[invalid-argument-type] Argument to function `_decompose_outer_indexer` is incorrect: Expected `BasicIndexer | OuterIndexer`, found `ExplicitIndexer & ~VectorizedIndexer`
+ xarray/core/parallel.py:139:12: error[invalid-return-type] Return type does not match returned value: expected `T_Xarray@infer_template`, found `Dataset | DataArray`
- xarray/structure/combine.py:634:9: error[invalid-assignment] Object of type `list[Unknown | Sequence[str | DataArray | Index[Any] | None] | DataArray | None]` is not assignable to `Sequence[str | DataArray | Index[Any] | None] | DataArray | None`
- xarray/structure/concat.py:363:22: error[unresolved-attribute] Object of type `Hashable` has no attribute `dims`
- xarray/structure/concat.py:535:40: error[not-iterable] Object of type `Iterable[Hashable] | CombineKwargDefault` may not be iterable
- xarray/structure/concat.py:549:32: error[invalid-argument-type] Argument to bound method `update` is incorrect: Expected `Iterable[Unknown]`, found `Iterable[Hashable] | CombineKwargDefault`
- Found 1751 diagnostics
+ Found 1735 diagnostics

django-stubs (https://github.com/typeddjango/django-stubs)
- mypy_django_plugin/django/context.py:161:66: error[invalid-argument-type] Argument to bound method `get_field_related_model_cls` is incorrect: Expected `RelatedField[Any, Any] | ForeignObjectRel`, found `Field[Any, Any] | ForeignObjectRel`
- mypy_django_plugin/django/context.py:415:16: error[invalid-return-type] Return type does not match returned value: expected `tuple[Field[Any, Any] | ForeignObjectRel, type[Model]]`, found `tuple[None | Unknown | Field[Any, Any], type[Model]]`
- mypy_django_plugin/django/context.py:446:58: error[invalid-argument-type] Argument to bound method `get_field_related_model_cls` is incorrect: Expected `RelatedField[Any, Any] | ForeignObjectRel`, found `Field[Unknown, Unknown] | ForeignObjectRel | GenericForeignKey`
- mypy_django_plugin/lib/helpers.py:417:29: warning[possibly-missing-attribute] Attribute `model` may be missing on object of type `ForeignObjectRel | None`
- Found 481 diagnostics
+ Found 477 diagnostics

zulip (https://github.com/zulip/zulip)
- zerver/lib/validator.py:567:16: error[invalid-return-type] Return type does not match returned value: expected `str | int`, found `object`
- zerver/lib/validator.py:600:20: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `object`
- Found 3375 diagnostics
+ Found 3373 diagnostics

rotki (https://github.com/rotki/rotki)
- rotkehlchen/accounting/history_base_entries.py:88:48: error[unresolved-attribute] Object of type `HistoryBaseEntry[Unknown]` has no attribute `tx_ref`
- Found 1673 diagnostics
+ Found 1672 diagnostics

core (https://github.com/home-assistant/core)
- homeassistant/components/screenlogic/number.py:160:13: error[invalid-assignment] Object of type `Unknown | None` is not assignable to attribute `_attr_native_max_value` of type `int | float`
- homeassistant/components/screenlogic/number.py:164:13: error[invalid-assignment] Object of type `Unknown | None` is not assignable to attribute `_attr_native_min_value` of type `int | float`
- homeassistant/components/screenlogic/number.py:168:13: error[invalid-assignment] Object of type `Unknown | None` is not assignable to attribute `_attr_native_step` of type `int | float`
- homeassistant/components/tesla_fleet/sensor.py:547:73: error[unsupported-operator] Operator `>` is not supported for types `None` and `int`, in comparing `Any | None` with `Literal[0]`
- homeassistant/components/teslemetry/sensor.py:1748:73: error[unsupported-operator] Operator `>` is not supported for types `None` and `int`, in comparing `Any | None` with `Literal[0]`
- Found 14446 diagnostics
+ Found 14441 diagnostics

scipy (https://github.com/scipy/scipy)
- scipy/interpolate/_rbfinterp.py:266:50: warning[possibly-missing-attribute] Attribute `shape` may be missing on object of type `Unknown | float`
- scipy/optimize/_root_scalar.py:284:16: error[non-subscriptable] Cannot subscript object of type `None` with no `__getitem__` method
- scipy/signal/_ltisys.py:3448:15: warning[possibly-unresolved-reference] Name `h` used when possibly not defined
- scipy/sparse/_construct.py:1385:25: warning[possibly-missing-attribute] Attribute `ravel` may be missing on object of type `Unknown | coo_array`
+ scipy/sparse/_construct.py:1385:25: warning[possibly-missing-attribute] Attribute `ravel` may be missing on object of type `(Unknown & ~Top[list[Unknown]] & ~Number) | coo_array`
- Found 9143 diagnostics
+ Found 9140 diagnostics

No memory usage changes detected ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 8, 2025

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-argument-type 0 14 0
unresolved-attribute 2 11 0
invalid-assignment 0 7 0
invalid-return-type 1 2 2
not-iterable 0 5 0
non-subscriptable 0 4 0
possibly-missing-attribute 0 3 1
unsupported-operator 0 2 2
no-matching-overload 0 2 0
index-out-of-bounds 0 1 0
possibly-unresolved-reference 0 1 0
Total 3 52 5

Full report with detailed diff (timing results)

Copy link
Contributor

@sharkdp sharkdp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@AlexWaygood AlexWaygood merged commit 020ff17 into main Nov 8, 2025
40 checks passed
@AlexWaygood AlexWaygood deleted the alex/isinstance-pep-604 branch November 8, 2025 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ecosystem-analyzer ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow narrowing with isinstance(x, str | int) (PEP 604 union types)

2 participants