[ty] Support Unpack[TypedDict] in **kwargs signatures#24653
[ty] Support Unpack[TypedDict] in **kwargs signatures#24653charliermarsh merged 11 commits intomainfrom
Unpack[TypedDict] in **kwargs signatures#24653Conversation
Typing conformance results improved 🎉The percentage of diagnostics emitted that were expected errors increased from 88.13% to 88.59%. The percentage of expected errors that received a diagnostic increased from 83.58% to 84.44%. The number of fully passing files improved from 81/134 to 83/134. SummaryHow 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 (
Test file breakdown2 files altered
True positives added (9)9 diagnostics
False positives removed (4)4 diagnostics
True positives changed (2)2 diagnostics
Optional Diagnostics Added (1)1 diagnostic
|
Memory usage reportSummary
Significant changesClick to expand detailed breakdownprefect
sphinx
trio
flake8
|
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
invalid-argument-type |
71 | 1 | 5 |
unused-type-ignore-comment |
0 | 32 | 0 |
no-matching-overload |
4 | 0 | 0 |
not-subscriptable |
0 | 3 | 0 |
invalid-return-type |
1 | 1 | 0 |
unresolved-attribute |
0 | 2 | 0 |
invalid-assignment |
0 | 1 | 0 |
invalid-method-override |
1 | 0 | 0 |
| Total | 77 | 40 | 5 |
Flaky changes detected. This PR summary excludes flaky changes; see the HTML report for details.
Raw diff (122 changes)
aiohttp-devtools (https://github.com/aio-libs/aiohttp-devtools)
+ aiohttp_devtools/runserver/watch.py:120:55 error[invalid-argument-type] Argument to bound method `ClientSession.get` is incorrect: Expected `SSLContext | bool | Fingerprint`, found `None | SSLContext`
+ aiohttp_devtools/runserver/watch.py:155:57 error[invalid-argument-type] Argument to bound method `ClientSession.get` is incorrect: Expected `SSLContext | bool | Fingerprint`, found `None | SSLContext`
altair (https://github.com/vega/altair)
- altair/datasets/_constraints.py:54:24 error[invalid-return-type] Return type does not match returned value: expected `Metadata`, found `dict[str, @Todo]`
- altair/datasets/_constraints.py:108:33 error[invalid-argument-type] Argument to bound method `MetaIs.from_metadata` is incorrect: Expected `Metadata`, found `dict[str, @Todo]`
- altair/utils/core.py:680:18 error[unresolved-attribute] Attribute `schema` is not defined on `NativeDataFrame`, `DataFrameLike`, `None` in union `NativeDataFrame | DataFrameLike | Unknown | None`
- altair/utils/core.py:682:22 error[not-subscriptable] Cannot subscript object of type `DataFrameLike` with no `__getitem__` method
- altair/utils/core.py:682:22 error[not-subscriptable] Cannot subscript object of type `NativeDataFrame` with no `__getitem__` method
- altair/utils/core.py:682:22 error[not-subscriptable] Cannot subscript object of type `None` with no `__getitem__` method
- altair/utils/core.py:686:39 error[unresolved-attribute] Attribute `to_native` is not defined on `NativeDataFrame`, `DataFrameLike`, `None` in union `NativeDataFrame | DataFrameLike | Unknown | None`
bokeh (https://github.com/bokeh/bokeh)
+ src/bokeh/plotting/_graph.py:131:9 error[invalid-argument-type] Argument to `GlyphRenderer.__init__` is incorrect: Argument type `Glyph | None` does not satisfy upper bound `Glyph` of type variable `GlyphType`
+ src/bokeh/plotting/_graph.py:131:9 error[invalid-argument-type] Argument to `GlyphRenderer.__init__` is incorrect: Expected `Glyph`, found `Glyph | None`
+ src/bokeh/plotting/_graph.py:149:9 error[invalid-argument-type] Argument to `GlyphRenderer.__init__` is incorrect: Argument type `Glyph | None` does not satisfy upper bound `Glyph` of type variable `GlyphType`
+ src/bokeh/plotting/_graph.py:149:9 error[invalid-argument-type] Argument to `GlyphRenderer.__init__` is incorrect: Expected `Glyph`, found `Glyph | None`
+ src/bokeh/transform.py:155:13 error[invalid-argument-type] Argument to `EqHistColorMapper.__init__` is incorrect: Expected `Sequence[str | tuple[int, int, int] | tuple[int, int, int, int | float]]`, found `Sequence[str | Color | tuple[int, int, int] | tuple[int, int, int, int | float]]`
+ src/bokeh/transform.py:158:13 error[invalid-argument-type] Argument to `EqHistColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float]`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float]`
+ src/bokeh/transform.py:159:13 error[invalid-argument-type] Argument to `EqHistColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float] | None`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float] | None`
+ src/bokeh/transform.py:160:13 error[invalid-argument-type] Argument to `EqHistColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float] | None`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float] | None`
+ src/bokeh/transform.py:200:13 error[invalid-argument-type] Argument to `CategoricalColorMapper.__init__` is incorrect: Expected `Sequence[str | tuple[int, int, int] | tuple[int, int, int, int | float]]`, found `Sequence[str | Color | tuple[int, int, int] | tuple[int, int, int, int | float]]`
+ src/bokeh/transform.py:202:13 error[invalid-argument-type] Argument to `CategoricalColorMapper.__init__` is incorrect: Expected `int`, found `int | float`
+ src/bokeh/transform.py:203:13 error[invalid-argument-type] Argument to `CategoricalColorMapper.__init__` is incorrect: Expected `int | None`, found `int | float | None`
+ src/bokeh/transform.py:204:13 error[invalid-argument-type] Argument to `CategoricalColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float]`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float]`
+ src/bokeh/transform.py:242:13 error[invalid-argument-type] Argument to `CategoricalPatternMapper.__init__` is incorrect: Expected `Sequence[Property[Literal["blank", "dot", "ring", "horizontal_line", "vertical_line", ... omitted 29 literals]]]`, found `Sequence[str]`
+ src/bokeh/transform.py:244:13 error[invalid-argument-type] Argument to `CategoricalPatternMapper.__init__` is incorrect: Expected `int`, found `int | float`
+ src/bokeh/transform.py:245:13 error[invalid-argument-type] Argument to `CategoricalPatternMapper.__init__` is incorrect: Expected `int | None`, found `int | float | None`
+ src/bokeh/transform.py:285:13 error[invalid-argument-type] Argument to `CategoricalMarkerMapper.__init__` is incorrect: Expected `Sequence[Literal["asterisk", "circle", "circle_cross", "circle_dot", "circle_x", ... omitted 23 literals]]`, found `Sequence[str]`
+ src/bokeh/transform.py:287:13 error[invalid-argument-type] Argument to `CategoricalMarkerMapper.__init__` is incorrect: Expected `int`, found `int | float`
+ src/bokeh/transform.py:288:13 error[invalid-argument-type] Argument to `CategoricalMarkerMapper.__init__` is incorrect: Expected `int | None`, found `int | float | None`
+ src/bokeh/transform.py:368:13 error[invalid-argument-type] Argument to `LinearColorMapper.__init__` is incorrect: Expected `Sequence[str | tuple[int, int, int] | tuple[int, int, int, int | float]]`, found `Sequence[str | Color | tuple[int, int, int] | tuple[int, int, int, int | float]]`
+ src/bokeh/transform.py:371:13 error[invalid-argument-type] Argument to `LinearColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float]`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float]`
+ src/bokeh/transform.py:372:13 error[invalid-argument-type] Argument to `LinearColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float] | None`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float] | None`
+ src/bokeh/transform.py:373:13 error[invalid-argument-type] Argument to `LinearColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float] | None`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float] | None`
+ src/bokeh/transform.py:415:13 error[invalid-argument-type] Argument to `LogColorMapper.__init__` is incorrect: Expected `Sequence[str | tuple[int, int, int] | tuple[int, int, int, int | float]]`, found `Sequence[str | Color | tuple[int, int, int] | tuple[int, int, int, int | float]]`
+ src/bokeh/transform.py:418:13 error[invalid-argument-type] Argument to `LogColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float]`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float]`
+ src/bokeh/transform.py:419:13 error[invalid-argument-type] Argument to `LogColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float] | None`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float] | None`
+ src/bokeh/transform.py:420:13 error[invalid-argument-type] Argument to `LogColorMapper.__init__` is incorrect: Expected `str | tuple[int, int, int] | tuple[int, int, int, int | float] | None`, found `str | Color | tuple[int, int, int] | tuple[int, int, int, int | float] | None`
+ src/bokeh/layouts.py:384:9 error[invalid-argument-type] Argument to `Toolbar.__init__` is incorrect: Expected `Literal["normal", "grey"] | None`, found `Literal["normal", "grey"] | None | UndefinedType`
+ src/bokeh/layouts.py:385:9 error[invalid-argument-type] Argument to `Toolbar.__init__` is incorrect: Expected `bool`, found `bool | UndefinedType`
+ src/bokeh/layouts.py:386:9 error[invalid-argument-type] Argument to `Toolbar.__init__` is incorrect: Expected `Literal["auto"] | Drag | ToolProxy | None`, found `ToolProxy | Tool | UndefinedType`
+ src/bokeh/layouts.py:387:9 error[invalid-argument-type] Argument to `Toolbar.__init__` is incorrect: Expected `Literal["auto"] | InspectTool | ToolProxy | Sequence[InspectTool] | None`, found `ToolProxy | Tool | UndefinedType`
+ src/bokeh/layouts.py:388:9 error[invalid-argument-type] Argument to `Toolbar.__init__` is incorrect: Expected `Literal["auto"] | Scroll | ToolProxy | None`, found `ToolProxy | Tool | UndefinedType`
+ src/bokeh/layouts.py:389:9 error[invalid-argument-type] Argument to `Toolbar.__init__` is incorrect: Expected `Literal["auto"] | Tap | ToolProxy | None`, found `ToolProxy | Tool | UndefinedType`
+ src/bokeh/layouts.py:390:9 error[invalid-argument-type] Argument to `Toolbar.__init__` is incorrect: Expected `Literal["auto"] | GestureTool | ToolProxy | None`, found `ToolProxy | Tool | UndefinedType`
+ src/bokeh/models/renderers/contour_renderer.py:112:13 error[invalid-argument-type] Argument to `ContourColorBar.__init__` is incorrect: Expected `GlyphRenderer[Glyph]`, found `Instance[GlyphRenderer[Unknown]]`
+ src/bokeh/models/renderers/contour_renderer.py:113:13 error[invalid-argument-type] Argument to `ContourColorBar.__init__` is incorrect: Expected `GlyphRenderer[Glyph]`, found `Instance[GlyphRenderer[Unknown]]`
+ src/bokeh/models/renderers/contour_renderer.py:114:13 error[invalid-argument-type] Argument to `ContourColorBar.__init__` is incorrect: Expected `Sequence[int | float]`, found `Seq[T@Seq]`
+ src/bokeh/models/renderers/contour_renderer.py:115:32 error[invalid-argument-type] Argument to `FixedTicker.__init__` is incorrect: Expected `Sequence[int | float]`, found `Seq[T@Seq]`
- src/bokeh/models/renderers/graph_renderer.py:84:45 error[invalid-argument-type] Argument to `Object.__init__` is incorrect: Argument type `() -> GlyphRenderer[Unknown]` does not satisfy upper bound `Serializable` of type variable `S`
+ src/bokeh/models/renderers/graph_renderer.py:84:45 error[invalid-argument-type] Argument to `Object.__init__` is incorrect: Argument type `() -> GlyphRenderer[Scatter]` does not satisfy upper bound `Serializable` of type variable `S`
- src/bokeh/models/renderers/graph_renderer.py:84:45 error[invalid-argument-type] Argument to `Object.__init__` is incorrect: Expected `GlyphRenderer[Unknown] | UndefinedType | IntrinsicType`, found `() -> GlyphRenderer[Unknown]`
+ src/bokeh/models/renderers/graph_renderer.py:84:45 error[invalid-argument-type] Argument to `Object.__init__` is incorrect: Expected `GlyphRenderer[Unknown] | UndefinedType | IntrinsicType`, found `() -> GlyphRenderer[Scatter]`
- src/bokeh/models/renderers/graph_renderer.py:89:45 error[invalid-argument-type] Argument to `Object.__init__` is incorrect: Argument type `() -> GlyphRenderer[Unknown]` does not satisfy upper bound `Serializable` of type variable `S`
+ src/bokeh/models/renderers/graph_renderer.py:89:45 error[invalid-argument-type] Argument to `Object.__init__` is incorrect: Argument type `() -> GlyphRenderer[MultiLine]` does not satisfy upper bound `Serializable` of type variable `S`
- src/bokeh/models/renderers/graph_renderer.py:89:45 error[invalid-argument-type] Argument to `Object.__init__` is incorrect: Expected `GlyphRenderer[Unknown] | UndefinedType | IntrinsicType`, found `() -> GlyphRenderer[Unknown]`
+ src/bokeh/models/renderers/graph_renderer.py:89:45 error[invalid-argument-type] Argument to `Object.__init__` is incorrect: Expected `GlyphRenderer[Unknown] | UndefinedType | IntrinsicType`, found `() -> GlyphRenderer[MultiLine]`
+ src/bokeh/plotting/_figure.py:243:41 error[invalid-argument-type] Argument to `CoordinateMapping.__init__` is incorrect: Expected `Range`, found `Range | None`
+ src/bokeh/plotting/_figure.py:243:60 error[invalid-argument-type] Argument to `CoordinateMapping.__init__` is incorrect: Expected `Range`, found `Range | None`
+ src/bokeh/plotting/_plot.py:90:32 error[invalid-argument-type] Argument to `FactorRange.__init__` is incorrect: Expected `Sequence[str] | Sequence[tuple[str, str]] | Sequence[tuple[str, str, str]]`, found `list[int | float | str]`
+ src/bokeh/plotting/_plot.py:98:32 error[invalid-argument-type] Argument to `Range1d.__init__` is incorrect: Expected `int | float | datetime | timedelta`, found `int | float | (Unknown & ~None) | str | IntrinsicType`
+ src/bokeh/plotting/_plot.py:98:45 error[invalid-argument-type] Argument to `Range1d.__init__` is incorrect: Expected `int | float | datetime | timedelta`, found `int | float | (Unknown & ~None) | str | IntrinsicType`
+ src/bokeh/plotting/_renderer.py:127:9 error[invalid-argument-type] Argument to `GlyphRenderer.__init__` is incorrect: Argument type `Glyph | None` does not satisfy upper bound `Glyph` of type variable `GlyphType`
+ src/bokeh/plotting/_renderer.py:127:9 error[invalid-argument-type] Argument to `GlyphRenderer.__init__` is incorrect: Expected `Glyph`, found `Glyph | None`
+ src/bokeh/plotting/_renderer.py:139:56 error[invalid-argument-type] Argument to function `update_legend` is incorrect: Expected `GlyphRenderer[Glyph]`, found `GlyphRenderer[GlyphType@GlyphRenderer]`
+ src/bokeh/plotting/_renderer.py:141:12 error[invalid-return-type] Return type does not match returned value: expected `GlyphRenderer[Glyph]`, found `GlyphRenderer[GlyphType@GlyphRenderer]`
discord.py (https://github.com/Rapptz/discord.py)
- discord/permissions.py:216:48 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/permissions.py:488:46 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/bot.py:294:59 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/bot.py:306:48 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/bot.py:307:107 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/bot.py:318:57 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/bot.py:330:48 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/bot.py:331:105 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/core.py:1551:48 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/core.py:1608:48 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `CooldownMapping[Context[Any]]`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `MaxConcurrency`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `bool`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `bool`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `bool`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `bool`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `bool`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `bool`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `dict[Any, Any]`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `list[(Context[Any], /) -> bool | Coroutine[Any, Any, bool]]`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `list[str] | tuple[str, ...]`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `str | None`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `str | None`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `str | None`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `str`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
+ discord/ext/commands/core.py:602:38 error[invalid-argument-type] Argument to `Command.__init__` is incorrect: Expected `str`, found `Any | list[str] | tuple[str, ...] | ... omitted 7 union elements`
- discord/ext/commands/hybrid.py:517:50 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:641:47 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:849:59 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:861:48 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:862:107 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:873:57 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:885:48 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:886:105 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:897:54 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:940:92 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:949:52 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- discord/ext/commands/hybrid.py:973:90 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
hydpy (https://github.com/hydpy-dev/hydpy)
+ hydpy/models/rconc/rconc_control.py:249:23 error[no-matching-overload] No overload of `dict.__init__` matches arguments
pandas (https://github.com/pandas-dev/pandas)
- pandas/io/parsers/readers.py:1604:41 error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `(@Todo & ~Literal[False] & ~_NoDefault) | None`
+ pandas/io/parsers/readers.py:1604:41 error[invalid-argument-type] Argument to function `len` is incorrect: Expected `Sized`, found `Hashable & ~Literal[False] & ~_NoDefault`
+ pandas/tests/io/parser/test_read_fwf.py:986:26 error[invalid-argument-type] Argument to function `read_fwf` is incorrect: Expected `Literal["pyarrow", "numpy_nullable"] | _NoDefault`, found `Literal["numpy"]`
+ pandas/tests/io/test_common.py:442:13 error[no-matching-overload] No overload of function `read_csv` matches arguments
prefect (https://github.com/PrefectHQ/prefect)
+ src/integrations/prefect-dbt/prefect_dbt/core/_orchestrator.py:1916:25 error[invalid-argument-type] Argument to `MaterializingTask.__init__` is incorrect: Expected `list[Asset | str] | None`, found `(list[Asset] & ~AlwaysFalsy) | None`
+ src/prefect/tasks.py:2218:9 error[invalid-method-override] Invalid override of method `with_options`: Definition is incompatible with `Task.with_options`
pycryptodome (https://github.com/Legrandin/pycryptodome)
+ lib/Crypto/SelfTest/Protocol/test_ecdh.py:315:53 error[invalid-argument-type] Argument to function `import_x25519_private_key` is incorrect: Expected `bytes`, found `bytes | bytearray | memoryview[int]`
+ lib/Crypto/SelfTest/Protocol/test_ecdh.py:316:51 error[invalid-argument-type] Argument to function `import_x25519_public_key` is incorrect: Expected `bytes`, found `bytes | bytearray | memoryview[int]`
+ lib/Crypto/SelfTest/Protocol/test_ecdh.py:410:51 error[invalid-argument-type] Argument to function `import_x448_private_key` is incorrect: Expected `bytes`, found `bytes | bytearray | memoryview[int]`
+ lib/Crypto/SelfTest/Protocol/test_ecdh.py:411:49 error[invalid-argument-type] Argument to function `import_x448_public_key` is incorrect: Expected `bytes`, found `bytes | bytearray | memoryview[int]`
pydantic (https://github.com/pydantic/pydantic)
- pydantic/fields.py:239:95 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pydantic/fields.py:278:57 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pydantic/fields.py:1278:39 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pydantic/fields.py:1282:47 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pydantic/fields.py:1292:47 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pydantic/fields.py:1302:53 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pydantic/fields.py:1312:57 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pydantic/fields.py:1322:39 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pydantic/fields.py:1335:40 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
- pydantic/fields.py:1350:43 warning[unused-type-ignore-comment] Unused blanket `type: ignore` directive
pyinstrument (https://github.com/joerick/pyinstrument)
- pyinstrument/context_manager.py:41:9 error[invalid-assignment] Object of type `dict[str, @Todo]` is not assignable to attribute `options` of type `ProfileContextOptions`
pywin32 (https://github.com/mhammond/pywin32)
+ com/win32comext/shell/demos/servers/folder_view.py:855:9 error[invalid-argument-type] Argument to function `UseCommandLine` is incorrect: Expected `bool`, found `Literal[0]`
+ com/win32comext/shell/demos/servers/shell_view.py:968:9 error[invalid-argument-type] Argument to function `UseCommandLine` is incorrect: Expected `bool`, found `Literal[0]`
rotki (https://github.com/rotki/rotki)
+ rotkehlchen/tests/db/test_db.py:407:20 error[no-matching-overload] No overload of bound method `DBHandler.get_dynamic_cache` matches arguments
+ rotkehlchen/tests/db/test_db.py:447:20 error[no-matching-overload] No overload of bound method `DBHandler.get_dynamic_cache` matches arguments1b9a9bd to
ffd2dca
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
| has_starred_annotation: bool, | ||
|
|
||
| /// Whether this parameter was declared as `**kwargs: Unpack[TypedDict]`. | ||
| has_unpacked_kwargs_annotation: bool, |
There was a problem hiding this comment.
This lets us distinguish **kwargs: Unpack[TD] from **kwargs: TD. The latter means that every kwarg value is itself of type TD.
There was a problem hiding this comment.
(We could also make this an enum to combine has_starred_annotation and has_unpacked_kwargs_annotation.)
| /// Per [PEP 692](https://peps.python.org/pep-0692/#typeddict-unions), unions (for example) are not | ||
| /// allowed in such annotations. |
There was a problem hiding this comment.
Slightly annoying because we already have some logic for extracting these keys in the more general case (see, e.g., extract_unpacked_typed_dict_keys_from_value_type), but PEP 692 explicitly forbids unions.
| /// The argument definitely binds this parameter. | ||
| Definitive, | ||
| /// The argument may bind this parameter at runtime, but does not guarantee its presence. | ||
| Provisional, |
There was a problem hiding this comment.
This is necessary for cases like...
class MaybeX(TypedDict, total=False):
x: str
def takes_x(*, x: int) -> None: ...
takes_x(**maybe_x)Where we need to report both missing-argument and invalid-argument-type.
|
For the ecosystem report...
Based on Codex's analysis, the rest are either true positives or things that are sufficiently dynamic that we shouldn't really expect to model them. But I'll go through a few more on my own. |
ce5fe61 to
8b766df
Compare
|
Also, note that the newly-added false positive on the conformance tests is related to |
|
|
||
| ## `Unpack[TypedDict]` in `**kwargs` | ||
|
|
||
| Using `Unpack[TypedDict]` on a `**kwargs` parameter should expose the `TypedDict` shape both inside |
There was a problem hiding this comment.
I haven't read the mdtest but could we split this test into multiple smaller snippets with some prose between snippets explaining what's being tested and what the expected behavior is?
This is one of my main learnings from maintaining Ruff. The long fixture files are a pain to maintain over time because they lack context of why something has been tested in the first place and if it's even asserting something intentionally or if they just tried to be exhaustive.
There was a problem hiding this comment.
This is awesome! Will be great to have this feature.
I reviewed the tests and some of the implementation; there are enough findings that might change enough of the implementation that I think it makes sense to do an iteration before reviewing more.
One meta-comment is that I think this is a case where the PR might have (understandably) suffered a bit of scope-creep. I think there are really two separable things addressed here. One is TypedDict unpacking on the formal-parameter side using Unpack (which is really just a matter of signature transformation, and a bit of code to infer the right type within the function body). The other is the whole Provisional matched argument thing, which is all about caller-side actual-argument unpacked TypedDict, and doesn't actually care whether the formal parameter is from an Unpack[TD] or just regular keyword arguments.
I think it would clarify the PR and the review if we separated those concerns into separate PRs.
| def func7(*, v1: int, v3: str, v2: str = "") -> None: | ||
| pass | ||
|
|
||
| # error: [invalid-assignment] | ||
| typed_dict_bad: TypedDictKwargs = func7 |
There was a problem hiding this comment.
Why do we expect invalid-assignment here? It looks to me like this assignment should succeed. func7 has the same signature that we should be treating TypedDictKwargs as having.
There was a problem hiding this comment.
Agreed; this should be accepted.
| class TD2(TD1): | ||
| v3: Required[str] | ||
|
|
||
| def func5(v1: int, **kwargs: Unpack[TD2]) -> None: # error: [invalid-type-form] |
There was a problem hiding this comment.
invalid-type-form feels weird for this one, since the type form Unpack[TD2] is just fine, what's invalid is the overall function signature. But I don't know of any better fitting code, and I don't think this is worth its own dedicated code. The non-Unpack version of this is just a syntax error, and this isn't, so that parallel doesn't help either. So I guess this really is our best option. Other type checkers also tend to use the same code for this as for the cases where the Unpack expression itself is malformed, so at least we're in good company.
| ### Regression coverage | ||
|
|
||
| These cases check a few tricky edges: unpacking non-string-keyed mappings, combining explicit | ||
| keyword arguments with unpacked `TypedDict`s, missing required keys from partial `TypedDict`s, and | ||
| legacy dunder-style keyword names. |
There was a problem hiding this comment.
Not to be a pain, but this is kind of a weird catch-all. It would be nicer to split these out into separate tests, each with their own prose...
There was a problem hiding this comment.
Also wording nit: "legacy dunder-style positional-only parameters"
| /// The key is guaranteed to be present at runtime when the mapping is unpacked. | ||
| Guaranteed, | ||
| /// The key may be present at runtime when the mapping is unpacked. | ||
| Potential, |
There was a problem hiding this comment.
Hmm... is there a good reason for us (here and in method names below) to invent new terminology that means the same thing as Required and NotRequired, which is the syntax that is actually used in defining a TypedDict key?
| from typing import Any | ||
| from typing_extensions import TypedDict, Unpack | ||
|
|
||
| class AnyKwargs(TypedDict, total=False): |
There was a problem hiding this comment.
Nit: I find this name confusing, because there is nothing Any related about this typed-dict type.
| if let Some((parameter_index, parameter, _)) = | ||
| self.parameters.unpacked_typed_dict_keyword_variadic(db) | ||
| { | ||
| let permissive_any_mapping = argument_type.is_some_and(|argument_type| { |
There was a problem hiding this comment.
Commented above on the tests -- I don't think it is correct to specially handle dict[str, Any]. All dict[str, ...] types should be forgiving in argument matching (but of course should still require that ... is assignable to each matched formal parameter, which is always true for Any).
We (and all type checkers) have the same forgiving behavior for e.g. * unpacking of list[int] -- we optimistically assume the list is the right length for the available parameters. But we still require that int be assignable to each matched parameter.
| /// Per [PEP 692](https://peps.python.org/pep-0692/#typeddict-unions), this accepts only a concrete | ||
| /// `TypedDict` target, or a type alias resolving to one. |
There was a problem hiding this comment.
I think it is always implied that stringified annotations should be supported too, but this function doesn't support them. All other type checkers support this:
from typing_extensions import TypedDict, Unpack
class TD(TypedDict):
a: int
def f(**kwargs: "Unpack[TD]") -> None:
reveal_type(kwargs) # should be TD
# should be accepted, same as an unquoted `Unpack[TD]`.
f(a=1)| } | ||
| } | ||
|
|
||
| value.push(keywords); |
There was a problem hiding this comment.
I think in order to fix some of the assignability bugs I mentioned in the tests, and remove the need for some special casing in call binding, we should eliminate this line -- the original **kwargs: Unpack[TD] parameter should not stay as part of the signature proper.
This might (not totally sure without trying it) require keeping a bit (or index?) around somewhere in the signature recording that this transformation happened, so that we can still refer to the original kwargs argument in diagnostics, detect arguments duplicated via this unpacking, etc. But I think it's important that we do that in a dedicated way that doesn't affect the signature itself, and is only used for these additional validation/diagnostic purposes.
(Keeping the **kwargs argument around in the signature is not necessary for properly inferring the type of kwargs inside the function. That goes through a totally separate Definition path that leads directly to the annotation on **kwargs, it doesn't go through a callable signature at all.)
There was a problem hiding this comment.
(The normalization is inside Parameters::new, but we now do roughly this.)
|
Great review, thank you. |
9387793 to
7bbef3b
Compare
Unpack[TypedDict]Unpack[TypedDict] in **kwargs signatures
7033e83 to
a7096ef
Compare
69559e9 to
b23d0ca
Compare
b23d0ca to
16c9d74
Compare
16c9d74 to
23def22
Compare
| if resolve_unpacked_typed_dict_kwargs_annotation_target(self.db(), inner_ty) | ||
| .is_some() | ||
| { | ||
| return inner_ty; |
There was a problem hiding this comment.
The way we recursively unwrap Unpack and pass it up as a bare type means we allow **kwargs: Unpack[Unpack[TD]] to pass silently, which we really shouldn't (and no other type checker does).
There was a problem hiding this comment.
Relatedly, it's kind of odd/unfortunate how we sort of double-handle Unpack, in that we handle it here, unwrap it, drop the information that it was wrapped in Unpack on the floor, and then later (in resolve_unpacked_typed_dict_kwargs_annotation) we have to go back to the raw AST to re-validate whether Unpack was really there after all. And that leads to the whole need for manualenter_string_annotation etc to support string annotations -- while string annotations are already naturally supported here in the inference builder.
It would be a lot nicer (and would give us a way to prevent Unpack[Unpack[...]]) if instead we could smuggle out of here the information about which expression(s) had Unpack. Options that come to mind:
- A dedicated
Type::Unpackwrapper variant. Too much churn all over the codebase, I don't think this is a good idea. - Add a way to optionally map an expression ID to some bitflags (I guess just one for now) in the type inference builder? I might be missing some details that make this one difficult, too...
There was a problem hiding this comment.
(I tried out the second.)
| diagnostic::add_type_expression_reference_link(diag); | ||
| } | ||
| return Type::unknown(); | ||
| } |
There was a problem hiding this comment.
There should be an else here where we emit an invalid-type-form for use of Unpack in any other location. (Except I guess for inside a tuple? So maybe we could leave this as a TODO until we actually implement that location too? Though it also probably wouldn't be hard to add IN_TUPLE_ANNOTATION and just carve out that exception for now.)
8e92b54 to
85a2363
Compare
da2c588 to
e8ddb60
Compare
|
I tried to implement the full range of |
* main: (44 commits) Update cargo-bins/cargo-binstall action to v1.18.1 (#24855) Update dependency ruff to v0.15.12 (#24857) Update taiki-e/install-action action to v2.75.18 (#24864) [ty] Model bool-op branch snapshots (#24458) [ty] Support `Unpack[TypedDict]` in `**kwargs` signatures (#24653) Update prek dependencies (#24858) Update Rust crate bitflags to v2.11.1 (#24859) Update Rust crate clap to v4.6.1 (#24860) Update Rust crate mimalloc to v0.1.49 (#24862) Update Rust crate uuid to v1.23.1 (#24863) Update Rust crate rayon to v1.12.0 (#24866) Update Rust crate libc to v0.2.185 (#24861) [ty] Reserve union element storage (#24849) [ty] bump conformance suite commit (#24848) [ty] Pass unmapped type variables to `SpecializationBuilder::build_with` (#24809) [ty] Avoid bookkeeping for unannotated functions (#24842) [ty] Optimize signature checking based on number of arguments (#24674) [ty] Avoid eagerly inferring legacy generic context (#24841) [ty] Skip decorator inference for undecorated functions (#24839) [ty] solve unions against generic protocols (#24837) ...
Summary
We now support
Unpack[TypedDict]as an annotation on**kwargs, as in the following example: