Skip to content

Comments

[ty] support enum _value_ annotation#22228

Open
silamon wants to merge 12 commits intoastral-sh:mainfrom
silamon:enum_value_annotation
Open

[ty] support enum _value_ annotation#22228
silamon wants to merge 12 commits intoastral-sh:mainfrom
silamon:enum_value_annotation

Conversation

@silamon
Copy link
Contributor

@silamon silamon commented Dec 27, 2025

Summary

The _value_ attribute is used inside an Enum class to explicitly define the underlying value of an enum member. Typing can be verified on the members.

Test Plan

Added a mdtest

@carljm carljm changed the title Support enum _value_ annotation [ty] support enum _value_ annotation Dec 27, 2025
@carljm carljm added the ty Multi-file analysis & type inference label Dec 27, 2025
@astral-sh-bot
Copy link

astral-sh-bot bot commented Dec 27, 2025

Typing conformance results improved 🎉

The percentage of diagnostics emitted that were expected errors increased from 84.96% to 84.99%. The percentage of expected errors that received a diagnostic increased from 75.14% to 75.25%.

Summary

Metric Old New Diff Outcome
True Positives 819 821 +2 ⏫ (✅)
False Positives 145 145 +0
False Negatives 271 270 -1 ⏬ (✅)
Total Diagnostics 964 966 +2
Precision 84.96% 84.99% +0.03% ⏫ (✅)
Recall 75.14% 75.25% +0.11% ⏫ (✅)

True positives added

Details
Location Name Message
enums_member_values.py:78:5 invalid-assignment Enum member GREEN value is not assignable to expected type

Optional Diagnostics Removed

Details
Location Name Message
enums_member_values.py:96:1 type-assertion-failure Type Unknown does not match asserted type int

Optional Diagnostics Added

Details
Location Name Message
enums_member_values.py:50:5 invalid-assignment Enum member MARS is incompatible with __init__
enums_member_values.py:51:5 invalid-assignment Enum member JUPITER is incompatible with __init__

@astral-sh-bot
Copy link

astral-sh-bot bot commented Dec 27, 2025

mypy_primer results

Changes were detected when running on open source projects
spack (https://github.com/spack/spack)
- lib/spack/spack/detection/path.py:169:33: error[invalid-argument-type] Argument to function `dedupe_paths` is incorrect: Expected `list[str]`, found `Unknown | list[str | PathLike[str] | PathLike[bytes] | ... omitted 3 union elements]`
+ lib/spack/spack/detection/path.py:169:33: error[invalid-argument-type] Argument to function `dedupe_paths` is incorrect: Expected `list[str]`, found `Unknown | list[int | str | bytes | ... omitted 3 union elements]`
- lib/spack/spack/llnl/util/filesystem.py:1668:35: error[invalid-argument-type] Argument to function `exists` is incorrect: Expected `int | str | bytes | PathLike[str] | PathLike[bytes]`, found `Unknown | Sized`
+ lib/spack/spack/llnl/util/filesystem.py:1668:35: error[invalid-argument-type] Argument to function `exists` is incorrect: Expected `int | str | bytes | PathLike[str] | PathLike[bytes]`, found `Sized | Unknown`
- lib/spack/spack/llnl/util/filesystem.py:1674:25: error[invalid-argument-type] Argument to function `move` is incorrect: Expected `str | PathLike[str]`, found `Unknown | Sized`
+ lib/spack/spack/llnl/util/filesystem.py:1674:25: error[invalid-argument-type] Argument to function `move` is incorrect: Expected `str | PathLike[str]`, found `Sized | Unknown`
- lib/spack/spack/verify_libraries.py:164:46: error[invalid-argument-type] Argument to function `candidate_matches` is incorrect: Expected `bytes`, found `bytes | Unknown | str | PathLike[str] | PathLike[bytes]`
+ lib/spack/spack/verify_libraries.py:164:46: error[invalid-argument-type] Argument to function `candidate_matches` is incorrect: Expected `bytes`, found `Unknown | bytes | str | PathLike[str] | PathLike[bytes]`
- lib/spack/spack/verify_libraries.py:165:17: error[invalid-assignment] Invalid subscript assignment with key of type `bytes | Unknown | str | PathLike[str] | PathLike[bytes]` and value of type `bytes | Unknown | str | PathLike[str] | PathLike[bytes]` on object of type `dict[bytes, bytes]`
+ lib/spack/spack/verify_libraries.py:165:17: error[invalid-assignment] Invalid subscript assignment with key of type `Unknown | bytes | str | PathLike[str] | PathLike[bytes]` and value of type `Unknown | bytes | str | PathLike[str] | PathLike[bytes]` on object of type `dict[bytes, bytes]`
- lib/spack/spack/verify_libraries.py:170:57: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[bytes]`, found `list[bytes | Unknown | str | PathLike[str] | PathLike[bytes]]`
+ lib/spack/spack/verify_libraries.py:170:57: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[bytes]`, found `list[Unknown | bytes | str | PathLike[str] | PathLike[bytes]]`
- lib/spack/spack/verify_libraries.py:170:69: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[bytes]`, found `list[bytes | Unknown | str | PathLike[str] | PathLike[bytes]]`
+ lib/spack/spack/verify_libraries.py:170:69: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[bytes]`, found `list[Unknown | bytes | str | PathLike[str] | PathLike[bytes]]`

pytest (https://github.com/pytest-dev/pytest)
+ src/_pytest/config/__init__.py:121:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
- Found 392 diagnostics
+ Found 393 diagnostics

rich (https://github.com/Textualize/rich)
- tests/test_tools.py:17:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, str | Unknown]]`
+ tests/test_tools.py:17:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, Unknown | str]]`
- tests/test_tools.py:18:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, str | Unknown]]`
+ tests/test_tools.py:18:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, Unknown | str]]`
- tests/test_tools.py:19:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, str | Unknown]]`
+ tests/test_tools.py:19:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, Unknown | str]]`
- tests/test_tools.py:20:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, str | Unknown]]`
+ tests/test_tools.py:20:17: error[invalid-argument-type] Argument to function `next` is incorrect: Expected `SupportsNext[Unknown]`, found `Iterable[tuple[bool, Unknown | str]]`

porcupine (https://github.com/Akuli/porcupine)
- porcupine/pluginmanager.py:133:49: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Iterable[Never]`, found `Unknown | str`
- Found 25 diagnostics
+ Found 24 diagnostics

