Skip to content

[ty] Promote class-literal types to type in invariant contexts#23872

Closed
AlexWaygood wants to merge 1 commit intomainfrom
alex/promote-class-literals
Closed

[ty] Promote class-literal types to type in invariant contexts#23872
AlexWaygood wants to merge 1 commit intomainfrom
alex/promote-class-literals

Conversation

@AlexWaygood
Copy link
Member

Summary

Test Plan

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Mar 10, 2026
@AlexWaygood AlexWaygood changed the title [ty] Promote class-literal types to type in invariant context [ty] Promote class-literal types to type in invariant contexts Mar 10, 2026
@AlexWaygood
Copy link
Member Author

something I did made rustfmt decide it wanted to reformat the entire function (I think a comment placed in exactly the wrong place meant it couldn't format anything in this function before...)

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 10, 2026

Typing conformance results improved 🎉

The percentage of diagnostics emitted that were expected errors increased from 85.29% to 85.30%. The percentage of expected errors that received a diagnostic increased from 78.13% to 78.23%. The number of fully passing files held steady at 64/132.

Summary

How are test cases classified?

Each test case represents one expected error annotation or a group of annotations sharing a tag. Counts are per test case, not per diagnostic — multiple diagnostics on the same line count as one. Required annotations (E) are true positives when ty flags the expected location and false negatives when it does not. Optional annotations (E?) are true positives when flagged but true negatives (not false negatives) when not. Tagged annotations (E[tag]) require ty to flag exactly one of the tagged lines; tagged multi-annotations (E[tag+]) allow any number up to the tag count. Flagging unexpected locations counts as a false positive.

Metric Old New Diff Outcome
True Positives 829 830 +1 ⏫ (✅)
False Positives 143 143 +0
False Negatives 232 231 -1 ⏬ (✅)
Total Diagnostics 1049 1050 +1
Precision 85.29% 85.30% +0.02% ⏫ (✅)
Recall 78.13% 78.23% +0.09% ⏫ (✅)
Passing Files 64/132 64/132 +0

Test file breakdown

1 file altered
File True Positives False Positives False Negatives Status
aliases_implicit.py 18 (+1) ✅ 1 4 (-1) ✅ 📈 Improving
Total (all files) 830 (+1) ✅ 143 231 (-1) ✅ 64/132

True positives added (1)

1 diagnostic
Test case Diff

aliases_implicit.py:112

+error[invalid-type-form] Variable of type `type` is not allowed in a type expression

True positives changed (6)

6 diagnostics
Test case Diff

aliases_implicit.py:109

-error[invalid-type-form] Variable of type `list[<class 'int'>]` is not allowed in a type expression
+error[invalid-type-form] Variable of type `list[type]` is not allowed in a type expression

aliases_type_statement.py:43

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
-error[invalid-type-form] Int literals are not allowed in this context in a type expression
+error[invalid-type-form] Invalid subscript of object of type `list[type]` in type expression
+error[invalid-type-form] Int literals are not allowed in this context in a type expression

aliases_typealiastype.py:58

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
-error[invalid-type-form] Int literals are not allowed in this context in a type expression
+error[invalid-type-form] Invalid subscript of object of type `list[type]` in type expression
+error[invalid-type-form] Int literals are not allowed in this context in a type expression

annotations_forward_refs.py:47

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
-error[invalid-type-form] Int literals are not allowed in this context in a type expression
+error[invalid-type-form] Invalid subscript of object of type `list[type]` in type expression
+error[invalid-type-form] Int literals are not allowed in this context in a type expression

annotations_typeexpr.py:94

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
-error[invalid-type-form] Int literals are not allowed in this context in a type expression
+error[invalid-type-form] Invalid subscript of object of type `list[type]` in type expression
+error[invalid-type-form] Int literals are not allowed in this context in a type expression

qualifiers_annotated.py:43

-error[invalid-type-form] Invalid subscript of object of type `list[<class 'int'>]` in type expression
-error[invalid-type-form] Int literals are not allowed in this context in a type expression
+error[invalid-type-form] Invalid subscript of object of type `list[type]` in type expression
+error[invalid-type-form] Int literals are not allowed in this context in a type expression

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 10, 2026

Memory usage report

Summary

Project Old New Diff Outcome
prefect 704.46MB 704.47MB +0.00% (9.53kB)
flake8 47.91MB 47.91MB -
trio 117.80MB 117.80MB -
sphinx 265.22MB 265.19MB -0.02% (40.76kB) ⬇️

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
StaticClassLiteral<'db>::try_mro_ 6.06MB 6.06MB +0.03% (2.07kB)
FunctionType 8.49MB 8.49MB +0.01% (1.08kB)
CallableType 1.90MB 1.91MB +0.04% (864.00B)
infer_scope_types_impl 52.88MB 52.88MB +0.00% (804.00B)
UnionType<'db>::from_two_elements_ 5.15MB 5.15MB +0.01% (616.00B)
Type<'db>::try_call_dunder_get_ 10.49MB 10.49MB +0.00% (532.00B)
FunctionType<'db>::signature_ 3.88MB 3.88MB -0.01% (508.00B)
StaticClassLiteral<'db>::try_mro_::interned_arguments 1.40MB 1.40MB +0.03% (432.00B)
Type<'db>::apply_specialization_ 3.61MB 3.61MB +0.01% (416.00B)
cached_protocol_interface 401.68kB 402.04kB +0.09% (360.00B)
is_redundant_with_impl::interned_arguments 5.35MB 5.35MB +0.01% (352.00B)
Type<'db>::class_member_with_policy_ 17.30MB 17.30MB +0.00% (336.00B)
Type<'db>::apply_specialization_::interned_arguments 2.88MB 2.88MB +0.01% (320.00B)
Type<'db>::class_member_with_policy_::interned_arguments 9.35MB 9.35MB +0.00% (312.00B)
is_redundant_with_impl 5.57MB 5.57MB +0.01% (312.00B)
... 19 more

sphinx

Name Old New Diff Outcome
StaticClassLiteral<'db>::try_mro_ 2.11MB 2.10MB -0.64% (13.83kB) ⬇️
infer_expression_types_impl 21.51MB 21.52MB +0.05% (12.02kB) ⬇️
Specialization 1.02MB 1.02MB -0.46% (4.81kB) ⬇️
FunctionType 3.12MB 3.12MB -0.12% (3.95kB) ⬇️
Type<'db>::class_member_with_policy_ 7.55MB 7.55MB -0.04% (3.18kB) ⬇️
GenericAlias 452.74kB 449.86kB -0.64% (2.88kB) ⬇️
StaticClassLiteral<'db>::try_mro_::interned_arguments 487.76kB 485.02kB -0.56% (2.74kB) ⬇️
Type<'db>::apply_specialization_ 1.66MB 1.66MB -0.16% (2.73kB) ⬇️
Type<'db>::try_call_dunder_get_ 4.94MB 4.94MB -0.05% (2.60kB) ⬇️
CallableType 1.08MB 1.07MB -0.23% (2.53kB) ⬇️
Type<'db>::apply_specialization_::interned_arguments 1.45MB 1.45MB -0.16% (2.42kB) ⬇️
FunctionType<'db>::signature_ 2.28MB 2.27MB -0.09% (2.15kB) ⬇️
Type<'db>::class_member_with_policy_::interned_arguments 3.99MB 3.99MB -0.05% (2.13kB) ⬇️
code_generator_of_static_class 529.56kB 527.68kB -0.36% (1.88kB) ⬇️
cached_protocol_interface 196.69kB 195.54kB -0.58% (1.15kB) ⬇️
... 14 more

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 10, 2026

mypy_primer results

Changes were detected when running on open source projects
scrapy (https://github.com/scrapy/scrapy)
- tests/test_logformatter.py:286:9: error[invalid-assignment] Invalid subscript assignment with key of type `Literal["LOG_FORMATTER"]` and value of type `<class 'SkipMessagesLogFormatter'>` on object of type `dict[str, str | dict[<class 'DropSomeItemsPipeline'>, int]]`
+ tests/test_logformatter.py:286:9: error[invalid-assignment] Invalid subscript assignment with key of type `Literal["LOG_FORMATTER"]` and value of type `<class 'SkipMessagesLogFormatter'>` on object of type `dict[str, str | dict[type, int]]`

vision (https://github.com/pytorch/vision)
- torchvision/models/video/resnet.py:448:51: warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ torchvision/models/video/resnet.py:411:9: error[invalid-argument-type] Argument to function `_video_resnet` is incorrect: Expected `Sequence[type[Conv3DSimple | Conv3DNoTemporal | Conv2Plus1D]]`, found `list[type]`
+ torchvision/models/video/resnet.py:485:9: error[invalid-argument-type] Argument to function `_video_resnet` is incorrect: Expected `Sequence[type[Conv3DSimple | Conv3DNoTemporal | Conv2Plus1D]]`, found `list[type]`
- Found 1418 diagnostics
+ Found 1419 diagnostics

mitmproxy (https://github.com/mitmproxy/mitmproxy)
+ mitmproxy/flowfilter.py:622:28: error[unresolved-attribute] Object of type `type` has no attribute `code`
+ mitmproxy/flowfilter.py:623:26: error[unresolved-attribute] Object of type `type` has no attribute `make`
+ mitmproxy/flowfilter.py:696:22: error[unresolved-attribute] Object of type `type` has no attribute `code`
+ mitmproxy/flowfilter.py:696:36: error[unresolved-attribute] Object of type `type` has no attribute `help`
- Found 2140 diagnostics
+ Found 2144 diagnostics

mypy (https://github.com/python/mypy)
+ mypyc/lib-rt/setup.py:76:9: error[invalid-argument-type] Argument to function `setup` is incorrect: Expected `_MutableDictLike[str, type[Command]]`, found `dict[str, type]`
- Found 1761 diagnostics
+ Found 1762 diagnostics

psycopg (https://github.com/psycopg/psycopg)
- tests/test_cursor_server.py:18:27: error[invalid-argument-type] Argument to bound method `append` is incorrect: Expected `<class 'ServerCursor'>`, found `<class 'RawServerCursor'>`
- tests/test_cursor_server_async.py:16:27: error[invalid-argument-type] Argument to bound method `append` is incorrect: Expected `<class 'AsyncServerCursor'>`, found `<class 'AsyncRawServerCursor'>`
- Found 666 diagnostics
+ Found 664 diagnostics

apprise (https://github.com/caronc/apprise)
- tests/helpers/rest.py:167:17: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `str | None`, found `Unknown | <class 'TypeError'> | Literal[PersistentStoreMode.MEMORY, PersistentStoreMode.AUTO]`
+ tests/helpers/rest.py:167:17: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `str | None`, found `Unknown | type | Literal[PersistentStoreMode.MEMORY, PersistentStoreMode.AUTO]`
- tests/helpers/rest.py:176:17: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `str | None`, found `Unknown | <class 'TypeError'> | Literal[PersistentStoreMode.MEMORY, PersistentStoreMode.AUTO]`
+ tests/helpers/rest.py:176:17: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `str | None`, found `Unknown | type | Literal[PersistentStoreMode.MEMORY, PersistentStoreMode.AUTO]`
- tests/helpers/rest.py:250:20: error[unresolved-attribute] Attribute `parse_url` is not defined on `<class 'TypeError'>` in union `(Unknown & ~None) | <class 'TypeError'>`
+ tests/helpers/rest.py:250:20: error[unresolved-attribute] Attribute `parse_url` is not defined on `type` in union `(Unknown & ~None) | type`
- tests/helpers/rest.py:251:20: error[unresolved-attribute] Attribute `parse_url` is not defined on `<class 'TypeError'>` in union `(Unknown & ~None) | <class 'TypeError'>`
+ tests/helpers/rest.py:251:20: error[unresolved-attribute] Attribute `parse_url` is not defined on `type` in union `(Unknown & ~None) | type`
- tests/helpers/rest.py:252:20: error[unresolved-attribute] Attribute `parse_url` is not defined on `<class 'TypeError'>` in union `(Unknown & ~None) | <class 'TypeError'>`
+ tests/helpers/rest.py:252:20: error[unresolved-attribute] Attribute `parse_url` is not defined on `type` in union `(Unknown & ~None) | type`
- tests/helpers/rest.py:260:53: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `(Unknown & ~AlwaysFalsy) | (<class 'TypeError'> & ~AlwaysFalsy)`
+ tests/helpers/rest.py:260:53: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `(Unknown & ~AlwaysFalsy) | (type & ~AlwaysFalsy)`
- tests/helpers/rest.py:312:29: error[unresolved-attribute] Attribute `items` is not defined on `<class 'TypeError'> & ~AlwaysFalsy` in union `(Unknown & ~AlwaysFalsy) | (<class 'TypeError'> & ~AlwaysFalsy)`
+ tests/helpers/rest.py:312:29: error[unresolved-attribute] Attribute `items` is not defined on `type & ~AlwaysFalsy` in union `(Unknown & ~AlwaysFalsy) | (type & ~AlwaysFalsy)`
- tests/test_plugin_email.py:545:36: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `<class 'TypeError'> | <class 'NotifyEmail'> | str | bool`
+ tests/test_plugin_email.py:545:36: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `type | str | bool`
- tests/test_plugin_email.py:561:24: error[unresolved-attribute] Attribute `parse_url` is not defined on `<class 'TypeError'>`, `str`, `bool` in union `<class 'TypeError'> | <class 'NotifyEmail'> | str | bool`
- tests/test_plugin_email.py:562:24: error[unresolved-attribute] Attribute `parse_url` is not defined on `<class 'TypeError'>`, `str`, `bool` in union `<class 'TypeError'> | <class 'NotifyEmail'> | str | bool`
- tests/test_plugin_email.py:563:24: error[unresolved-attribute] Attribute `parse_url` is not defined on `<class 'TypeError'>`, `str`, `bool` in union `<class 'TypeError'> | <class 'NotifyEmail'> | str | bool`
+ tests/test_plugin_email.py:561:24: error[unresolved-attribute] Object of type `type | str | bool` has no attribute `parse_url`
+ tests/test_plugin_email.py:562:24: error[unresolved-attribute] Object of type `type | str | bool` has no attribute `parse_url`
+ tests/test_plugin_email.py:563:24: error[unresolved-attribute] Object of type `type | str | bool` has no attribute `parse_url`
- tests/test_plugin_email.py:571:57: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `(<class 'TypeError'> & ~AlwaysFalsy) | (<class 'NotifyEmail'> & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | Literal[True]`
+ tests/test_plugin_email.py:571:57: error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `(type & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | Literal[True]`
- tests/test_plugin_email.py:596:33: error[unresolved-attribute] Object of type `(<class 'TypeError'> & ~AlwaysFalsy) | (<class 'NotifyEmail'> & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | Literal[True]` has no attribute `items`
+ tests/test_plugin_email.py:596:33: error[unresolved-attribute] Object of type `(type & ~AlwaysFalsy) | (str & ~AlwaysFalsy) | Literal[True]` has no attribute `items`
- tests/test_plugin_email.py:622:38: error[not-iterable] Object of type `(<class 'TypeError'> & ~AlwaysTruthy) | (<class 'NotifyEmail'> & ~AlwaysTruthy) | (str & ~AlwaysTruthy) | tuple[SMTPHeloError, SMTPException, RuntimeError, SMTPRecipientsRefused, SMTPSenderRefused, SMTPDataError, SMTPServerDisconnected]` may not be iterable
+ tests/test_plugin_email.py:622:38: error[not-iterable] Object of type `(type & ~AlwaysTruthy) | (str & ~AlwaysTruthy) | tuple[SMTPHeloError, SMTPException, RuntimeError, SMTPRecipientsRefused, SMTPSenderRefused, SMTPDataError, SMTPServerDisconnected]` may not be iterable
- tests/test_plugin_email.py:648:38: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `<class 'TypeError'> | bool | <class 'NotifyEmail'> | str`
+ tests/test_plugin_email.py:648:38: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `type | bool | str`
- tests/test_plugin_email.py:660:34: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `<class 'TypeError'> | <class 'NotifyEmail'> | str | bool`
+ tests/test_plugin_email.py:660:34: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `type | str | bool`
- tests/test_plugin_growl.py:323:36: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `(Unknown & ~None) | <class 'NotifyGrowl'> | bool`
+ tests/test_plugin_growl.py:323:36: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `(Unknown & ~None) | type | bool`
- tests/test_plugin_growl.py:349:33: error[unresolved-attribute] Attribute `items` is not defined on `<class 'NotifyGrowl'> & ~AlwaysFalsy`, `Literal[True]` in union `(Unknown & ~AlwaysFalsy) | (<class 'NotifyGrowl'> & ~AlwaysFalsy) | Literal[True]`
+ tests/test_plugin_growl.py:349:33: error[unresolved-attribute] Attribute `items` is not defined on `type & ~AlwaysFalsy`, `Literal[True]` in union `(Unknown & ~AlwaysFalsy) | (type & ~AlwaysFalsy) | Literal[True]`
- tests/test_plugin_growl.py:367:38: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `None | Unknown | <class 'NotifyGrowl'> | bool`
+ tests/test_plugin_growl.py:367:38: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `None | Unknown | type | bool`
- tests/test_plugin_growl.py:376:34: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `(Unknown & ~None) | <class 'NotifyGrowl'> | bool`
+ tests/test_plugin_growl.py:376:34: error[invalid-argument-type] Argument to function `isinstance` is incorrect: Expected `type | tuple[Divergent, ...]`, found `(Unknown & ~None) | type | bool`

manticore (https://github.com/trailofbits/manticore)
+ server/setup.py:62:5: error[invalid-argument-type] Argument to function `setup` is incorrect: Expected `_MutableDictLike[str, type[Command]]`, found `dict[str, type]`
- Found 11090 diagnostics
+ Found 11091 diagnostics

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 60 diagnostics
+ Found 59 diagnostics

prefect (https://github.com/PrefectHQ/prefect)
+ src/prefect/server/orchestration/global_policy.py:102:16: error[invalid-return-type] Return type does not match returned value: expected `list[type[BaseUniversalTransform[TaskRun, TaskRunPolicy] | BaseOrchestrationRule[TaskRun, TaskRunPolicy]]]`, found `list[type]`
- Found 5883 diagnostics
+ Found 5884 diagnostics

pywin32 (https://github.com/mhammond/pywin32)
+ adodbapi/setup.py:46:9: error[invalid-argument-type] Argument to function `setup` is incorrect: Expected `_MutableDictLike[str, type[Command]]`, found `dict[str, type]`
+ com/win32com/test/testall.py:240:76: error[invalid-argument-type] Argument to bound method `loadTestsFromTestCase` is incorrect: Expected `type[TestCase]`, found `type | Unknown`
- Found 2739 diagnostics
+ Found 2741 diagnostics

ibis (https://github.com/ibis-project/ibis)
- ibis/backends/bigquery/tests/system/udf/test_udf_execute.py:51:9: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `dict[str, <class 'float'>]`
+ ibis/backends/bigquery/tests/system/udf/test_udf_execute.py:51:9: error[invalid-argument-type] Argument is incorrect: Expected `bool`, found `dict[str, type]`

sympy (https://github.com/sympy/sympy)
- sympy/polys/matrices/tests/test_xxm.py:72:26: error[invalid-argument-type] Argument to bound method `append` is incorrect: Expected `<class 'DDM'>`, found `<class 'DFM'> | <class 'DFM_dummy'>`
- Found 16479 diagnostics
+ Found 16478 diagnostics

static-frame (https://github.com/static-frame/static-frame)
+ static_frame/core/util.py:732:9: error[invalid-assignment] Object of type `Unknown | list[tuple[str, None | Unknown, type, None | Unknown, int]]` is not assignable to attribute `filters` of type `Sequence[tuple[str, Pattern[str] | None, type[Warning], Pattern[str] | None, int]]`
- static_frame/test/unit/test_frame.py:995:36: error[invalid-argument-type] Argument to bound method `from_pandas` is incorrect: Expected `Iterable[str | dtype[Any] | type | None] | dtype[Any] | type | None | dict[Hashable, str | dtype[Any] | type | None]`, found `dict[int, <class 'bool'>]`
+ static_frame/test/unit/test_frame.py:995:36: error[invalid-argument-type] Argument to bound method `from_pandas` is incorrect: Expected `Iterable[str | dtype[Any] | type | None] | dtype[Any] | type | None | dict[Hashable, str | dtype[Any] | type | None]`, found `dict[int, type]`
- static_frame/test/unit/test_frame.py:14742:24: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `str | dtype[Any] | type | None`, found `dict[str, <class 'str'>]`
+ static_frame/test/unit/test_frame.py:14742:24: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `str | dtype[Any] | type | None`, found `dict[str, type]`
- static_frame/test/unit/test_frame.py:14785:24: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `str | dtype[Any] | type | None`, found `dict[str | int, <class 'bool'>]`
+ static_frame/test/unit/test_frame.py:14785:24: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `str | dtype[Any] | type | None`, found `dict[str | int, type]`
- static_frame/test/unit/test_index_hierarchy.py:4459:28: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `dtype[Any]`, found `dict[int, <class 'str'>]`
+ static_frame/test/unit/test_index_hierarchy.py:4459:28: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `dtype[Any]`, found `dict[int, type]`
- static_frame/test/unit/test_type_blocks.py:3539:47: error[invalid-argument-type] Argument to function `get_col_dtype_factory` is incorrect: Expected `Iterable[str | dtype[Any] | type | None] | dtype[Any] | type | None | dict[Hashable, str | dtype[Any] | type | None]`, found `dict[int, <class 'str'>]`
+ static_frame/test/unit/test_type_blocks.py:3539:47: error[invalid-argument-type] Argument to function `get_col_dtype_factory` is incorrect: Expected `Iterable[str | dtype[Any] | type | None] | dtype[Any] | type | None | dict[Hashable, str | dtype[Any] | type | None]`, found `dict[int, type]`
- static_frame/test/unit/test_type_blocks.py:3557:13: error[invalid-argument-type] Argument to function `get_col_dtype_factory` is incorrect: Expected `Iterable[str | dtype[Any] | type | None] | dtype[Any] | type | None | dict[Hashable, str | dtype[Any] | type | None]`, found `dict[int, <class 'str'>]`
+ static_frame/test/unit/test_type_blocks.py:3557:13: error[invalid-argument-type] Argument to function `get_col_dtype_factory` is incorrect: Expected `Iterable[str | dtype[Any] | type | None] | dtype[Any] | type | None | dict[Hashable, str | dtype[Any] | type | None]`, found `dict[int, type]`
- Found 1819 diagnostics
+ Found 1820 diagnostics

pandas (https://github.com/pandas-dev/pandas)
- pandas/plotting/_matplotlib/core.py:711:33: error[invalid-argument-type] Argument to bound method `extend` is incorrect: Expected `Iterable[<class 'number'>]`, found `list[str]`
+ pandas/plotting/_matplotlib/core.py:711:33: error[invalid-argument-type] Argument to bound method `extend` is incorrect: Expected `Iterable[type]`, found `list[str]`

jax (https://github.com/google/jax)
+ jax/_src/checkify.py:1172:14: error[invalid-parameter-default] Default value of type `frozenset[type]` is not assignable to annotated parameter type `frozenset[type[JaxException]]`
- jax/experimental/colocated_python/serialization.py:243:9: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `MutableMapping[<class 'Mesh'> | <class 'NamedSharding'> | <class 'DeviceList'> | <class 'SingleDeviceSharding'>, (Any, /) -> tuple[Any, Any]]`, found `dict[<class 'Mesh'>, (Any, /) -> tuple[Any, Any]]`
- jax/experimental/colocated_python/serialization.py:244:9: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `MutableMapping[<class 'Mesh'> | <class 'NamedSharding'> | <class 'DeviceList'> | <class 'SingleDeviceSharding'>, (Any, /) -> tuple[Any, Any]]`, found `dict[<class 'NamedSharding'>, (Any, /) -> tuple[Any, Any]]`
- jax/experimental/colocated_python/serialization.py:245:9: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `MutableMapping[<class 'Mesh'> | <class 'NamedSharding'> | <class 'DeviceList'> | <class 'SingleDeviceSharding'>, (Any, /) -> tuple[Any, Any]]`, found `dict[<class 'DeviceList'>, (Any, /) -> tuple[Any, Any]]`
- jax/experimental/colocated_python/serialization.py:246:9: error[invalid-argument-type] Argument to bound method `__init__` is incorrect: Expected `MutableMapping[<class 'Mesh'> | <class 'NamedSharding'> | <class 'DeviceList'> | <class 'SingleDeviceSharding'>, (Any, /) -> tuple[Any, Any]]`, found `dict[<class 'SingleDeviceSharding'>, (Any, /) -> tuple[Any, Any]]`
- Found 2152 diagnostics
+ Found 2149 diagnostics

rotki (https://github.com/rotki/rotki)
- rotkehlchen/logging.py:209:20: error[invalid-argument-type] Invalid argument to key "filters" with declared type `dict[str, _FilterConfigurationTypedDict | dict[str, Any]]` on TypedDict `_DictConfigArgs`: value of type `dict[str, dict[str, <class 'PywsgiFilter'>]]`
+ rotkehlchen/logging.py:209:20: error[invalid-argument-type] Invalid argument to key "filters" with declared type `dict[str, _FilterConfigurationTypedDict | dict[str, Any]]` on TypedDict `_DictConfigArgs`: value of type `dict[str, dict[str, type]]`

scipy (https://github.com/scipy/scipy)
+ scipy/fft/_backend.py:46:8: error[unresolved-attribute] Attribute `__ua_domain__` is not defined on `type` in union `(Unknown & ~str) | type`
- Found 7976 diagnostics
+ Found 7977 diagnostics

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 10, 2026

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-argument-type 6 5 19
unresolved-attribute 5 0 9
invalid-assignment 1 0 1
invalid-parameter-default 1 0 0
invalid-return-type 1 0 0
not-iterable 0 0 1
unused-type-ignore-comment 0 1 0
Total 14 6 30

Full report with detailed diff (timing results)


Type::ClassLiteral(class) => match type_mapping {
TypeMapping::Promote(PromotionMode::On) => {
SubclassOfType::from(db, ClassType::NonGeneric(class))
Copy link
Contributor

Choose a reason for hiding this comment

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

This promotes e.g. int to type[int], not to just type. Which is a reasonable promotion, but I think unlikely to help most invariant cases? It assumes that by [int] you mean list[type[int]], which is still too precise if you later wanted to insert str into the list.

This is a tricky one because type types are already weird. It's hard to say whether you meant a list of callables, or a list of type objects that you want to later use in e.g. isinstance, or what.

Copy link
Contributor

Choose a reason for hiding this comment

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

For example, it means this PR still wouldn't help with astral-sh/ty#3013

Copy link
Member Author

Choose a reason for hiding this comment

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

This promotes e.g. int to type[int], not to just type.

I know that 😛 this is a draft PR for a reason, I'm playing around with stuff! The PR title is out of date.

the first thing I tried was promoting class-literal types all the way to type, as per the PR description, and it did indeed fix a bunch of false positives, but it also caused a bunch of new ones. So I then tried doing the halfway promotion to a subclass-of type, but now we have a very underwhelming ecosystem report such that I'm not sure it's worth it.

I think we may just have to wait for better bidirectional inference on this one

@AlexWaygood AlexWaygood force-pushed the alex/promote-class-literals branch from 55301b1 to 4820b87 Compare March 11, 2026 18:15
@AlexWaygood AlexWaygood force-pushed the alex/promote-class-literals branch from 4820b87 to a34e880 Compare March 11, 2026 18:15
@AlexWaygood
Copy link
Member Author

AlexWaygood commented Mar 11, 2026

I've tried three different kinds of promotion here (recursive promotion to type, recursive promotion to subclass-of types, and non-recursive promotion to type). None of them seemed to make an impact on the ecosystem report that was both significant and unambiguously positive, so I don't think it's worth doing anything here

@AlexWaygood AlexWaygood deleted the alex/promote-class-literals branch March 11, 2026 18:24
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.

2 participants