bpo-37838: get_type_hints for wrapped functions with forward reference (GH-17126)
https://bugs.python.org/issue37838
This commit is contained in:
parent
82f897bf8f
commit
0aca3a3a1e
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
:meth:`typing.get_type_hints` properly handles functions decorated with :meth:`functools.wraps`.
|
Loading…
Reference in New Issue