Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python rtype docstring/restructured text for class factories/selectors

:rtype: specifies that this is the type of the returned object.

Therefore, when I create the object obj in the following snippet I receive a warning from the IDE that cls is not callable, since the IDE expects that cls is object of type SomeAbstractClass, and I want SomeAbstractClass itself.

The IDE is right, since this is the default behaviour. But how can I specify that I am returning a class, not an instance of a class?

Specifying type instead of SomeAbstractClass helps a bit, but that's not a solution, since no further introspection is available.

def class_selector(data):
    """
    :rtype: SomeAbstractClass
    :return: Return some class based on given parameters
    """
    
    return get_from.get(data.name)
cls = class_selector(data)
obj = cls(data.more_data)

Meanwhile I have solved this by adding """:type: SomeAbstractClass""" after object creating, but this does not cancel the warning and it's a dirty solution.

By the way, I am talking about Python 2.x.

like image 723
Tigra Avatar asked Mar 23 '14 16:03

Tigra


1 Answers

As for 2020, the only solution that is working properly - using python3 annotations:

Which in general is totally acceptable for 2020

Attaching a screenshot to demonstrate the correct behavior. Basically, def factory(name) -> type[SomeAbstractClass]: or def factory(name) -> "type[SomeAbstractClass]": (for cases when can't import the name) works totally fine.

Still could not come up with a solution for older Python versions (i.e avoiding the use of annotations). But it's not a deal-breaker in 2020

correct_behaviour

And same code as text, if anyone wants to copy-paste to test alternative approaches

class SomeAbstractClass:
    property_by_class = 1
    def __init__(self):
        self.property_by_object = 1


def factory(name) -> type[SomeAbstractClass]:
    hide_it = dict()
    class ActualClassImpl(SomeAbstractClass):
        pass
    hide_it.__setitem__(name, ActualClassImpl)
    return hide_it.__getitem__(name)

if __name__ == '__main__':
    a = factory('testclass')
    by_class_should_be_ok = a.property_by_class
    by_object_should_hint_error = a.property_by_object
    just_like_none_existing_property_hints = a.property_by_object_bad


like image 72
Tigra Avatar answered Sep 29 '22 09:09

Tigra