-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Bug Report
(yes I used claude code to sum the issue up)
Summary
mypy 1.17.0 incorrectly reports type errors when using dict literals that should be compatible with Sequence[TypedDict]
fields. This worked correctly in mypy 1.16.1 and represents a regression in TypedDict structural typing.
Expected Behavior
Dict literals with the correct structure should be accepted when assigned to fields expecting Sequence[TypedDict]
, following structural typing principles that TypedDict is supposed to provide.
Actual Behavior
mypy 1.17.0 reports:
error: Incompatible types (expression has type "list[dict[str, str]]", TypedDict item "inputs" has type "Sequence[Component]") [typeddict-item]
Environment
- mypy version: 1.17.0 (fails) vs 1.16.1 (works)
- Python version: 3.11.9
- Platform: Linux
- Dependencies: None (pure
typing
module)
Minimal Reproducible Example
Save as test_regression.py
:
class Component(TypedDict):
"""Simulates ABIComponent from eth_typing"""
type: str
name: NotRequired[str]
components: NotRequired[Sequence['Component']]
class Function(TypedDict):
"""Simulates ABIFunction from eth_typing"""
type: Literal['function']
name: str
stateMutability: Literal['pure', 'view', 'nonpayable', 'payable']
inputs: NotRequired[Sequence[Component]]
outputs: NotRequired[Sequence[Component]]
# This should work according to TypedDict structural typing rules
# Works in mypy 1.16.1, fails in mypy 1.17.0
# Simple case
simple_function: Function = {
'type': 'function',
'name': 'test',
'stateMutability': 'view',
'inputs': [{'type': 'uint256', 'name': 'value'}], # Error in 1.17.0
'outputs': [{'type': 'bool'}] # Error in 1.17.0
}
# Nested case (components within components)
complex_function: Function = {
'type': 'function',
'name': 'complex',
'stateMutability': 'view',
'inputs': [
{'type': 'tuple', 'components': [ # Error in 1.17.0
{'type': 'uint256', 'name': 'amount'},
{'type': 'address', 'name': 'recipient'}
]}
]
}
# Direct assignment to Sequence should also fail
components_list: Sequence[Component] = [
{'type': 'uint256', 'name': 'value'}, # Error in 1.17.0
{'type': 'address'} # Error in 1.17.0
]
# List of functions
function_list: list[Function] = [
{
'type': 'function',
'name': 'func1',
'stateMutability': 'pure',
'inputs': [{'type': 'uint256'}] # Error in 1.17.0
}
]
Steps to Reproduce
- Save the code above as
test_regression.py
- Run with mypy 1.16.1:
mypy test_regression.py
→ ✅ Success - Run with mypy 1.17.0:
mypy test_regression.py
→ ❌ Fails
Error Output (mypy 1.17.0)
standalone_bug_test.py:43: error: Incompatible types (expression has type "list[dict[str, str]]", TypedDict item "components" has type "Sequence[Component]") [typeddict-item]
standalone_bug_test.py:62: error: Incompatible types (expression has type "list[dict[str, str]]", TypedDict item "inputs" has type "Sequence[Component]") [typeddict-item]
Analysis
This is a clear regression where mypy 1.17.0 is no longer properly recognizing dict literals as structurally compatible with TypedDict types when used in Sequence[TypedDict]
contexts. The fundamental principle of TypedDict structural typing is broken.
Root Cause
The issue appears to be in mypy's type inference logic where:
- Dict literals inside lists are inferred as
dict[str, str]
instead of the contextually expected TypedDict - This inference happens before structural compatibility is checked
- The resulting
list[dict[str, str]]
is then (correctly) rejected as incompatible withSequence[TypedDict]
Expected Fix
Dict literals should be contextually typed when the expected type is Sequence[TypedDict]
, allowing structural compatibility to work as intended.
Workarounds
- Use
# type: ignore[typeddict-item]
or# type: ignore[assignment]
comments - Use explicit
cast(list[Component], [...])
- Use explicit TypedDict construction:
Component(type='uint256', name='value')
- Downgrade to mypy 1.16.1