With PEP 563, from __future__ import annotations changes type annotations so that they are evaluated lazily, which provides a bunch of benefits like forward references.
However, this seems to play badly with other features, like dataclasses. For example, I have some code that inspects the type parameters of a class's __init__ method. (The real use case is to provide a default serializer for the class, but that is not important here.)
from dataclasses import dataclass
from typing import get_type_hints
class Foo:
pass
@dataclass
class Bar:
foo: Foo
print(get_type_hints(Bar.__init__))
In Python 3.6 and 3.7, this does what is expected; it prints {'foo': <class '__main__.Foo'>, 'return': <class 'NoneType'>}.
However, if in Python 3.7, I add from __future__ import annotations, then this fails with an error:
NameError: name 'Foo' is not defined
I think I understand why this is happening. The __init__ method is defined in dataclasses which does not have the Foo object in its environment, and the Foo annotation is being passed to dataclass and attached to __init__ as the string "Foo" rather than as the original object Foo, but get_type_hints for the new annotations only does a name lookup in the module where __init__ is defined not where the annotation is defined.
I feel like I must be doing something wrong. I am surprised that these two new features play so poorly together. Is there a proper way to inspect the type hints of of an __init__ method so that it works on dataclasses like it does on normal classes?