bpo-37838: get_type_hints for wrapped functions with forward referenc… · python/cpython@30e5bd8 (original) (raw)

4 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
6 6 """
7 7
8 8 from typing import Optional
9 +from functools import wraps
9 10
10 11 __annotations__[1] = 2
11 12
@@ -51,3 +52,9 @@ def foo(x: int = 10):
51 52 def bar(y: List[str]):
52 53 x: str = 'yes'
53 54 bar()
55 +
56 +def dec(func):
57 +@wraps(func)
58 +def wrapper(*args, **kwargs):
59 +return func(*args, **kwargs)
60 +return wrapper
Original file line number Diff line number Diff line change
@@ -1787,6 +1787,16 @@ async def g_with(am: AsyncContextManager[int]):
1787 1787
1788 1788 gth = get_type_hints
1789 1789
1790 +class ForRefExample:
1791 +@ann_module.dec
1792 +def func(self: 'ForRefExample'):
1793 +pass
1794 +
1795 +@ann_module.dec
1796 +@ann_module.dec
1797 +def nested(self: 'ForRefExample'):
1798 +pass
1799 +
1790 1800
1791 1801 class GetTypeHintTests(BaseTestCase):
1792 1802 def test_get_type_hints_from_various_objects(self):
@@ -1885,6 +1895,11 @@ def test_get_type_hints_ClassVar(self):
1885 1895 'x': ClassVar[Optional[B]]})
1886 1896 self.assertEqual(gth(G), {'lst': ClassVar[List[T]]})
1887 1897
1898 +def test_get_type_hints_wrapped_decoratored_func(self):
1899 +expects = {'self': ForRefExample}
1900 +self.assertEqual(gth(ForRefExample.func), expects)
1901 +self.assertEqual(gth(ForRefExample.nested), expects)
1902 +
1888 1903
1889 1904 class CollectionsAbcTests(BaseTestCase):
1890 1905
Original file line number Diff line number Diff line change
@@ -981,7 +981,11 @@ def get_type_hints(obj, globalns=None, localns=None):
981 981 if isinstance(obj, types.ModuleType):
982 982 globalns = obj.__dict__
983 983 else:
984 -globalns = getattr(obj, '__globals__', {})
984 +nsobj = obj
985 +# Find globalns for the unwrapped object.
986 +while hasattr(nsobj, '__wrapped__'):
987 +nsobj = nsobj.__wrapped__
988 +globalns = getattr(nsobj, '__globals__', {})
985 989 if localns is None:
986 990 localns = globalns
987 991 elif localns is None:
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1 +:meth:`typing.get_type_hints` properly handles functions decorated with :meth:`functools.wraps`.