Wizard.Ritvik
Wizard.Ritvik

Reputation: 11612

How to enable code completion for a dictionary from method in Python?

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:

Any 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

Answers (2)

Wizard.Ritvik
Wizard.Ritvik

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.

Using builtin 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!

Dot-Access Dict - w/ fast performance

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

ramazan polat
ramazan polat

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:

Prodict code completion

PS: I am the author of the Prodict.

Upvotes: 5

Related Questions