diff --git a/Lib/test/ann_module.py b/Lib/test/ann_module.py index 9e6b87dac40..0567d6de1b6 100644 --- a/Lib/test/ann_module.py +++ b/Lib/test/ann_module.py @@ -6,6 +6,7 @@ Empty lines above are for good reason (testing for correct line numbers) """ from typing import Optional +from functools import wraps __annotations__[1] = 2 @@ -51,3 +52,9 @@ def foo(x: int = 10): def bar(y: List[str]): x: str = 'yes' bar() + +def dec(func): + @wraps(func) + def wrapper(*args, **kwargs): + return func(*args, **kwargs) + return wrapper diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 49417efe511..ccd617c1fdf 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2778,6 +2778,16 @@ except StopIteration as e: 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): def test_get_type_hints_from_various_objects(self): @@ -2876,6 +2886,11 @@ class GetTypeHintTests(BaseTestCase): 'x': ClassVar[Optional[B]]}) 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): def test_get_origin(self): diff --git a/Lib/typing.py b/Lib/typing.py index 27be37a369a..5523ee01e1f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1234,7 +1234,11 @@ def get_type_hints(obj, globalns=None, localns=None): if isinstance(obj, types.ModuleType): globalns = obj.__dict__ 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: localns = globalns elif localns is None: diff --git a/Misc/NEWS.d/next/Library/2019-11-21-11-39-17.bpo-37838.lRFcEC.rst b/Misc/NEWS.d/next/Library/2019-11-21-11-39-17.bpo-37838.lRFcEC.rst new file mode 100644 index 00000000000..96d804addeb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-11-21-11-39-17.bpo-37838.lRFcEC.rst @@ -0,0 +1 @@ +:meth:`typing.get_type_hints` properly handles functions decorated with :meth:`functools.wraps`.