Skip to content

[ty] Preserve constrained TypeVar mappings at ** call sites#24452

Draft
charliermarsh wants to merge 5 commits intocharlie/td-unionfrom
charlie/td-star
Draft

[ty] Preserve constrained TypeVar mappings at ** call sites#24452
charliermarsh wants to merge 5 commits intocharlie/td-unionfrom
charlie/td-star

Conversation

@charliermarsh
Copy link
Copy Markdown
Member

@charliermarsh charliermarsh commented Apr 6, 2026

Summary

This PR improves support for **kwargs in cases where kwargs is a constrained TypeVar. We now compute the exact keys instead of falling back to the generic mapping case.

@astral-sh-bot astral-sh-bot bot added the ty Multi-file analysis & type inference label Apr 6, 2026
@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Apr 6, 2026

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 87.72%. The percentage of expected errors that received a diagnostic held steady at 82.85%. The number of fully passing files held steady at 74/132.

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Apr 6, 2026

Memory usage report

Summary

Project Old New Diff Outcome
flake8 48.02MB 48.02MB -
sphinx 264.90MB 264.90MB -
trio 117.77MB 117.77MB -
prefect 716.92MB 716.91MB -0.00% (17.10kB) ⬇️

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
CallableType 2.12MB 2.11MB -0.14% (2.95kB) ⬇️
infer_definition_types 89.52MB 89.52MB -0.00% (1.70kB) ⬇️
Type<'db>::class_member_with_policy_ 17.99MB 17.99MB -0.01% (1.45kB) ⬇️
Type<'db>::try_call_dunder_get_ 10.82MB 10.82MB -0.01% (1.33kB) ⬇️
Type<'db>::class_member_with_policy_::interned_arguments 9.73MB 9.73MB -0.01% (1.02kB) ⬇️
FunctionType 8.75MB 8.75MB -0.01% (960.00B) ⬇️
infer_deferred_types 14.40MB 14.40MB -0.01% (792.00B) ⬇️
FunctionType<'db>::signature_ 4.01MB 4.01MB -0.02% (768.00B) ⬇️
TupleType 716.09kB 715.44kB -0.09% (672.00B) ⬇️
Type<'db>::apply_specialization_::interned_arguments 2.93MB 2.93MB -0.02% (480.00B) ⬇️
Type<'db>::member_lookup_with_policy_ 16.35MB 16.35MB -0.00% (448.00B) ⬇️
GenericContext 291.21kB 290.80kB -0.14% (420.00B) ⬇️
Type<'db>::member_lookup_with_policy_::interned_arguments 5.87MB 5.87MB -0.01% (416.00B) ⬇️
Type<'db>::try_call_dunder_get_::interned_arguments 3.08MB 3.08MB -0.01% (416.00B) ⬇️
place_by_id 4.60MB 4.60MB -0.01% (400.00B) ⬇️
... 14 more

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot bot commented Apr 6, 2026

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-await 40 0 0
missing-argument 32 0 0
unknown-argument 11 0 0
invalid-return-type 1 0 6
invalid-argument-type 0 2 1
Total 84 2 7

Changes in flaky projects detected. Raw diff output excludes flaky projects; see the HTML report for details.

