Reputation: 11612
I am using Python 3.6 with PyCharm and it's kind of frustrating that there's no support for code completion for special cases of dictionary objects (with fixed key schema).
Say for example I create and try to access a simple dictionary object like this:
inventory = {'name': 'hammer', 'price': 2.3}
inventory['']
When I position my cursor inside the quotes ' ' and hit Ctrl + Space
i get code completion and the IDE correctly suggests all the possible keys in the dictionary object. That's great!
But if i try to build it as a utility function that returns this same dict object, say with values that the user provide but with the same dict keys - then I don't get code completion anymore!
def get_inventory(name: str, price: float):
return {'name': name, 'price': price}
inventory = get_inventory('hammer', 2.3)
inventory[''] # <- Pycharm can't offer any suggestions!
Any workaround or solution for this? I searched already for similar solutions but I didn't find anything that works. I know I can just convert it into a class Inventory
and access the properties that way but I don't want to do it for a couple of reasons:
dict
objects are the easiest for this purposeAny help or solution for how I can get my IDE to assist in code completion by recognizing the possible keys in such a dict
object would be greatly appreciated!
Upvotes: 7
Views: 9861
Reputation: 11612
It is now mid-2023, and still no ways for PyCharm to detect dynamic dict
keys returned from a function def
exist.
However, there is a "sort" of workaround that is now possible. I realized that I forgot to mention it, so including it here.
Note that I say it's kind of a workaround, because this approach only works for static dict keys, rather than dynamic keys populated within a function scope. But hey, it's better than nothing.
dict
In Python 3.8+, this can now be achieved using TypedDict
, as shown below. Also added a __future__
import to account for annotations that could potentially be undefined at runtime, based on usage below.
from __future__ import annotations
from typing import TYPE_CHECKING, TypedDict
# To avoid creating a class at runtime, for type-hinting alone.
if TYPE_CHECKING:
# Map the `dict` fields here
class Inventory(TypedDict):
name: str
price: float
def get_inventory(name: str, price: float) -> Inventory:
return {'name': name, 'price': price}
inventory = get_inventory('hammer', 2.3)
inventory[''] # <- suggestions now work in PyCharm!
If dot or attribute access is desirable -- such as a.b.c
instead of a['b']['c']
-- then I have created a helper library dotwiz
to achieve this, as shown below:
import dotwiz
from typing import TYPE_CHECKING
# To avoid creating a class at runtime, for type-hinting alone.
if TYPE_CHECKING:
from dataclasses import dataclass
# Map the `dict` fields here
@dataclass
class Inventory:
name: str
price: float
else:
Inventory = dotwiz.DotWiz
def get_inventory(name: str, price: float) -> Inventory:
return Inventory(name=name, price=price)
inventory = get_inventory('hammer', 2.3)
print(inventory)
assert inventory.price == 2.3
inventory. # <- suggestions now work in PyCharm!
Upvotes: 2
Reputation: 7880
PyCharm has no idea what a dict
contains because its keys and values are denoted at runtime. So you have to somehow hint PyCharm about the keys of dict
beforehand. Prodict does exactly this to hint PyCharm, so you get the code completion.
class Inventory(Prodict):
name: str
price: float
def get_inventory(name: str, price: float):
return Inventory(name=name, price=price)
inventory = get_inventory('hammer', 2.3)
print(inventory.name)
print(inventory.price)
In the above code, both name
and price
attributes are auto-completed.
Since Prodict is derived directly from dict
, so you can use it as a regular dict
.
This is the screenshot from the Prodict repo that illustrates code completion:
PS: I am the author of the Prodict.
Upvotes: 5