]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-37838: get_type_hints for wrapped functions with forward reference (GH-17126)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 21 Nov 2019 17:43:13 +0000 (09:43 -0800)
committerGitHub <noreply@github.com>
Thu, 21 Nov 2019 17:43:13 +0000 (09:43 -0800)
https://bugs.python.org/issue37838
(cherry picked from commit 0aca3a3a1e68b4ca2d334ab5255dfc267719096e)

Co-authored-by: benedwards14 <53377856+benedwards14@users.noreply.github.com>
Lib/test/ann_module.py
Lib/test/test_typing.py
Lib/typing.py
Misc/NEWS.d/next/Library/2019-11-21-11-39-17.bpo-37838.lRFcEC.rst [new file with mode: 0644]

index 9e6b87dac40f5ceea34296ac69125d1aa3f31b3b..0567d6de1b6478fa2e2690abcf9ed87f4894c713 100644 (file)
@@ -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
index d8abc0ac96a108f4ad072f32e947bbc29937dd8b..087dc2a82f0386c6868dae5a9b3d293273d9d996 100644 (file)
@@ -1787,6 +1787,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):
@@ -1885,6 +1895,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 CollectionsAbcTests(BaseTestCase):
 
index ea8dea54a5a3dcba657b978e4beaf4906c3dc233..607eb1f8fc31a8e790fc19b28b0d850339c2c91d 100644 (file)
@@ -981,7 +981,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 (file)
index 0000000..96d804a
--- /dev/null
@@ -0,0 +1 @@
+:meth:`typing.get_type_hints` properly handles functions decorated with :meth:`functools.wraps`.