Skip to content

Commit 9458c5c

Browse files
bpo-37838: get_type_hints for wrapped functions with forward reference (GH-17126)
https://bugs.python.org/issue37838 (cherry picked from commit 0aca3a3) Co-authored-by: benedwards14 <53377856+benedwards14@users.noreply.github.com>
1 parent 767b426 commit 9458c5c

File tree

4 files changed

+28
-1
lines changed

4 files changed

+28
-1
lines changed

Lib/test/ann_module.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
from typing import Optional
9+
from functools import wraps
910

1011
__annotations__[1] = 2
1112

@@ -51,3 +52,9 @@ def foo(x: int = 10):
5152
def bar(y: List[str]):
5253
x: str = 'yes'
5354
bar()
55+
56+
def dec(func):
57+
@wraps(func)
58+
def wrapper(*args, **kwargs):
59+
return func(*args, **kwargs)
60+
return wrapper

Lib/test/test_typing.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,6 +2778,16 @@ async def g_with(am: AsyncContextManager[int]):
27782778

27792779
gth = get_type_hints
27802780

2781+
class ForRefExample:
2782+
@ann_module.dec
2783+
def func(self: 'ForRefExample'):
2784+
pass
2785+
2786+
@ann_module.dec
2787+
@ann_module.dec
2788+
def nested(self: 'ForRefExample'):
2789+
pass
2790+
27812791

27822792
class GetTypeHintTests(BaseTestCase):
27832793
def test_get_type_hints_from_various_objects(self):
@@ -2876,6 +2886,11 @@ def test_get_type_hints_ClassVar(self):
28762886
'x': ClassVar[Optional[B]]})
28772887
self.assertEqual(gth(G), {'lst': ClassVar[List[T]]})
28782888

2889+
def test_get_type_hints_wrapped_decoratored_func(self):
2890+
expects = {'self': ForRefExample}
2891+
self.assertEqual(gth(ForRefExample.func), expects)
2892+
self.assertEqual(gth(ForRefExample.nested), expects)
2893+
28792894

28802895
class GetUtilitiesTestCase(TestCase):
28812896
def test_get_origin(self):

Lib/typing.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,11 @@ def get_type_hints(obj, globalns=None, localns=None):
12341234
if isinstance(obj, types.ModuleType):
12351235
globalns = obj.__dict__
12361236
else:
1237-
globalns = getattr(obj, '__globals__', {})
1237+
nsobj = obj
1238+
# Find globalns for the unwrapped object.
1239+
while hasattr(nsobj, '__wrapped__'):
1240+
nsobj = nsobj.__wrapped__
1241+
globalns = getattr(nsobj, '__globals__', {})
12381242
if localns is None:
12391243
localns = globalns
12401244
elif localns is None:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:meth:`typing.get_type_hints` properly handles functions decorated with :meth:`functools.wraps`.

0 commit comments

Comments
 (0)