Closed Ravencentric closed 3 months ago
Pylance is working correctly here. It's understanding of how dict.get
behaves is based entirely on the stdlib type stubs in typeshed. The relevant overload of get
in this case is:
def get(self, key: _KT, default: _T, /) -> _VT | _T: ...
Pylance doesn't track the contents of containers and also doesn't have any special knowledge of the behavior of get
, therefore it will never make an assumption about whether the default
value will be returned based on the key name that you are retrieving. It's clear to you that the default value (an empty dictionary) will be returned, but Pylance doesn't know that.
So, the first get
call will return either the value type of the data
dictionary (int
) or the type of the default
argument (dict[Any, Any]
), therefore the return type is int | dict[Any, Any]
.
The second call to get
has two issues -- one for each of the possible types in that union:
int
doesn't have a get
method. If you enable type checking, you'll see that the second get
call is flagged with a diagnostic because of this -- Cannot access attribute "get" for class "int"
. Since int.get()
doesn't exist, the type checker treats it (and its return value) as type Any
.
get("c", {})
on a dict[Any, Any]
can return either Any
(the value type of dict[Any, Any]
) or dict[Any, Any]
(the default argument).
So the return type of this second get
call is Any | Any | dict[Any, Any]
which is simplified to just Any
. Once the type checker is dealing with an object of type Any
it can no longer do anything useful. Any method can be called on Any
, but any such method is unknown and therefore also of type Any
.
The type of dict()
is also dict[Any, Any]
, so the behavior of the other line in your example is the same.
If you want to get completion suggestions on subsequent calls to get
you'll need to convince the type checker that the object you're dealing with is a dict
. For example, you could change your code to something like this:
data = {"a": 1}
result = data.get("b", {})
if isinstance(result, dict):
result = result.get("c", {})
if isinstance(result, dict):
result. # you will see "get" as a completion suggestion here
Thank you for the detailed explanation
Environment data
v2024.7.1
Windows 11 Pro 23H2 22631.3880
3.12.3
Code Snippet
Expected behavior
Auto-complete, highlight and provide hints for
dict.get
when used in a chainActual behavior
Does not auto-complete, highlight or provide hints for
dict.get
when used in a chainLogs
Logs