bpo-37838: get_type_hints for wrapped functions with forward reference (GH-17126)

https://bugs.python.org/issue37838
This commit is contained in:
benedwards14 2019-11-21 17:24:58 +00:00 committed by Ivan Levkivskyi
parent 82f897bf8f
commit 0aca3a3a1e
4 changed files with 28 additions and 1 deletions

View File

@ -6,6 +6,7 @@ Empty lines above are for good reason (testing for correct line numbers)
""" """
from typing import Optional from typing import Optional
from functools import wraps
__annotations__[1] = 2 __annotations__[1] = 2
@ -51,3 +52,9 @@ def foo(x: int = 10):
def bar(y: List[str]): def bar(y: List[str]):
x: str = 'yes' x: str = 'yes'
bar() bar()
def dec(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper

View File

@ -2778,6 +2778,16 @@ except StopIteration as e:
gth = get_type_hints gth = get_type_hints
class ForRefExample:
@ann_module.dec
def func(self: 'ForRefExample'):
pass
@ann_module.dec
@ann_module.dec
def nested(self: 'ForRefExample'):
pass
class GetTypeHintTests(BaseTestCase): class GetTypeHintTests(BaseTestCase):
def test_get_type_hints_from_various_objects(self): def test_get_type_hints_from_various_objects(self):
@ -2876,6 +2886,11 @@ class GetTypeHintTests(BaseTestCase):
'x': ClassVar[Optional[B]]}) 'x': ClassVar[Optional[B]]})
self.assertEqual(gth(G), {'lst': ClassVar[List[T]]}) self.assertEqual(gth(G), {'lst': ClassVar[List[T]]})
def test_get_type_hints_wrapped_decoratored_func(self):
expects = {'self': ForRefExample}
self.assertEqual(gth(ForRefExample.func), expects)
self.assertEqual(gth(ForRefExample.nested), expects)
class GetUtilitiesTestCase(TestCase): class GetUtilitiesTestCase(TestCase):
def test_get_origin(self): def test_get_origin(self):

View File

@ -1234,7 +1234,11 @@ def get_type_hints(obj, globalns=None, localns=None):
if isinstance(obj, types.ModuleType): if isinstance(obj, types.ModuleType):
globalns = obj.__dict__ globalns = obj.__dict__
else: else:
globalns = getattr(obj, '__globals__', {}) nsobj = obj
# Find globalns for the unwrapped object.
while hasattr(nsobj, '__wrapped__'):
nsobj = nsobj.__wrapped__
globalns = getattr(nsobj, '__globals__', {})
if localns is None: if localns is None:
localns = globalns localns = globalns
elif localns is None: elif localns is None:

View File

@ -0,0 +1 @@
:meth:`typing.get_type_hints` properly handles functions decorated with :meth:`functools.wraps`.