-
Notifications
You must be signed in to change notification settings - Fork 273
Open
astral-sh/ruff
#23946Milestone
Description
Summary
Given the following code:
def foo(body: object) -> str | None:
if isinstance(body, dict):
value = body.get("key") # reveal_type(body) shows `Top[dict[Unknown, Unknown]]`
if isinstance(value, str):
return value
return Nonety reports:
error[invalid-argument-type]: Argument to bound method `get` is incorrect
--> isinstance_dict_narrowing.py:3:26
|
1 | def foo(body: object) -> str | None:
2 | if isinstance(body, dict):
3 | value = body.get("key")
| ^^^^^ Expected `Never`, found `Literal["key"]`
4 | if isinstance(value, str):
5 | return value
|
info: Matching overload defined here
--> stdlib/builtins.pyi:3015:9
|
3013 | # Positional-only in dict, but not in MutableMapping
3014 | @overload # type: ignore[override]
3015 | def get(self, key: _KT, default: None = None, /) -> _VT | None:
| ^^^ -------- Parameter declared here
3016 | """Return the value for key if key is in the dictionary, else default."""
|
info: Non-matching overloads for bound method `get`:
info: (self, key: _KT@dict, default: _VT@dict, /) -> _VT@dict
info: (self, key: _KT@dict, default: _T@get, /) -> _VT@dict | _T@get
info: rule `invalid-argument-type` is enabled by default
After reading #456 and its implementation astral-sh/ruff#20256, this seems to be working as designed? Top materialization means we can't call the .get method here since there is no type for the key would satisfy all possible dicts of any key type, thus the Never type. The ecosystem analysis result on astral-sh/ruff#20256 also shows a few examples like the theme_config variable here.
However, I couldn't wrap my head around this behavior. Is there a good or pedantic example that ty is catching real errors? And at least, could we add better diagnostics or documentation?
(I also found the relevant open issue #1130, but it's talking specifically about TypedDict.)
Version
ty 0.0.9 (f1652f0 2026-01-05)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels