Skip to content

[ty] Support place narrowing for dictionaries contained within list/tuple literals#23569

Merged
ibraheemdev merged 2 commits intomainfrom
ibraheem/narrow-dict-in-list
Mar 6, 2026
Merged

[ty] Support place narrowing for dictionaries contained within list/tuple literals#23569
ibraheemdev merged 2 commits intomainfrom
ibraheem/narrow-dict-in-list

Conversation

@ibraheemdev
Copy link
Member

Resolves astral-sh/ty#2894 by traversing list (or tuple) literals that may contain nested dictionary literals.

@ibraheemdev ibraheemdev added the ty Multi-file analysis & type inference label Feb 25, 2026
@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 25, 2026

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 87.07%. The percentage of expected errors that received a diagnostic held steady at 77.62%.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 25, 2026

mypy_primer results

Changes were detected when running on open source projects
pydantic (https://github.com/pydantic/pydantic)
- pydantic/_internal/_core_metadata.py:87:54: error[invalid-assignment] Invalid assignment to key "pydantic_js_extra" with declared type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | ((dict[str, Divergent], type[Any], /) -> None)` on TypedDict `CoreMetadata`: value of type `dict[object, object]`
+ pydantic/_internal/_core_metadata.py:87:54: error[invalid-assignment] Invalid assignment to key "pydantic_js_extra" with declared type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | ((dict[str, int | float | str | ... omitted 3 union elements], type[Any], /) -> None)` on TypedDict `CoreMetadata`: value of type `dict[object, object]`
- pydantic/fields.py:949:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:949:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:989:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:989:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1032:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1032:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1072:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1072:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1115:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1115:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1154:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1154:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1194:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
+ pydantic/fields.py:1194:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
- pydantic/fields.py:1573:13: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`, found `dict[str, Divergent] | dict[Never, Never] | (((dict[str, Divergent], /) -> None) & ~Top[dict[Unknown, Unknown]]) | None`
+ pydantic/fields.py:1573:13: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`, found `dict[str, int | float | str | ... omitted 3 union elements] | dict[Never, Never] | (((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) & ~Top[dict[Unknown, Unknown]]) | None`

apprise (https://github.com/caronc/apprise)
- apprise/plugins/line.py:174:13: error[invalid-assignment] Cannot assign to a subscript on an object of type `str`
- apprise/plugins/slack.py:504:17: error[unresolved-attribute] Attribute `insert` is not defined on `str`, `int`, `tuple[int, int, int]` in union `list[dict[str, str | dict[str, str | Unknown]]] | str | int | tuple[int, int, int]`
- apprise/plugins/slack.py:544:17: error[unresolved-attribute] Attribute `append` is not defined on `str`, `int`, `tuple[int, int, int]` in union `list[dict[str, str | dict[str, str | Unknown]]] | str | int | tuple[int, int, int]`
- Found 3578 diagnostics
+ Found 3575 diagnostics

freqtrade (https://github.com/freqtrade/freqtrade)
- freqtrade/rpc/discord.py:57:21: error[unresolved-attribute] Attribute `append` is not defined on `str`, `int` in union `Unknown | str | int | list[Unknown]`
- Found 668 diagnostics
+ Found 667 diagnostics

materialize (https://github.com/MaterializeInc/materialize)
- misc/python/materialize/cli/orchestratord.py:312:9: error[invalid-assignment] Cannot assign to a subscript on an object of type `str`
- Found 548 diagnostics
+ Found 547 diagnostics

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 25, 2026

Memory usage report

Summary

Project Old New Diff Outcome
prefect 693.42MB 694.19MB +0.11% (782.92kB)
sphinx 265.38MB 265.38MB +0.00% (7.24kB)
flake8 47.91MB 47.91MB -
trio 118.04MB 118.04MB -

Significant changes

Click to expand detailed breakdown

prefect

Name Old New Diff Outcome
semantic_index 169.80MB 170.39MB +0.34% (597.64kB)
Definition 21.63MB 21.81MB +0.84% (184.97kB)
infer_expression_types_impl 59.59MB 59.59MB -0.00% (360.00B)
is_redundant_with_impl::interned_arguments 5.36MB 5.36MB +0.01% (352.00B)
all_narrowing_constraints_for_expression 6.92MB 6.92MB +0.00% (236.00B)
is_redundant_with_impl 5.54MB 5.54MB +0.00% (192.00B)
infer_definition_types 87.33MB 87.33MB -0.00% (188.00B)
infer_expression_type_impl 14.26MB 14.26MB -0.00% (172.00B)
UnionType 3.51MB 3.51MB +0.00% (144.00B)
StaticClassLiteral<'db>::implicit_attribute_inner_ 9.72MB 9.72MB +0.00% (120.00B)
UnionType<'db>::from_two_elements_ 5.14MB 5.14MB -0.00% (12.00B)
Type<'db>::member_lookup_with_policy_ 15.26MB 15.26MB +0.00% (12.00B)
all_negative_narrowing_constraints_for_expression 2.58MB 2.58MB -0.00% (8.00B)

sphinx

Name Old New Diff Outcome
semantic_index 62.49MB 62.50MB +0.01% (5.37kB)
Definition 8.87MB 8.87MB +0.02% (1.88kB)

@astral-sh-bot
Copy link

astral-sh-bot bot commented Feb 25, 2026

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-await 0 40 0
unresolved-attribute 0 3 0
invalid-assignment 0 2 0
invalid-return-type 0 1 0
Total 0 46 0

Full report with detailed diff (timing results)

Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

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

Very cool! I was worried this would be too expensive, but I guess list literals containing dict literals aren't that common, so it's not really an issue.

@carljm carljm assigned carljm and unassigned oconnor663 Feb 25, 2026
@ibraheemdev ibraheemdev force-pushed the ibraheem/narrow-dict-in-list branch from 6bb9de9 to 921375c Compare March 6, 2026 05:56
@ibraheemdev ibraheemdev merged commit 6920ea9 into main Mar 6, 2026
49 of 50 checks passed
@ibraheemdev ibraheemdev deleted the ibraheem/narrow-dict-in-list branch March 6, 2026 06:04
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.

Confusing error when accessing a deeply nested field in dict with mixed types

3 participants