Raw diff (51 changes)
bokeh (https://github.com/bokeh/bokeh)
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `attr` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `cols` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `data` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `kind` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `model` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `msg_data` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `msg_type` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `new` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `patches` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `rollover` does not match any known parameter of bound method `__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `title` does not match any known parameter of bound method `__init__`

core (https://github.com/home-assistant/core)
- homeassistant/components/aprilaire/coordinator.py:106:21 error[invalid-argument-type] Argument to bound method `async_update_device` is incorrect: Expected `DeviceEntryType | None | UndefinedType`, found `set[tuple[str, str]]`
- homeassistant/components/aprilaire/coordinator.py:106:21 error[invalid-argument-type] Argument to bound method `async_update_device` is incorrect: Expected `str | None | UndefinedType`, found `set[tuple[str, str]]`
- homeassistant/components/energy/data.py:786:20 error[invalid-return-type] Return type does not match returned value: expected `BatterySourceType`, found `dict[str, Unknown | str]`
+ homeassistant/components/energy/data.py:786:20 error[invalid-return-type] Return type does not match returned value: expected `BatterySourceType`, found `dict[str, PowerConfig | str]`
- homeassistant/components/energy/data.py:789:16 error[invalid-return-type] Return type does not match returned value: expected `BatterySourceType`, found `dict[str, Unknown | str]`
+ homeassistant/components/energy/data.py:789:16 error[invalid-return-type] Return type does not match returned value: expected `BatterySourceType`, found `dict[str, PowerConfig | str]`
- homeassistant/components/energy/data.py:804:20 error[invalid-return-type] Return type does not match returned value: expected `GridSourceType`, found `dict[str, Unknown | str]`
+ homeassistant/components/energy/data.py:804:20 error[invalid-return-type] Return type does not match returned value: expected `GridSourceType`, found `dict[str, int | float | str | None | PowerConfig]`
- homeassistant/components/energy/data.py:807:16 error[invalid-return-type] Return type does not match returned value: expected `GridSourceType`, found `dict[str, Unknown | str]`
+ homeassistant/components/energy/data.py:807:16 error[invalid-return-type] Return type does not match returned value: expected `GridSourceType`, found `dict[str, int | float | str | None | PowerConfig]`

graphql-core (https://github.com/graphql-python/graphql-core)
+ src/graphql/type/directives.py:133:16 error[missing-argument] No arguments provided for required parameters `name`, `locations` of bound method `__init__`
+ src/graphql/utilities/extend_schema.py:295:16 error[missing-argument] No arguments provided for required parameters `name`, `locations` of bound method `__init__`
+ src/graphql/utilities/extend_schema.py:333:23 error[missing-argument] No argument provided for required parameter `type_` of bound method `__init__`
+ src/graphql/utilities/extend_schema.py:352:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/extend_schema.py:367:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/extend_schema.py:384:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/extend_schema.py:418:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/extend_schema.py:457:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/extend_schema.py:482:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/extend_schema.py:492:16 error[missing-argument] No argument provided for required parameter `type_` of bound method `__init__`
+ src/graphql/utilities/extend_schema.py:502:16 error[missing-argument] No argument provided for required parameter `type_` of bound method `__init__`
+ src/graphql/type/definition.py:291:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/type/definition.py:443:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/type/definition.py:547:16 error[missing-argument] No argument provided for required parameter `type_` of bound method `__init__`
+ src/graphql/type/definition.py:693:16 error[missing-argument] No argument provided for required parameter `type_` of bound method `__init__`
+ src/graphql/type/definition.py:773:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/type/definition.py:877:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/type/definition.py:980:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/type/definition.py:1115:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/type/definition.py:1347:16 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/type/definition.py:1444:16 error[missing-argument] No argument provided for required parameter `type_` of bound method `__init__`
+ src/graphql/utilities/lexicographic_sort_schema.py:67:16 error[missing-argument] No arguments provided for required parameters `name`, `locations` of bound method `__init__`
+ src/graphql/utilities/lexicographic_sort_schema.py:78:26 error[missing-argument] No argument provided for required parameter `type_` of bound method `__init__`
+ src/graphql/utilities/lexicographic_sort_schema.py:89:28 error[missing-argument] No argument provided for required parameter `type_` of bound method `__init__`
+ src/graphql/utilities/lexicographic_sort_schema.py:124:20 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/lexicographic_sort_schema.py:132:20 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/lexicographic_sort_schema.py:140:20 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/lexicographic_sort_schema.py:144:20 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ src/graphql/utilities/lexicographic_sort_schema.py:160:20 error[missing-argument] No argument provided for required parameter `name` of function `__new__`
+ tests/type/test_definition.py:1280:17 error[missing-argument] No argument provided for required parameter `name` of function `__new__`

pydantic (https://github.com/pydantic/pydantic)
- pydantic/_internal/_generate_schema.py:2886:16 error[invalid-return-type] Return type does not match returned value: expected `InvalidSchema | AnySchema | NoneSchema | ... omitted 49 union elements`, found `dict[str, Unknown | str]`
+ pydantic/_internal/_generate_schema.py:2886:16 error[invalid-return-type] Return type does not match returned value: expected `InvalidSchema | AnySchema | NoneSchema | ... omitted 49 union elements`, found `dict[str, int | list[str] | list[ArgumentsParameter] | ... omitted 91 union elements]`
- pydantic/types.py:1772:17 error[invalid-argument-type] Argument to function `no_info_after_validator_function` is incorrect: Expected `InvalidSchema | AnySchema | NoneSchema | ... omitted 49 union elements`, found `dict[str, Unknown | bool]`
+ pydantic/types.py:1772:17 error[invalid-argument-type] Argument to function `no_info_after_validator_function` is incorrect: Expected `InvalidSchema | AnySchema | NoneSchema | ... omitted 49 union elements`, found `dict[str, int | list[str] | list[ArgumentsParameter] | ... omitted 91 union elements]`

pyjwt (https://github.com/jpadilla/pyjwt)
- jwt/api_jwt.py:88:16 error[invalid-return-type] Return type does not match returned value: expected `FullOptions`, found `dict[str, Unknown]`
+ jwt/api_jwt.py:88:16 error[invalid-return-type] Return type does not match returned value: expected `FullOptions`, found `dict[Literal["enforce_minimum_key_length", "require", "strict_aud", "verify_aud", "verify_exp", ... omitted 6 literals], bool | list[str]]`

pylint (https://github.com/pycqa/pylint)
+ pylint/checkers/base_checker.py:207:16 error[missing-argument] No argument provided for required parameter `scope` of bound method `__init__`

Full report with detailed diff (timing results)

@charliermarsh charliermarsh marked this pull request as ready for review April 6, 2026 19:23
@charliermarsh charliermarsh marked this pull request as draft April 6, 2026 19:49
@charliermarsh charliermarsh force-pushed the charlie/td-star branch 2 times, most recently from 966da8d to c3c3c39 Compare April 6, 2026 19:52
@charliermarsh
Copy link
Copy Markdown
Member Author

  • The Pylint error is passing **options to a function that requires scope, but options has total=False. It works in practice because they call options.setdefault("scope", default_scope) just before. So maybe this should work?

  • The Prefect example is very similar. They initialize a TypedDict with total=False to "interval": timedelta(seconds=interval)... then pass it to a function that requires interval. I think that would be better modeled by making it a non-required key, rather than using total=False?

  • I think the graphql-core diagnostics are true positives because they're using total=False and assuming they are complete in various ways.

  • The Bokeh diagnostics seem very hard to model. The TypedDict variants have a discriminant, and they use that discriminant to select the right handler. But we don't track that, and so various keys across the union are considered unsupported arguments.

@charliermarsh
Copy link
Copy Markdown
Member Author

We could decide that a permissive fallback (as we were doing before) is better here. I'm not sure.

@charliermarsh charliermarsh force-pushed the charlie/td-union branch 4 times, most recently from 687c6b4 to 95f73c5 Compare April 8, 2026 18:59
@charliermarsh charliermarsh force-pushed the charlie/td-union branch 3 times, most recently from 39d13a2 to c58b08e Compare April 9, 2026 18:53
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.

2 participants