Can I use __qualname__ in a Python type hint with postponed annotation evaluation?

language-lawyer, python

Solution

`Foo.make` doesn't always return an instance of `Foo` (which is what `__qualname__` expands to). It returns an instance of the class it receives as an argument, which isn't necessarily `Foo`. Consider:

>>> class Foo:
...     @classmethod
...     def make(cls):
...         return cls()
...
>>> class Bar(Foo):
...     pass
...
>>> type(Bar.make())
<class '__main__.Bar'>

The correct type hint would be a type variable:

T = TypeVar("T", bound="Foo")

class Foo:
    @classmethod
    def make(cls: Type[T]) -> T:
        return cls()

Problem

I like using `__qualname__` for the return-type annotation of factory-style class methods, because it doesn't hardcode the classname and therefore keeps working subclasses (cf. this answer). ``` class Foo: @classmethod def make(cls) -> __qualname__: return cls() ``` Currently this seems to work fine, but I am not sure whether this will still be possible with the postponed evaluation of annotations (PEP 563): the PEP says that Annotations can only use names present in the module scope as postponed evaluation using local names is not reliable (with the sole exception of class-level names resolved by `typing.get_type_hints()`). The PEP also says: The `get_type_hints()` function automatically resolves the correct value of `globalns` for functions and classes. It also automatically provides the correct `localns` for classes. However, the following code ``` from __future__ import annotations import typing class Foo(): @classmethod def make(cls) -> __qualname__: return cls() print(typing.get_type_hints(Foo.make)) ``` fails with ``` File "qualname_test.py", line 11, in <module> print(typing.get_type_hints(Foo.make)) File "/var/local/conda/envs/py37/lib/python3.7/typing.py", line 1004, in get_type_hints value = _eval_type(value, globalns, localns) File "/var/local/conda/envs/py37/lib/python3.7/typing.py", line 263, in _eval_type return t._evaluate(globalns, localns) File "/var/local/conda/envs/py37/lib/python3.7/typing.py", line 467, in _evaluate eval(self.__forward_code__, globalns, localns), File "<string>", line 1, in <module> NameError: name '__qualname__' is not defined ``` Commenting the `__future__` import makes the code work again, in that case it outputs ``` {'return': <class '__main__.Foo'>} ``` as expected. Is my use case `__qualname__` supported (which would mean that `get_type_hints` is buggy), or is this approach not possible with PEP 563?

Original source

Related problems