vision (https://github.com/pytorch/vision)
- test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1543:49: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `list[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1597:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1597:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1597:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1597:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1597:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1597:13: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1684:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1684:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1684:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1684:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1684:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1684:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1684:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1684:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1739:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1739:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Number | Sequence[Unknown]`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1739:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1739:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1739:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1739:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Sequence[int | float] | None`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`
- test/test_transforms_v2.py:1739:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | tuple[int, int, int, int] | int | tuple[int | float, int | float]`
+ test/test_transforms_v2.py:1739:45: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `InterpolationMode | int`, found `Unknown | int | tuple[int | float, int | float] | tuple[int, int, int, int]`

Expression (https://github.com/cognitedata/Expression)
+ tests/test_compose.py:21:16: error[invalid-assignment] Object of type `(Never, /) -> Never` is not assignable to `(int, /) -> int`
- Found 204 diagnostics
+ Found 205 diagnostics

psycopg (https://github.com/psycopg/psycopg)
+ psycopg/psycopg/_enums.py:60:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
+ psycopg/psycopg/pq/_enums.py:17:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
+ psycopg/psycopg/pq/_enums.py:47:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
+ psycopg/psycopg/pq/_enums.py:66:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
+ psycopg/psycopg/pq/_enums.py:138:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
+ psycopg/psycopg/pq/_enums.py:159:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
+ psycopg/psycopg/pq/_enums.py:185:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
+ psycopg/psycopg/pq/_enums.py:208:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
+ psycopg/psycopg/pq/_enums.py:240:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
+ psycopg/psycopg/pq/_enums.py:253:5: error[invalid-assignment] Enum member `__module__` value is not assignable to expected type
- Found 657 diagnostics
+ Found 667 diagnostics

meson (https://github.com/mesonbuild/meson)
- mesonbuild/dependencies/cuda.py:137:76: error[invalid-argument-type] Argument to function `version_compare_many` is incorrect: Expected `str`, found `Unknown | str | None`
+ mesonbuild/dependencies/cuda.py:137:76: error[invalid-argument-type] Argument to function `version_compare_many` is incorrect: Expected `str`, found `str | None | Unknown`

openlibrary (https://github.com/internetarchive/openlibrary)
- openlibrary/catalog/utils/__init__.py:132:17: error[unresolved-attribute] Attribute `search` is not defined on `str` in union `str | Unknown`
+ openlibrary/catalog/utils/__init__.py:132:17: error[unresolved-attribute] Attribute `search` is not defined on `str` in union `Unknown | str`

scikit-build-core (https://github.com/scikit-build/scikit-build-core)
+ src/scikit_build_core/build/wheel.py:99:20: error[no-matching-overload] No overload of bound method `__init__` matches arguments
- Found 51 diagnostics
+ Found 52 diagnostics

prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/deployments/runner.py:1017:70: error[unresolved-attribute] Attribute `__name__` is not defined on `((...) -> Any) & ((*args: object, **kwargs: object) -> object)` in union `Unknown | (((...) -> Any) & ((*args: object, **kwargs: object) -> object))`
+ src/prefect/deployments/runner.py:1017:70: error[unresolved-attribute] Attribute `__name__` is not defined on `(...) -> Any` in union `Unknown | ((...) -> Any)`
+ src/prefect/flow_engine.py:1004:32: error[invalid-await] `Unknown | R@FlowRunEngine | Coroutine[Any, Any, R@FlowRunEngine]` is not awaitable
+ src/prefect/flow_engine.py:1610:24: error[invalid-await] `Unknown | R@AsyncFlowRunEngine | Coroutine[Any, Any, R@AsyncFlowRunEngine]` is not awaitable
- src/prefect/flows.py:286:34: error[unresolved-attribute] Object of type `((**P@Flow) -> R@Flow) & ((*args: object, **kwargs: object) -> object)` has no attribute `__name__`
+ src/prefect/flows.py:286:34: error[unresolved-attribute] Object of type `(**P@Flow) -> R@Flow` has no attribute `__name__`
- src/prefect/flows.py:404:68: error[unresolved-attribute] Object of type `((**P@Flow) -> R@Flow) & ((*args: object, **kwargs: object) -> object)` has no attribute `__name__`
+ src/prefect/flows.py:404:68: error[unresolved-attribute] Object of type `(**P@Flow) -> R@Flow` has no attribute `__name__`
- src/prefect/input/run_input.py:672:20: error[invalid-return-type] Return type does not match returned value: expected `T@GetAutomaticInputHandler | AutomaticRunInput[T@GetAutomaticInputHandler]`, found `Unknown | Coroutine[Any, Any, Unknown]`
+ src/prefect/input/run_input.py:672:20: error[invalid-return-type] Return type does not match returned value: expected `T@GetAutomaticInputHandler | AutomaticRunInput[T@GetAutomaticInputHandler]`, found `T@GetAutomaticInputHandler | AutomaticRunInput[T@GetAutomaticInputHandler] | Coroutine[Any, Any, T@GetAutomaticInputHandler | AutomaticRunInput[T@GetAutomaticInputHandler]]`
- Found 5886 diagnostics
+ Found 5888 diagnostics

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- ddtrace/debugging/_redaction.py:16:5: error[unsupported-operator] Operator `|` is not supported between objects of type `frozenset[Unknown | str]` and `Unknown | EnvVariable[set[Unknown]]`
+ ddtrace/debugging/_redaction.py:16:5: error[unsupported-operator] Operator `|` is not supported between objects of type `frozenset[str | Unknown]` and `Unknown | EnvVariable[set[Unknown]]`
- scripts/freshvenvs.py:343:69: error[invalid-argument-type] Argument to function `_versions_fully_cover_bounds` is incorrect: Expected `list[str]`, found `list[Version | Unknown] & ~AlwaysFalsy`
+ scripts/freshvenvs.py:343:69: error[invalid-argument-type] Argument to function `_versions_fully_cover_bounds` is incorrect: Expected `list[str]`, found `list[Unknown | Version] & ~AlwaysFalsy`
- tests/tracer/test_span.py:193:29: error[invalid-argument-type] Argument to bound method `set_metric` is incorrect: Expected `int | float`, found `int | float | complex | ... omitted 6 union elements`
+ tests/tracer/test_span.py:193:29: error[invalid-argument-type] Argument to bound method `set_metric` is incorrect: Expected `int | float`, found `Span | Unknown | None | ... omitted 6 union elements`

django-stubs (https://github.com/typeddjango/django-stubs)
- tests/assert_type/db/models/_enums.py:22:1: error[type-assertion-failure] Type `tuple[Literal["N"], Literal["North"]]` does not match asserted type `str`
+ tests/assert_type/db/models/_enums.py:22:1: error[type-assertion-failure] Type `Any` does not match asserted type `str`
+ tests/assert_type/db/models/test_enums.py:55:5: error[invalid-assignment] Enum member `__empty__` is incompatible with `__init__`
- tests/assert_type/db/models/test_enums.py:144:1: error[type-assertion-failure] Type `tuple[Literal[4], _StrPromise]` does not match asserted type `int`
+ tests/assert_type/db/models/test_enums.py:144:1: error[type-assertion-failure] Type `Any` does not match asserted type `int`
- tests/assert_type/db/models/test_enums.py:155:1: error[type-assertion-failure] Type `tuple[Literal["SR"], _StrPromise]` does not match asserted type `str`
+ tests/assert_type/db/models/test_enums.py:155:1: error[type-assertion-failure] Type `Any` does not match asserted type `str`
- tests/assert_type/db/models/test_enums.py:167:1: error[type-assertion-failure] Type `tuple[Literal[1], Literal["Carriage"]]` does not match asserted type `int`
+ tests/assert_type/db/models/test_enums.py:167:1: error[type-assertion-failure] Type `Any` does not match asserted type `int`
- tests/assert_type/db/models/test_enums.py:181:1: error[type-assertion-failure] Type `Literal["M"]` does not match asserted type `str`
+ tests/assert_type/db/models/test_enums.py:181:1: error[type-assertion-failure] Type `Any` does not match asserted type `str`
- tests/assert_type/db/models/test_enums.py:262:1: error[type-assertion-failure] Type `tuple[Literal["N"], Literal["North"]]` does not match asserted type `str`
+ tests/assert_type/db/models/test_enums.py:262:1: error[type-assertion-failure] Type `Any` does not match asserted type `str`
- tests/assert_type/db/models/test_enums.py:274:1: error[type-assertion-failure] Type `tuple[Literal["N"], Literal["North"]]` does not match asserted type `str`
+ tests/assert_type/db/models/test_enums.py:274:1: error[type-assertion-failure] Type `Any` does not match asserted type `str`
- Found 479 diagnostics
+ Found 480 diagnostics

static-frame (https://github.com/static-frame/static-frame)
- static_frame/test/unit/test_bus.py:2137:26: error[unresolved-attribute] Attribute `to_pairs` is not defined on `ndarray[Any, Any]` in union `@Todo | Series[Any, Any] | ndarray[Any, Any]`
+ static_frame/test/unit/test_bus.py:2137:26: error[unresolved-attribute] Attribute `to_pairs` is not defined on `ndarray[Any, Any]` in union `ndarray[Any, Any] | @Todo | Series[Any, Any]`
- static_frame/test/unit/test_bus.py:2138:26: error[unresolved-attribute] Attribute `to_pairs` is not defined on `ndarray[Any, Any]` in union `@Todo | Series[Any, Any] | ndarray[Any, Any]`
+ static_frame/test/unit/test_bus.py:2138:26: error[unresolved-attribute] Attribute `to_pairs` is not defined on `ndarray[Any, Any]` in union `ndarray[Any, Any] | @Todo | Series[Any, Any]`
- static_frame/test/unit/test_bus.py:2166:26: error[unresolved-attribute] Attribute `to_pairs` is not defined on `ndarray[Any, Any]` in union `@Todo | Series[Any, Any] | ndarray[Any, Any]`
+ static_frame/test/unit/test_bus.py:2166:26: error[unresolved-attribute] Attribute `to_pairs` is not defined on `ndarray[Any, Any]` in union `ndarray[Any, Any] | @Todo | Series[Any, Any]`
- static_frame/test/unit/test_bus.py:2167:26: error[unresolved-attribute] Attribute `to_pairs` is not defined on `ndarray[Any, Any]` in union `@Todo | Series[Any, Any] | ndarray[Any, Any]`
+ static_frame/test/unit/test_bus.py:2167:26: error[unresolved-attribute] Attribute `to_pairs` is not defined on `ndarray[Any, Any]` in union `ndarray[Any, Any] | @Todo | Series[Any, Any]`

materialize (https://github.com/MaterializeInc/materialize)
+ misc/python/materialize/cli/mz_workload_anonymize.py:251:13: error[no-matching-overload] No overload of bound method `join` matches arguments
- Found 525 diagnostics
+ Found 526 diagnostics

jax (https://github.com/google/jax)
- jax/_src/export/_export.py:1377:45: error[invalid-argument-type] Argument to function `_get_named_sharding` is incorrect: Expected `ShapedArray`, found `AbstractValue | Unknown`
+ jax/_src/export/_export.py:1377:45: error[invalid-argument-type] Argument to function `_get_named_sharding` is incorrect: Expected `ShapedArray`, found `Unknown | AbstractValue`
- jax/collect_profile.py:110:17: error[unresolved-attribute] Attribute `glob` is not defined on `PathLike[str]`, `int`, `str`, `bytes`, `PathLike[bytes]` in union `Unknown | PathLike[str] | int | ... omitted 3 union elements`
+ jax/collect_profile.py:110:17: error[unresolved-attribute] Attribute `glob` is not defined on `PathLike[str]`, `int`, `str`, `bytes`, `PathLike[bytes]` in union `PathLike[str] | Unknown | int | ... omitted 3 union elements`
- jax/collect_profile.py:113:22: error[unsupported-operator] Operator `/` is not supported between objects of type `Unknown | PathLike[str] | int | ... omitted 3 union elements` and `Literal["remote.trace.json.gz"]`
+ jax/collect_profile.py:113:22: error[unsupported-operator] Operator `/` is not supported between objects of type `PathLike[str] | Unknown | int | ... omitted 3 union elements` and `Literal["remote.trace.json.gz"]`

rotki (https://github.com/rotki/rotki)
- rotkehlchen/tests/unit/test_makerdao.py:170:9: error[invalid-argument-type] Argument is incorrect: Expected `defaultdict[Asset, defaultdict[str, Balance]]`, found `defaultdict[Asset | Unknown, defaultdict[str, Balance] | Balance | Unknown | dict[Unknown | str, Unknown | Balance]]`
+ rotkehlchen/tests/unit/test_makerdao.py:170:9: error[invalid-argument-type] Argument is incorrect: Expected `defaultdict[Asset, defaultdict[str, Balance]]`, found `defaultdict[Asset | Unknown, defaultdict[str, Balance] | Balance | dict[Unknown | str, Unknown | Balance] | Unknown]`
- rotkehlchen/tests/unit/test_makerdao.py:171:9: error[invalid-argument-type] Argument is incorrect: Expected `defaultdict[Asset, defaultdict[str, Balance]]`, found `defaultdict[Asset | Unknown, defaultdict[str, Balance] | Balance | Unknown | dict[Unknown | str, Unknown | Balance]]`
+ rotkehlchen/tests/unit/test_makerdao.py:171:9: error[invalid-argument-type] Argument is incorrect: Expected `defaultdict[Asset, defaultdict[str, Balance]]`, found `defaultdict[Asset | Unknown, defaultdict[str, Balance] | Balance | dict[Unknown | str, Unknown | Balance] | Unknown]`

scikit-learn (https://github.com/scikit-learn/scikit-learn)
- sklearn/datasets/_lfw.py:469:60: error[invalid-argument-type] Argument to class `str` is incorrect: Expected `bytes | bytearray`, found `str | Unknown`
+ sklearn/datasets/_lfw.py:469:60: error[invalid-argument-type] Argument to class `str` is incorrect: Expected `bytes | bytearray`, found `Unknown | str`

sympy (https://github.com/sympy/sympy)
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
- sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic | int | float | complex | Any` is not assignable to `Expr | int | float | complex`
+ sympy/algebras/quaternion.py:132:22: error[invalid-assignment] Object of type `Basic` is not assignable to `Expr | int | float | complex`
- sympy/functions/combinatorial/factorials.py:967:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:967:13: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
- sympy/functions/combinatorial/factorials.py:968:29: error[unresolved-attribute] Attribute `is_nonnegative` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:968:47: error[unresolved-attribute] Attribute `is_integer` is not defined on `int`, `complex` in union `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:969:12: error[unresolved-attribute] Attribute `is_zero` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:972:13: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:972:13: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[1]`
- sympy/functions/combinatorial/factorials.py:975:12: error[unresolved-attribute] Attribute `is_integer` is not defined on `int`, `complex` in union `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:976:16: error[unresolved-attribute] Attribute `is_negative` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:978:18: error[unresolved-attribute] Attribute `is_number` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:984:14: error[unresolved-attribute] Attribute `is_number` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/functions/combinatorial/factorials.py:986:26: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:986:26: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic` and `Literal[1]`
- sympy/functions/combinatorial/factorials.py:986:40: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
+ sympy/functions/combinatorial/factorials.py:986:40: error[unsupported-operator] Operator `+` is not supported between objects of type `Basic` and `Literal[1]`
- sympy/functions/combinatorial/factorials.py:986:53: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/functions/combinatorial/factorials.py:986:53: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
- sympy/geometry/polygon.py:1500:12: error[unresolved-attribute] Attribute `is_Number` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/geometry/polygon.py:1501:20: error[invalid-argument-type] Argument to function `as_int` is incorrect: Expected `SupportsIndex`, found `Basic | int | float | complex | Any`
+ sympy/geometry/polygon.py:1501:20: error[invalid-argument-type] Argument to function `as_int` is incorrect: Expected `SupportsIndex`, found `Basic`
- sympy/geometry/polygon.py:1502:16: error[unsupported-operator] Operator `<` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[3]`
+ sympy/geometry/polygon.py:1502:16: error[unsupported-operator] Operator `<` is not supported between objects of type `Basic` and `Literal[3]`
- sympy/geometry/polygon.py:1509:40: error[unresolved-attribute] Attribute `is_number` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/matrices/expressions/hadamard.py:81:22: error[invalid-argument-type] Argument to function `validate_matadd_integer` is incorrect: Expected `MatrixExpr`, found `Any | Basic | int | float | complex`
+ sympy/matrices/expressions/hadamard.py:81:22: error[invalid-argument-type] Argument to function `validate_matadd_integer` is incorrect: Expected `MatrixExpr`, found `Basic`
- sympy/matrices/expressions/kronecker.py:109:16: error[unresolved-attribute] Attribute `is_Identity` is not defined on `Basic`, `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
- sympy/matrices/expressions/kronecker.py:110:33: error[unresolved-attribute] Attribute `rows` is not defined on `Basic`, `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
+ sympy/matrices/expressions/kronecker.py:109:16: error[unresolved-attribute] Object of type `Basic` has no attribute `is_Identity`
+ sympy/matrices/expressions/kronecker.py:110:33: error[unresolved-attribute] Object of type `Basic` has no attribute `rows`
- sympy/matrices/expressions/matadd.py:60:22: error[invalid-argument-type] Argument to function `validate_matadd_integer` is incorrect: Expected `MatrixExpr`, found `Unknown | Basic | int | float | complex`
+ sympy/matrices/expressions/matadd.py:60:22: error[invalid-argument-type] Argument to function `validate_matadd_integer` is incorrect: Expected `MatrixExpr`, found `Unknown | Basic`
- sympy/physics/optics/gaussopt.py:263:56: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:263:56: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:298:54: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:298:54: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:298:69: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:298:69: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:707:12: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
+ sympy/physics/optics/gaussopt.py:707:12: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic` and `Literal[2]`
- sympy/physics/optics/gaussopt.py:756:8: error[unresolved-attribute] Attribute `is_infinite` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:756:25: error[unresolved-attribute] Attribute `is_infinite` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:757:21: error[unresolved-attribute] Attribute `is_infinite` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/physics/optics/gaussopt.py:759:16: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:759:16: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:759:21: error[unsupported-operator] Operator `+` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:759:21: error[unsupported-operator] Operator `+` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:790:34: error[unsupported-operator] Unary operator `-` is not supported for object of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:790:34: error[unsupported-operator] Unary operator `-` is not supported for object of type `Basic`
- sympy/physics/optics/gaussopt.py:837:30: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
+ sympy/physics/optics/gaussopt.py:837:30: error[unsupported-operator] Operator `**` is not supported between objects of type `Basic` and `Literal[2]`
- sympy/physics/optics/gaussopt.py:837:41: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:837:41: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:837:54: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:837:54: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Basic`
- sympy/physics/optics/gaussopt.py:838:22: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:838:22: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:838:37: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:838:37: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:839:31: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:839:31: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:839:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:839:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/physics/optics/gaussopt.py:887:9: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/physics/optics/gaussopt.py:887:9: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/physics/quantum/cg.py:83:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
- sympy/physics/quantum/cg.py:258:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
- sympy/physics/quantum/cg.py:347:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
- sympy/polys/fields.py:101:24: error[unresolved-attribute] Attribute `as_numer_denom` is not defined on `Basic`, `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
+ sympy/polys/fields.py:101:24: error[unresolved-attribute] Object of type `Basic` has no attribute `as_numer_denom`
- sympy/polys/polyoptions.py:472:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
+ sympy/polys/polyoptions.py:472:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
- sympy/polys/polyoptions.py:474:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
+ sympy/polys/polyoptions.py:474:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
- sympy/polys/polyoptions.py:476:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
+ sympy/polys/polyoptions.py:476:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
- sympy/polys/polyoptions.py:478:63: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
+ sympy/polys/polyoptions.py:478:63: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
- sympy/polys/polyoptions.py:480:63: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
+ sympy/polys/polyoptions.py:480:63: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
- sympy/polys/polyoptions.py:482:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
+ sympy/polys/polyoptions.py:482:61: error[invalid-argument-type] Argument to bound method `poly_ring` is incorrect: Expected `str | Expr`, found `Basic`
- sympy/polys/polyoptions.py:492:62: error[invalid-argument-type] Argument to bound method `frac_field` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
+ sympy/polys/polyoptions.py:492:62: error[invalid-argument-type] Argument to bound method `frac_field` is incorrect: Expected `str | Expr`, found `Basic`
- sympy/polys/polyoptions.py:494:62: error[invalid-argument-type] Argument to bound method `frac_field` is incorrect: Expected `str | Expr`, found `Any | Basic | int | float | complex`
+ sympy/polys/polyoptions.py:494:62: error[invalid-argument-type] Argument to bound method `frac_field` is incorrect: Expected `str | Expr`, found `Basic`
- sympy/polys/polytools.py:5998:12: error[unresolved-attribute] Attribute `is_algebraic` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:5998:31: error[unresolved-attribute] Attribute `is_irrational` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:5998:51: error[unresolved-attribute] Attribute `is_algebraic` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:5998:70: error[unresolved-attribute] Attribute `is_irrational` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:5999:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:5999:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/polys/polytools.py:6128:12: error[unresolved-attribute] Attribute `is_algebraic` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:6128:31: error[unresolved-attribute] Attribute `is_irrational` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:6128:51: error[unresolved-attribute] Attribute `is_algebraic` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:6128:70: error[unresolved-attribute] Attribute `is_irrational` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/polys/polytools.py:6129:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/polys/polytools.py:6129:20: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/series/formal.py:987:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
- sympy/series/fourier.py:146:34: error[invalid-argument-type] Argument to function `__new__` is incorrect: Expected `Basic`, found `Basic | int | float | complex | Any`
- sympy/series/order.py:153:20: error[unresolved-attribute] Attribute `is_symbol` is not defined on `int`, `float`, `complex` in union `Unknown | Basic | int | float | complex`
- sympy/series/order.py:188:28: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Unknown | Basic | int | float | complex`
+ sympy/series/order.py:188:28: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[1]` and `Unknown | Basic`
- sympy/series/order.py:192:29: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[-1]` and `Unknown | Basic | int | float | complex`
+ sympy/series/order.py:192:29: error[unsupported-operator] Operator `/` is not supported between objects of type `Literal[-1]` and `Unknown | Basic`
- sympy/series/order.py:269:52: error[invalid-argument-type] Argument to bound method `as_independent` is incorrect: Expected `Basic | type[Basic]`, found `Any | Basic | int | float | complex`
- sympy/series/order.py:269:52: error[invalid-argument-type] Argument to bound method `as_independent` is incorrect: Expected `Basic | type[Basic]`, found `Any | Basic | int | float | complex`
- sympy/series/order.py:269:52: error[invalid-argument-type] Argument to bound method `as_independent` is incorrect: Expected `Basic | type[Basic]`, found `Any | Basic | int | float | complex`
- sympy/series/order.py:287:45: error[unsupported-operator] Unary operator `-` is not supported for object of type `Any | Basic | int | float | complex`
+ sympy/series/order.py:287:45: error[unsupported-operator] Unary operator `-` is not supported for object of type `Unknown | Basic`
- sympy/series/order.py:288:48: error[unsupported-operator] Operator `**` is not supported between objects of type `Any | Basic | int | float | complex` and `Basic`
+ sympy/series/order.py:288:48: error[unsupported-operator] Operator `**` is not supported between objects of type `Unknown | Basic` and `Basic`
- sympy/series/order.py:291:49: error[unsupported-operator] Unary operator `-` is not supported for object of type `Any | Basic | int | float | complex`
+ sympy/series/order.py:291:49: error[unsupported-operator] Unary operator `-` is not supported for object of type `Unknown | Basic`
- sympy/series/order.py:297:53: error[unsupported-operator] Unary operator `-` is not supported for object of type `Any | Basic | int | float | complex`
+ sympy/series/order.py:297:53: error[unsupported-operator] Unary operator `-` is not supported for object of type `Unknown | Basic`
- sympy/simplify/cse_main.py:299:23: error[not-iterable] Object of type `Unknown | Sized` may not be iterable
+ sympy/simplify/cse_main.py:299:23: error[not-iterable] Object of type `Sized | Unknown` may not be iterable
- sympy/simplify/cse_main.py:305:16: error[unsupported-operator] Operator `in` is not supported between objects of type `Unknown` and `Unknown | Sized`
+ sympy/simplify/cse_main.py:305:16: error[unsupported-operator] Operator `in` is not supported between objects of type `Unknown` and `Sized | Unknown`
- sympy/simplify/hyperexpand.py:1046:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1046:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1047:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1047:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1048:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1048:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
- sympy/simplify/hyperexpand.py:1087:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1087:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1088:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1088:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1089:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1089:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
- sympy/simplify/hyperexpand.py:1175:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1175:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1176:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1176:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1177:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1177:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1178:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1178:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1179:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1179:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
- sympy/simplify/hyperexpand.py:1213:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1213:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1214:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1214:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1215:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1215:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1216:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1216:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1217:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1217:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
- sympy/simplify/hyperexpand.py:1265:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1265:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1266:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1266:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1267:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1267:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1268:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1268:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1269:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1269:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
- sympy/simplify/hyperexpand.py:1313:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1313:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1314:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1314:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1315:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1315:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1316:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1316:19: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `Iterable[Unknown]`, found `Basic`
- sympy/simplify/hyperexpand.py:1317:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Any | Basic | int | float | complex`
+ sympy/simplify/hyperexpand.py:1317:21: error[invalid-argument-type] Argument to bound method `pop` is incorrect: Expected `SupportsIndex`, found `Basic`
- sympy/simplify/simplify.py:357:10: error[unsupported-operator] Operator `/` is not supported between two objects of type `Any | Basic | int | float | complex`
+ sympy/simplify/simplify.py:357:10: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/simplify/sqrtdenest.py:430:25: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Basic | int | float | complex | Any`
- sympy/solvers/recurr.py:417:9: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
- sympy/solvers/recurr.py:417:9: error[unresolved-attribute] Attribute `expand` is not defined on `Basic` in union `Any | Basic`
+ sympy/solvers/recurr.py:417:9: error[unresolved-attribute] Object of type `Basic` has no attribute `expand`
- sympy/solvers/recurr.py:421:24: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
- sympy/solvers/recurr.py:436:24: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
- sympy/solvers/recurr.py:589:23: error[unresolved-attribute] Attribute `subs` is not defined on `int`, `float`, `complex` in union `Any | Basic | int | float | complex`
- sympy/stats/tests/test_finite_rv.py:357:31: error[unsupported-operator] Operator `+` is not supported between objects of type `int | Basic | float | complex | Any` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:357:31: error[unsupported-operator] Operator `+` is not supported between objects of type `int | Basic` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:361:32: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:361:32: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic`
- sympy/stats/tests/test_finite_rv.py:362:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:362:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:363:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:363:46: error[unsupported-operator] Operator `/` is not supported between two objects of type `Basic`
- sympy/stats/tests/test_finite_rv.py:363:52: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:363:52: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
- sympy/stats/tests/test_finite_rv.py:363:62: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:363:62: error[unsupported-operator] Operator `-` is not supported between two objects of type `Basic`
- sympy/stats/tests/test_finite_rv.py:363:70: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:363:70: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:365:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[2]`
+ sympy/stats/tests/test_finite_rv.py:365:20: error[unsupported-operator] Operator `>` is not supported between objects of type `Basic` and `Literal[2]`
- sympy/stats/tests/test_finite_rv.py:365:30: error[unsupported-operator] Operator `<` is not supported between objects of type `Literal[0]` and `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:365:30: error[unsupported-operator] Operator `<` is not supported between objects of type `Literal[0]` and `Basic`
- sympy/stats/tests/test_finite_rv.py:365:34: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:365:34: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic`
- sympy/stats/tests/test_finite_rv.py:365:44: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:365:44: error[unsupported-operator] Operator `<` is not supported between two objects of type `Basic`
- sympy/stats/tests/test_finite_rv.py:366:57: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:366:57: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic`
- sympy/stats/tests/test_finite_rv.py:366:67: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic | int | float | complex | Any` and `Literal[1]`
+ sympy/stats/tests/test_finite_rv.py:366:67: error[unsupported-operator] Operator `-` is not supported between objects of type `Basic` and `Literal[1]`
- sympy/stats/tests/test_finite_rv.py:366:79: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:366:79: error[unsupported-operator] Operator `*` is not supported between objects of type `Literal[2]` and `Basic`
- sympy/stats/tests/test_finite_rv.py:367:33: error[unsupported-operator] Operator `*` is not supported between two objects of type `Basic | int | float | complex | Any`
+ sympy/stats/tests/test_finite_rv.py:367:33: error[unsupported-operator] Operator `*` is not supported between two ob

... (truncated 35 lines) ...

@silamon
Copy link
Contributor Author

silamon commented Dec 28, 2025

Aside from some failing CI, there's still 2 more issues that got identified:

from enum import Enum

class Color(Enum):
    _value_: int
    RED = 1

reveal_type(Color.RED.value)  # revealed: Literal[1]
reveal_type(Color.RED._value_)  # revealed: Literal[1]

The _value_ revealed still holds Literal[1] there, while some other type checkers will show up int. What would we do here?

Second, this example came out the comformance testing:

from enum import Enum

class Planet2(Enum):
    _value_: str

    def __init__(self, value: int, mass: float, radius: float):
        self._value_ = value  # E

    MERCURY = (1, 3.303e23, 2.4397e6)

It's throwing an diagnostic currently on the last MERCURY line, while it shouldn't. While it's obviously what's happening here, it's not so obviously to me how to fix it.

@MichaReiser
Copy link
Member

Thank you for working on this. Almost the entire team is out this week. It may take a few days before someone finds time to answer your question. We're sorry for that. Happy holidays.

Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

Nice, thank you! Sorry for the delay in reviewing this!!

@AlexWaygood
Copy link
Member

from enum import Enum

class Color(Enum):
    _value_: int
    RED = 1

reveal_type(Color.RED.value)  # revealed: Literal[1]
reveal_type(Color.RED._value_)  # revealed: Literal[1]

The value revealed still holds Literal[1] there, while some other type checkers will show up int. What would we do here?

I think inferring Literal[1] there is fine, since Literal[1] is assignable to int. Possibly it's unsound to infer Literal[1] if the enum class has a custom constructor method...? But the enum class in your example does not.

Second, this example came out the comformance testing:

from enum import Enum

class Planet2(Enum):
    _value_: str

    def __init__(self, value: int, mass: float, radius: float):
        self._value_ = value  # E

    MERCURY = (1, 3.303e23, 2.4397e6)

It's throwing an diagnostic currently on the last MERCURY line, while it shouldn't. While it's obviously what's happening here, it's not so obviously to me how to fix it.

The spec explains what to do here at https://typing.python.org/en/latest/spec/enums.html#member-values

@AlexWaygood AlexWaygood self-assigned this Jan 16, 2026
@silamon silamon force-pushed the enum_value_annotation branch 3 times, most recently from 13c83bc to 8e2b01e Compare January 23, 2026 20:37
@silamon
Copy link
Contributor Author

silamon commented Jan 23, 2026

I've applied your patch (thanks for that), and worked further on it. It's a better place than what I had first.
EnumClassInfo and EnumMetadata feels like they could be combined.

Conformance testing shows what I expected, unit tests succeed including the stub example.
I'll await review and then will include fixes for the markdown linting, which still fails.

Copy link
Contributor

@carljm carljm 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, this looks good!

I'll await review and then will include fixes for the markdown linting

For future reference: this should be a trivial fix with uvx prek -a, so it probably makes more sense to just go ahead and fix it rather than waiting for review first?

Comment on lines 79 to 84
/// Extracts the expected enum member type from `__init__` method parameters.
fn extract_init_member_type(
db: &'db dyn Db,
_class: StaticClassLiteral<'db>,
scope: ScopeId<'db>,
) -> Option<Type<'db>> {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we can assume that the first parameter of an Enum class's __init__ method always provides the _value_ type. I think we need to look at the type assigned to self._value_ inside the enum's __init__ method rather than attempting to extract the annotated type of the first parameter of the __init__ method

Copy link
Contributor

Choose a reason for hiding this comment

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

As I understand it, it's the entire signature of __init__ that determines the expected type assigned to members. If __init__ takes multiple arguments, it's a tuple of those types that we expect. If __init__ takes only a single argument, it's that type that is expected. That's what's implemented here, and it looks correct to me.

If we are discussing the type ultimately revealed by accessing _value_ on a member, that may be something else? But it also doesn't seem to be touched by this PR.

Copy link
Member

Choose a reason for hiding this comment

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

Oh I see, sorry. Yes, looks like you're right.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we need to look at the type assigned to self._value_ inside the enum's __init__ method

I don't think other type checkers do this. Pyright appears to just fallback to Any as the type of the _value_ member, if there is an __init__.

So I do think that's an improvement we need (either the pyright fallback, or the more complex analysis you suggest), and it should probably go in this PR, although technically I think this PR is a strict improvement either way. Here's a test case:

from enum import Enum

class MyEnum(Enum):
    def __init__(self, x: int, y: str):
        self._value_ = y

    RED = (1, "red")
    BLUE = (2, "blue")

reveal_type(MyEnum.RED._value_)

Pyright reveals Any here (but reveals the precise assigned type if there is no __init__). We currently (and in this PR) reveal tuple[Literal[1], Literal["red"]], which is wrong. The ideal thing to reveal would be Literal["red"], but I think that would be quite hard and not worth it. Revealing str instead of Any doesn't seem too hard (though I'm still not sure it's worth it, given that there will always be more complex cases where we have to fall back to a union, if there are multiple assignments to _value_ in __init__, and that union could cause false positives.)

Copy link
Member

@AlexWaygood AlexWaygood Jan 23, 2026

Choose a reason for hiding this comment

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

Yeah, I agree it's out of scope for this PR, which as you say is a strict improvement over the status quo. Sorry for getting confused!

If the enum has a custom __init__ method I think we would ideally fallback to the _value_ annotation (either in __init__ or in the class body), if it's available, and fallback to Any if not. But if that's hard I'd also be okay with only falling back to _value_ if it's provided in the class body and ignoring assignments in __init__.

Copy link
Member

Choose a reason for hiding this comment

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

and to be clear, we should always make sure .value is consistent with ._value_, so this has implications for the type we store in the EnumMetadata::members mapping from enum members to their values.

Copy link
Contributor

@carljm carljm Jan 23, 2026

Choose a reason for hiding this comment

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

I think relatedly, we should probably revisit the earlier decision in this PR that it's OK for _value_ to reveal Literal[1] in this example, rather than int:

from enum import Enum

class MyEnum(Enum):
    _value_: int
    RED = 1
    BLUE = 2

reveal_type(MyEnum.RED._value_)

The reason is that it's possible for the RHS of these assignments to be e.g. a call that returns Any or Unknown, and in that case we should really reveal int, not Any or Unknown. In a sense this is just another version of astral-sh/ty#136, where it does matter that we respect the explicit type annotation given by the user.

Copy link
Contributor

@carljm carljm Jan 23, 2026

Choose a reason for hiding this comment

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

(Sorry, wasn't getting live updates on the PR thread, and posted all my comments here, and the main request-changes comment, before I saw any of your comments. I kind of changed my mind about these issues being out of scope for this PR, because I think the need to connect annotated _value_ type to eventual inferred type of _value_ / value member attributes could significantly change the implementation here.)

Copy link
Member

Choose a reason for hiding this comment

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

it makes me a bit sad that we'll lose literal types for .value for things like this -- Literal types seem much more important for enum values than for most other areas of Python typing:

class Foo(Enum):
    _value_: str
    X = 'A'
    Y = 'B'

but I do agree that it's important we don't infer Any or Unknown for .value for things like this:

def returns_unknown():
    return "foo"

class Bar(Enum):
    _value_: str
    X = returns_unknown()
    Y = returns_unknown()

Since enums are heavily special-cased anyway, it's possible we could do some kind of syntactic check here to see whether the type was inferred due to a literal value on the right-hand side (which will be by far the most common case) or something else, like a function call.

But given that _value_ annotations are pretty rare anyway, maybe we shouldn't worry about this too much. I definitely don't think we should make a rule that says we prefer the inferred type only if the inferred type is fully static; that would be very inconsistent with what e.g. mypy does, what users expect, and what I believe we're currently planning to do to address astral-sh/ty#136 (though the title of that issue still mentions only preferring "more precise" declared types).

Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

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

Given the discussion in the sub-thread, I think we should update this PR so that a) we always respect explicit _value_ annotation, if there is one, when inferring a type for accessing _value_ or value attribute on an enum member, and b) we fall back to Any for our inference of _value_ / value attributes if the enum has an __init__ method. (I think that if we want to do anything more precise than Any here -- and I'm not sure we should -- that's subtle enough that it should be a separate PR.)

I do also think it's worth considering just merging EnumClassInfo into EnumMetadata. I don't think this is critical, but it's also not clear to me that there's any benefit to them being separate. (And given the above changes will require having value_sunder_type also influence our inference of _value_ / value attribute types, it may simplify that implementation anyway.)

@silamon
Copy link
Contributor Author

silamon commented Jan 24, 2026

I'm going to work further on this later, thank you for your feedback.

@silamon silamon force-pushed the enum_value_annotation branch from cebc4ae to 39a1c81 Compare February 7, 2026 09:16
@silamon
Copy link
Contributor Author

silamon commented Feb 7, 2026

I've did the remarks:

  • Merged the EnumClassInfo into EnumMetadata
  • Removed the logic that resolved the type when a init exists and return Any type.

Somehow along the way I started to introduce something that resolves many types to Unknown, which causes a lot of tests to fail. I haven't been able to find it yet, if somebody could help me out I would appreciate it.

@sharkdp sharkdp removed their request for review February 9, 2026 09:57
@carljm
Copy link
Contributor

carljm commented Feb 13, 2026

@charliermarsh this might be another one in the queue that you could take a look at what it needs to get land-ready?

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 14, 2026

Memory usage report

Summary

Project Old New Diff Outcome
prefect 711.45MB 711.59MB +0.02% (145.23kB)
sphinx 272.07MB 272.11MB +0.01% (39.34kB)
trio 121.13MB 121.15MB +0.01% (15.30kB)
flake8 49.45MB 49.46MB +0.01% (5.57kB)

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
enum_metadata 2.36MB 2.50MB +5.94% (143.38kB)
infer_definition_types 87.64MB 87.64MB +0.00% (1.05kB)
StaticClassLiteral<'db>::try_metaclass_ 1.16MB 1.17MB +0.04% (452.00B)
StaticClassLiteral<'db>::is_typed_dict_ 598.27kB 598.48kB +0.04% (216.00B)
StaticClassLiteral<'db>::inheritance_cycle_ 348.01kB 348.08kB +0.02% (72.00B)
place_table 720.18kB 720.23kB +0.01% (60.00B)
use_def_map 436.82kB 436.88kB +0.01% (60.00B)
infer_expression_types_impl 61.57MB 61.57MB -0.00% (36.00B)

sphinx

Name Old New Diff Outcome
enum_metadata 651.11kB 689.62kB +5.92% (38.52kB)
infer_definition_types 24.48MB 24.48MB +0.00% (536.00B)
StaticClassLiteral<'db>::is_typed_dict_ 182.24kB 182.34kB +0.06% (108.00B)
infer_scope_types_impl 15.82MB 15.82MB +0.00% (84.00B)
place_table 226.70kB 226.76kB +0.03% (60.00B)
use_def_map 126.15kB 126.21kB +0.05% (60.00B)

trio

Name Old New Diff Outcome
enum_metadata 208.45kB 222.91kB +6.94% (14.46kB)
StaticClassLiteral<'db>::try_metaclass_ 126.77kB 127.21kB +0.35% (452.00B)
infer_scope_types_impl 4.90MB 4.90MB +0.00% (228.00B)
StaticClassLiteral<'db>::is_typed_dict_ 65.74kB 65.84kB +0.16% (108.00B)
StaticClassLiteral<'db>::inheritance_cycle_ 34.27kB 34.34kB +0.21% (72.00B)

flake8

Name Old New Diff Outcome
enum_metadata 56.87kB 60.76kB +6.84% (3.89kB)
infer_definition_types 1.89MB 1.89MB +0.05% (1.05kB)
StaticClassLiteral<'db>::is_typed_dict_ 27.72kB 27.93kB +0.76% (216.00B)
place_by_id 143.30kB 143.43kB +0.08% (124.00B)
place_table 25.08kB 25.20kB +0.47% (120.00B)
use_def_map 19.10kB 19.22kB +0.61% (120.00B)
place_by_id::interned_arguments 106.45kB 106.52kB +0.07% (72.00B)

@charliermarsh
Copy link
Member

(Attempting to push a change to get the remaining conformance tests passing.)

@charliermarsh
Copy link
Member

I will let @carljm merge (or not) since he is more well-versed in the semantics.

@carljm carljm self-requested a review February 16, 2026 07:39
@carljm carljm assigned carljm and unassigned charliermarsh Feb 16, 2026
Copy link
Member

@AlexWaygood AlexWaygood left a comment

Choose a reason for hiding this comment

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

I understand the rationale for resolving .value and ._value_ to Any if __init__ is defined. But I don't understand the rationale for not doing any validation of the right-hand side of member assignments if __init__ is assigned. It seems like we could fairly easily validate the right-hand side of member assignments against the parameters that __init__ expects.

Is this just a short-term simplification? If so, that's fine, but we should add some TODO comments and make clear in the tests that we could add validation against __init__ parameters in the future. (But I also don't think it would be too complex to just do it in this PR.)

self._value_ = value # error: [invalid-assignment]

MERCURY = (1, 3.303e23, 2.4397e6)
SATURN = "saturn"
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand the rationale for "falling back to Any" for member validation here. This fails at runtime -- could we not catch the runtime error by synthesizing a call to the __init__ signature if __init__ is defined? (The right-hand side of the SATURN assignment should be an int, float, float tuple, because those are the parameters expected by __init__ here.)

Copy link
Member

Choose a reason for hiding this comment

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

Hmm yeah, this seems wrong. I think I was confused by this conformance test:

class Planet2(Enum):
    _value_: str

    def __init__(self, value: int, mass: float, radius: float):
        self._value_ = value  # E

    MERCURY = (1, 3.303e23, 2.4397e6)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah there should be an error on this line, we should be validating against the __init__ signature. I think the previous version of this PR did that correctly?

Comment on lines 159 to 175
When `__init__` is defined but no explicit `_value_` annotation exists, we also fall back to `Any`
for member value validation:

```py
from enum import Enum

class Planet2(Enum):
def __init__(self, mass: float, radius: float):
self.mass = mass
self.radius = radius

MERCURY = (3.303e23, 2.4397e6)
VENUS = (4.869e24, 6.0518e6)

reveal_type(Planet2.MERCURY.value) # revealed: Any
reveal_type(Planet2.MERCURY._value_) # revealed: Any
```
Copy link
Member

Choose a reason for hiding this comment

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

I'm confused: the prose here describes "falling back to Any for member validation". But that's not what the test demonstrates. The test demonstrates that we infer Any for the .value and ._value_ attributes. But when it comes to validation of the right-hand sides of the MERCURY and VENUS assignments, this test uses right-hand sides which are compatible with the __init__ signature in both cases, so the test would still pass even if we did not "fallback to Any for member validation".

rayzeller added a commit to rayzeller/ruff that referenced this pull request Feb 20, 2026
…pport

Strip the `_value_` annotation lookup logic (`enum_value_annotation_type`
and `own_value_annotation`) to avoid overlap with astral-sh#22228, which handles
`_value_` semantics more broadly. Custom `__new__` enums now always fall
back to `Any` for the member value type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rayzeller added a commit to rayzeller/ruff that referenced this pull request Feb 20, 2026
…pport

Strip the `_value_` annotation lookup logic (`enum_value_annotation_type`
and `own_value_annotation`) to avoid overlap with astral-sh#22228, which handles
`_value_` semantics more broadly. Custom `__new__` enums now always fall
back to `Any` for the member value type.

Also remove the redundant known-class skip list from `has_custom_enum_new`
— the vendored path check already covers all stdlib classes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rayzeller added a commit to rayzeller/ruff that referenced this pull request Feb 20, 2026
…new`

Remove the `_value_` annotation lookup logic to avoid overlap with astral-sh#22228,
which handles `_value_` semantics more broadly. Custom `__new__` enums now
always fall back to `Any`. Also remove the redundant known-class skip list
from `has_custom_enum_new` — the vendored path check already covers all
stdlib classes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

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

Just reviewed the tests for now -- will review the code once it looks like the tests are specifying the right semantics.

It looks to me like @AlexWaygood 's comments from a few days ago were exactly right -- no need to wait for me to confirm!

Comment on lines +117 to +118
# In stub files, `[]` is not exempt from type checking (only `...` is).
PURPLE = [] # error: [invalid-assignment]
Copy link
Contributor

@carljm carljm Feb 21, 2026

Choose a reason for hiding this comment

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

Kind of an odd comment and test. Not necessarily opposed to including the test, but I don't really get why anyone would think that [] would be a special case here.

self._value_ = value # error: [invalid-assignment]

MERCURY = (1, 3.303e23, 2.4397e6)
SATURN = "saturn"
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah there should be an error on this line, we should be validating against the __init__ signature. I think the previous version of this PR did that correctly?

### `_value_` annotation with `__init__`

When `__init__` is defined, member values are passed through `__init__` rather than directly
assigned to `_value_`, so we fall back to `Any` for member value validation. The `_value_`
Copy link
Contributor

Choose a reason for hiding this comment

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

We shouldn't fall back to Any for validation. We should validate against the __init__ signature.

We should fall back to Any for the type of .value or ._value_ on individual members, if there is no annotated _value_ type on the enum class. (If there is, we should use that -- and validate assignments to self._value_ in __init__ according to that annotation, as you already do.)

Comment on lines 159 to 160
When `__init__` is defined but no explicit `_value_` annotation exists, we also fall back to `Any`
for member value validation:
Copy link
Contributor

Choose a reason for hiding this comment

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

We should never "fall back to Any for member value validation." What this test (correctly) shows is that we are falling back to Any for the type of .value and ._value_ on the resulting members. But this comment is wrong.

Comment on lines 177 to 192
### Inherited `_value_` annotation

A `_value_` annotation on a parent enum is not inherited by subclasses for the purpose of member
value validation:

```py
from enum import Enum

class Base(Enum):
_value_: int

class Child(Base):
A = 1
B = "not checked against int"

reveal_type(Child.A.value) # revealed: Literal[1]
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this specified, or just something observed in the ecosystem?

Copy link
Member

Choose a reason for hiding this comment

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

I think it's unspecified... I think Pyright does inherit _value_, mypy does not.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this PR currently doesn't inherit __init__ from a base class, and it needs to do so in order to match runtime behavior on e.g. this example:

from enum import Enum

class Base(Enum):
    def __init__(self, a: int, b: str):
        self._value_ = a

class Child(Base):
    A = (1, "foo")
    B = "should be checked against __init__"  # should error, currently doesn't

reveal_type(Child.A.value)  # should reveal `Any`, currently reveals `tuple[Literal[1], Literal["foo"]]`

At runtime A and B do pass through Base.__init__, so we should also model that.

And once we model that correctly, I think the only consistent/correct approach is also to inherit _value_ annotation from a base.

@charliermarsh
Copy link
Member

(We realized offline that I had addressed some feedback but pushed to the wrong branch... So I just updated this PR now.)

Comment on lines 177 to 192
### Inherited `_value_` annotation

A `_value_` annotation on a parent enum is not inherited by subclasses for the purpose of member
value validation:

```py
from enum import Enum

class Base(Enum):
_value_: int

class Child(Base):
A = 1
B = "not checked against int"

reveal_type(Child.A.value) # revealed: Literal[1]
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this PR currently doesn't inherit __init__ from a base class, and it needs to do so in order to match runtime behavior on e.g. this example:

from enum import Enum

class Base(Enum):
    def __init__(self, a: int, b: str):
        self._value_ = a

class Child(Base):
    A = (1, "foo")
    B = "should be checked against __init__"  # should error, currently doesn't

reveal_type(Child.A.value)  # should reveal `Any`, currently reveals `tuple[Literal[1], Literal["foo"]]`

At runtime A and B do pass through Base.__init__, so we should also model that.

And once we model that correctly, I think the only consistent/correct approach is also to inherit _value_ annotation from a base.

_value_: str

def __init__(self, value: int, mass: float, radius: float):
self._value_ = value # error: [invalid-assignment]
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's also have a happy-path test with both _value_ annotation and __init__, where the assignment to _value_ in __init__ is correct.

@charliermarsh charliermarsh requested a review from carljm February 23, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants