Skip to content

[ty] Validate unpacked TypedDict **kwargs arguments#24710

Open
charliermarsh wants to merge 2 commits intocharlie/unpackfrom
charlie/unpack-validate
Open

[ty] Validate unpacked TypedDict **kwargs arguments#24710
charliermarsh wants to merge 2 commits intocharlie/unpackfrom
charlie/unpack-validate

Conversation

@charliermarsh
Copy link
Copy Markdown
Member

@charliermarsh charliermarsh commented Apr 19, 2026

Summary

This PR improves validation of **kwargs unpacking against Unpack[TypedDict] at call sites.

In particular, we now distinguish definitely-present keys from maybe-present keys, so required parameters are no
longer treated as satisfied by optional TypedDict entries, duplicate explicit keywords are diagnosed correctly, etc.

Comparing our behavior before and after:

from typing import TypedDict, Unpack

class MaybeX(TypedDict, total=False):
    x: int

class HasX(TypedDict):
    x: int

def takes_required_x(**kwargs: Unpack[HasX]) -> None: ...
def takes_x(*, x: int) -> None: ...

maybe_x: MaybeX = {}

# Before: accepted
# After: error[missing-argument]
takes_required_x(**maybe_x)
                 
# Before: accepted
# After: error[parameter-already-assigned]
takes_x(x=1, **maybe_x)

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

astral-sh-bot Bot commented Apr 19, 2026

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 88.34%. The percentage of expected errors that received a diagnostic held steady at 84.42%. The number of fully passing files held steady at 81/133.

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented Apr 19, 2026

Memory usage report

Memory usage unchanged ✅

@astral-sh-bot
Copy link
Copy Markdown

astral-sh-bot Bot commented Apr 19, 2026

ecosystem-analyzer results

