FunkySayu
FunkySayu

Reputation: 8061

How to specify class or function type in docstring for PyCharm parser

I use a lot the Pycharm docstring type parser in order to specify the types of the methods parameters and return, the attributes or the instance variable. If it works nearly all the time, I have a little issue about telling PyCharm I am giving a function or a class as parameter/attribute/...

Here is a short example :

class Bar:

    def __init__(self, bar):
        """
        :type bar: str
        """
        print bar

class Foo:
    """
    :type my_class: Bar.__class__
    """

    def __init__(self, cinstance=Bar):
        """
        :type cinstance: Bar.__class__
        """
        self.my_class = cinstance

    def run(self):
        # it should print an unexpected type warning, but it doesn't.
        self.my_class(2)

If I just put Bar instead of Bar.__class__, of course PyCharm tell me that Bar cannot be call. So how to tell him that I'm giving him the class ?

Note that with the @classmethod decorator, PyCharm has no issue to understand we are speaking about the class and not the instance.

Here are my attempts :

Attempt with <code>Bar.__name__</code>

Attempt with <code>Bar.__class__</code>

Attempt with <code>Bar</code>

Upvotes: 13

Views: 12076

Answers (4)

aiven
aiven

Reputation: 4313

Try this:

from typing import Type

def __init__(self, klass: Type[Bar]):
    pass

Upvotes: 0

Mack
Mack

Reputation: 2724

For functions, specifying using callable works with PyCharm.

Upvotes: 1

FunkySayu
FunkySayu

Reputation: 8061

The PyCharm support told me the following :

As PyCharm developer said: You cannot distinguish classes and instances in type hints. The name of a class in a type hint means that an instance of that class is expected. If your function accepts the class itself, your options are either not to use type hints at all or use the 'type' as a class name. Anyway, there won't be any useful code completion in these cases. See also https://youtrack.jetbrains.com/issue/PY-11615.

The only way to specificate an argument is a class is to use :type arg: type, but the completion won't work well. There is no other way currently.

Upvotes: 4

Chris Sprague
Chris Sprague

Reputation: 740

If you want to specify that a parameter is of type SomeClass, it should be declared as such:

@type (param): SomeClass

Specified properly, you should get something like this:

part 1

If you don't specify the type of the parameter properly:

part 2

At this point, I figured I would dig a little deeper to see if I could find anything interesting. If you go to the declaration of an object's .__class__, you'll be directed here (in builtins.py):

part 3

Perhaps __class__ was set to None? Even if it is by default but then updated when the class gets instantiated (which would be my guess as to what happens), this might be what PyCharm infers __class__ resolves to. All of this is just speculation on my end and may as well be incorrect, but... Just for the heck of it, what behavior can we see if we set a parameter's type to None, then?

part 4

Looks like the same thing that happened when we set the type to SomeClass.__fake__ (and I tested it with SomeClass.__class__, and the same thing happens there too.)

So I suppose the question at hand is, why can't you use @type cinstance: Bar?

Upvotes: 1

Related Questions