Close #13266: Add inspect.unwrap

Initial patch by Daniel Urban and Aaron Iles
This commit is contained in:
Nick Coghlan 2013-07-28 20:00:01 +10:00
parent 77578204d6
commit e8c45d6d0e
5 changed files with 141 additions and 11 deletions

View file

@ -8,6 +8,7 @@ import datetime
import collections
import os
import shutil
import functools
from os.path import normcase
from test.support import run_unittest, TESTFN, DirsOnSysPath
@ -1719,6 +1720,17 @@ class TestSignatureObject(unittest.TestCase):
((('b', ..., ..., "positional_or_keyword"),),
...))
# Test we handle __signature__ partway down the wrapper stack
def wrapped_foo_call():
pass
wrapped_foo_call.__wrapped__ = Foo.__call__
self.assertEqual(self.signature(wrapped_foo_call),
((('a', ..., ..., "positional_or_keyword"),
('b', ..., ..., "positional_or_keyword")),
...))
def test_signature_on_class(self):
class C:
def __init__(self, a):
@ -1833,6 +1845,10 @@ class TestSignatureObject(unittest.TestCase):
self.assertEqual(self.signature(Wrapped),
((('a', ..., ..., "positional_or_keyword"),),
...))
# wrapper loop:
Wrapped.__wrapped__ = Wrapped
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
self.signature(Wrapped)
def test_signature_on_lambdas(self):
self.assertEqual(self.signature((lambda a=10: a)),
@ -2284,6 +2300,62 @@ class TestBoundArguments(unittest.TestCase):
self.assertNotEqual(ba, ba4)
class TestUnwrap(unittest.TestCase):
def test_unwrap_one(self):
def func(a, b):
return a + b
wrapper = functools.lru_cache(maxsize=20)(func)
self.assertIs(inspect.unwrap(wrapper), func)
def test_unwrap_several(self):
def func(a, b):
return a + b
wrapper = func
for __ in range(10):
@functools.wraps(wrapper)
def wrapper():
pass
self.assertIsNot(wrapper.__wrapped__, func)
self.assertIs(inspect.unwrap(wrapper), func)
def test_stop(self):
def func1(a, b):
return a + b
@functools.wraps(func1)
def func2():
pass
@functools.wraps(func2)
def wrapper():
pass
func2.stop_here = 1
unwrapped = inspect.unwrap(wrapper,
stop=(lambda f: hasattr(f, "stop_here")))
self.assertIs(unwrapped, func2)
def test_cycle(self):
def func1(): pass
func1.__wrapped__ = func1
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
inspect.unwrap(func1)
def func2(): pass
func2.__wrapped__ = func1
func1.__wrapped__ = func2
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
inspect.unwrap(func1)
with self.assertRaisesRegex(ValueError, 'wrapper loop'):
inspect.unwrap(func2)
def test_unhashable(self):
def func(): pass
func.__wrapped__ = None
class C:
__hash__ = None
__wrapped__ = func
self.assertIsNone(inspect.unwrap(C()))
def test_main():
run_unittest(
TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
@ -2291,7 +2363,7 @@ def test_main():
TestGetcallargsFunctions, TestGetcallargsMethods,
TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState,
TestNoEOL, TestSignatureObject, TestSignatureBind, TestParameterObject,
TestBoundArguments, TestGetClosureVars
TestBoundArguments, TestGetClosureVars, TestUnwrap
)
if __name__ == "__main__":