Lint rule Added Removed Changed
missing-argument 32 0 0
invalid-argument-type 0 12 0
unknown-argument 11 0 0
Total 43 12 0
Raw diff (55 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 `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `cols` does not match any known parameter of `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `data` does not match any known parameter of `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `kind` does not match any known parameter of `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `model` does not match any known parameter of `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `msg_data` does not match any known parameter of `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `msg_type` does not match any known parameter of `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `new` does not match any known parameter of `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `patches` does not match any known parameter of `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `rollover` does not match any known parameter of `DocumentChangedEvent.__init__`
+ src/bokeh/document/events.py:244:56 error[unknown-argument] Argument `title` does not match any known parameter of `DocumentChangedEvent.__init__`

core (https://github.com/home-assistant/core)
- homeassistant/components/aprilaire/coordinator.py:106:21 error[invalid-argument-type] Argument to bound method `DeviceRegistry.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 `DeviceRegistry.async_update_device` is incorrect: Expected `str | None | UndefinedType`, found `set[tuple[str, str]]`

discord.py (https://github.com/Rapptz/discord.py)
- discord/ext/commands/help.py:1087:26 error[invalid-argument-type] Argument to `HelpCommand.__init__` is incorrect: Expected `_CommandKwargs`, found `str`
- discord/ext/commands/help.py:1087:26 error[invalid-argument-type] Argument to `HelpCommand.__init__` is incorrect: Expected `bool | None`, found `str`
- discord/ext/commands/help.py:1087:26 error[invalid-argument-type] Argument to `HelpCommand.__init__` is incorrect: Expected `bool`, found `_CommandKwargs`
- discord/ext/commands/help.py:1378:26 error[invalid-argument-type] Argument to `HelpCommand.__init__` is incorrect: Expected `_CommandKwargs`, found `str`
- discord/ext/commands/help.py:1378:26 error[invalid-argument-type] Argument to `HelpCommand.__init__` is incorrect: Expected `bool | None`, found `str`
- discord/ext/commands/help.py:1378:26 error[invalid-argument-type] Argument to `HelpCommand.__init__` is incorrect: Expected `bool`, found `_CommandKwargs`
- discord/shard.py:380:50 error[invalid-argument-type] Argument to `Client.__init__` is incorrect: Expected `Status | None`, found `int | None`
- discord/shard.py:380:50 error[invalid-argument-type] Argument to `Client.__init__` is incorrect: Expected `int | None`, found `int | float | None`

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 `GraphQLDirective.__init__`
+ src/graphql/utilities/extend_schema.py:295:16 error[missing-argument] No arguments provided for required parameters `name`, `locations` of `GraphQLDirective.__init__`
+ src/graphql/utilities/extend_schema.py:333:23 error[missing-argument] No argument provided for required parameter `type_` of `GraphQLInputField.__init__`
+ src/graphql/utilities/extend_schema.py:352:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/extend_schema.py:367:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/extend_schema.py:384:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/extend_schema.py:418:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/extend_schema.py:457:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/extend_schema.py:482:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/extend_schema.py:492:16 error[missing-argument] No argument provided for required parameter `type_` of `GraphQLField.__init__`
+ src/graphql/utilities/extend_schema.py:502:16 error[missing-argument] No argument provided for required parameter `type_` of `GraphQLArgument.__init__`
+ src/graphql/type/definition.py:291:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/type/definition.py:443:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/type/definition.py:547:16 error[missing-argument] No argument provided for required parameter `type_` of `GraphQLField.__init__`
+ src/graphql/type/definition.py:693:16 error[missing-argument] No argument provided for required parameter `type_` of `GraphQLArgument.__init__`
+ src/graphql/type/definition.py:773:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/type/definition.py:877:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/type/definition.py:980:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/type/definition.py:1115:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/type/definition.py:1347:16 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/type/definition.py:1444:16 error[missing-argument] No argument provided for required parameter `type_` of `GraphQLInputField.__init__`
+ src/graphql/utilities/lexicographic_sort_schema.py:67:16 error[missing-argument] No arguments provided for required parameters `name`, `locations` of `GraphQLDirective.__init__`
+ src/graphql/utilities/lexicographic_sort_schema.py:78:26 error[missing-argument] No argument provided for required parameter `type_` of `GraphQLArgument.__init__`
+ src/graphql/utilities/lexicographic_sort_schema.py:89:28 error[missing-argument] No argument provided for required parameter `type_` of `GraphQLField.__init__`
+ src/graphql/utilities/lexicographic_sort_schema.py:124:20 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/lexicographic_sort_schema.py:132:20 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/lexicographic_sort_schema.py:140:20 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/lexicographic_sort_schema.py:144:20 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ src/graphql/utilities/lexicographic_sort_schema.py:160:20 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`
+ tests/type/test_definition.py:1280:17 error[missing-argument] No argument provided for required parameter `name` of constructor `GraphQLNamedType.__new__`

prefect (https://github.com/PrefectHQ/prefect)
+ src/prefect/cli/deployment.py:753:20 error[missing-argument] No argument provided for required parameter `interval` of `IntervalSchedule.__init__`

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

rotki (https://github.com/rotki/rotki)
- rotkehlchen/history/events/structures/solana_swap.py:111:17 error[invalid-argument-type] Argument to `SolanaSwapEvent.__init__` is incorrect: Expected `TimestampMS`, found `str | None`
- rotkehlchen/history/events/structures/solana_swap.py:111:17 error[invalid-argument-type] Argument to `SolanaSwapEvent.__init__` is incorrect: Expected `str | None`, found `Location`

Full report with detailed diff (timing results)

@charliermarsh charliermarsh force-pushed the charlie/unpack-validate branch from 9e30cce to 42d1dc6 Compare April 19, 2026 14:54
@charliermarsh charliermarsh marked this pull request as ready for review April 19, 2026 15:44
@astral-sh-bot astral-sh-bot Bot requested a review from oconnor663 April 19, 2026 15:44
@carljm carljm assigned carljm and unassigned oconnor663 Apr 20, 2026
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.

3 participants