14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport unittest 24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom test import test_support 34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef funcattrs(**kwds): 54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def decorate(func): 64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm func.__dict__.update(kwds) 74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return func 84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return decorate 94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass MiscDecorators (object): 114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @staticmethod 124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def author(name): 134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def decorate(func): 144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm func.__dict__['author'] = name 154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return func 164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return decorate 174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# ----------------------------------------------- 194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass DbcheckError (Exception): 214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, exprstr, func, args, kwds): 224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # A real version of this would set attributes here 234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm Exception.__init__(self, "dbcheck %r failed (func=%s args=%s kwds=%s)" % 244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm (exprstr, func, args, kwds)) 254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef dbcheck(exprstr, globals=None, locals=None): 284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm "Decorator to implement debugging assertions" 294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def decorate(func): 304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm expr = compile(exprstr, "dbcheck-%s" % func.func_name, "eval") 314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def check(*args, **kwds): 324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not eval(expr, globals, locals): 334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise DbcheckError(exprstr, func, args, kwds) 344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return func(*args, **kwds) 354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return check 364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return decorate 374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# ----------------------------------------------- 394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef countcalls(counts): 414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm "Decorator to count calls to a function" 424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def decorate(func): 434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm func_name = func.func_name 444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm counts[func_name] = 0 454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def call(*args, **kwds): 464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm counts[func_name] += 1 474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return func(*args, **kwds) 484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm call.func_name = func_name 494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return call 504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return decorate 514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# ----------------------------------------------- 534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef memoize(func): 554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm saved = {} 564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def call(*args): 574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return saved[args] 594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except KeyError: 604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm res = func(*args) 614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm saved[args] = res 624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return res 634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except TypeError: 644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Unhashable argument 654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return func(*args) 664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm call.func_name = func.func_name 674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return call 684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# ----------------------------------------------- 704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass TestDecorators(unittest.TestCase): 724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_single(self): 744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm class C(object): 754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @staticmethod 764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def foo(): return 42 774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(C.foo(), 42) 784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(C().foo(), 42) 794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_staticmethod_function(self): 814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @staticmethod 824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def notamethod(x): 834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return x 844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertRaises(TypeError, notamethod, 1) 854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_dotted(self): 874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm decorators = MiscDecorators() 884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @decorators.author('Cleese') 894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def foo(): return 42 904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(foo(), 42) 914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(foo.author, 'Cleese') 924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_argforms(self): 944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # A few tests of argument passing, as we use restricted form 954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # of expressions for decorators. 964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def noteargs(*args, **kwds): 984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def decorate(func): 994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm setattr(func, 'dbval', (args, kwds)) 1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return func 1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return decorate 1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm args = ( 'Now', 'is', 'the', 'time' ) 1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm kwds = dict(one=1, two=2) 1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @noteargs(*args, **kwds) 1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def f1(): return 42 1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(f1(), 42) 1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(f1.dbval, (args, kwds)) 1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @noteargs('terry', 'gilliam', eric='idle', john='cleese') 1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def f2(): return 84 1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(f2(), 84) 1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(f2.dbval, (('terry', 'gilliam'), 1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm dict(eric='idle', john='cleese'))) 1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @noteargs(1, 2,) 1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def f3(): pass 1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(f3.dbval, ((1, 2), {})) 1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_dbcheck(self): 1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @dbcheck('args[1] is not None') 1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def f(a, b): 1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return a + b 1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(f(1, 2), 3) 1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertRaises(DbcheckError, f, 1, None) 1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_memoize(self): 1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm counts = {} 1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @memoize 1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @countcalls(counts) 1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def double(x): 1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return x * 2 1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(double.func_name, 'double') 1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(counts, dict(double=0)) 1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Only the first call with a given argument bumps the call count: 1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(double(2), 4) 1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(counts['double'], 1) 1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(double(2), 4) 1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(counts['double'], 1) 1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(double(3), 6) 1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(counts['double'], 2) 1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Unhashable arguments do not get memoized: 1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(double([10]), [10, 10]) 1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(counts['double'], 3) 1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(double([10]), [10, 10]) 1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(counts['double'], 4) 1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_errors(self): 1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Test syntax restrictions - these are all compile-time errors: 1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for expr in [ "1+2", "x[3]", "(1, 2)" ]: 1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Sanity check: is expr is a valid expression by itself? 1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm compile(expr, "testexpr", "exec") 1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm codestr = "@%s\ndef f(): pass" % expr 1624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertRaises(SyntaxError, compile, codestr, "test", "exec") 1634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # You can't put multiple decorators on a single line: 1654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 1664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertRaises(SyntaxError, compile, 1674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm "@f1 @f2\ndef f(): pass", "test", "exec") 1684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Test runtime errors 1704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def unimp(func): 1724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise NotImplementedError 1734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm context = dict(nullval=None, unimp=unimp) 1744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for expr, exc in [ ("undef", NameError), 1764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ("nullval", TypeError), 1774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ("nullval.attr", AttributeError), 1784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ("unimp", NotImplementedError)]: 1794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm codestr = "@%s\ndef f(): pass\nassert f() is None" % expr 1804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm code = compile(codestr, "test", "exec") 1814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertRaises(exc, eval, code, context) 1824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_double(self): 1844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm class C(object): 1854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @funcattrs(abc=1, xyz="haha") 1864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @funcattrs(booh=42) 1874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def foo(self): return 42 1884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(C().foo(), 42) 1894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(C.foo.abc, 1) 1904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(C.foo.xyz, "haha") 1914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(C.foo.booh, 42) 1924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_order(self): 1944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Test that decorators are applied in the proper order to the function 1954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # they are decorating. 1964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def callnum(num): 1974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Decorator factory that returns a decorator that replaces the 1984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm passed-in function with one that returns the value of 'num'""" 1994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def deco(func): 2004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return lambda: num 2014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return deco 2024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @callnum(2) 2034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @callnum(1) 2044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def foo(): return 42 2054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(foo(), 2, 2064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm "Application order of decorators is incorrect") 2074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_eval_order(self): 2094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Evaluating a decorated function involves four steps for each 2104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # decorator-maker (the function that returns a decorator): 2114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 2124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 1: Evaluate the decorator-maker name 2134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 2: Evaluate the decorator-maker arguments (if any) 2144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 3: Call the decorator-maker to make a decorator 2154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 4: Call the decorator 2164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 2174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # When there are multiple decorators, these steps should be 2184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # performed in the above order for each decorator, but we should 2194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # iterate through the decorators in the reverse of the order they 2204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # appear in the source. 2214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm actions = [] 2234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def make_decorator(tag): 2254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm actions.append('makedec' + tag) 2264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def decorate(func): 2274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm actions.append('calldec' + tag) 2284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return func 2294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return decorate 2304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm class NameLookupTracer (object): 2324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, index): 2334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.index = index 2344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __getattr__(self, fname): 2364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if fname == 'make_decorator': 2374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm opname, res = ('evalname', make_decorator) 2384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm elif fname == 'arg': 2394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm opname, res = ('evalargs', str(self.index)) 2404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 2414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm assert False, "Unknown attrname %s" % fname 2424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm actions.append('%s%d' % (opname, self.index)) 2434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return res 2444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm c1, c2, c3 = map(NameLookupTracer, [ 1, 2, 3 ]) 2464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm expected_actions = [ 'evalname1', 'evalargs1', 'makedec1', 2484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 'evalname2', 'evalargs2', 'makedec2', 2494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 'evalname3', 'evalargs3', 'makedec3', 2504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 'calldec3', 'calldec2', 'calldec1' ] 2514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm actions = [] 2534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @c1.make_decorator(c1.arg) 2544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @c2.make_decorator(c2.arg) 2554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @c3.make_decorator(c3.arg) 2564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def foo(): return 42 2574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(foo(), 42) 2584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(actions, expected_actions) 2604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Test the equivalence claim in chapter 7 of the reference manual. 2624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # 2634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm actions = [] 2644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def bar(): return 42 2654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm bar = c1.make_decorator(c1.arg)(c2.make_decorator(c2.arg)(c3.make_decorator(c3.arg)(bar))) 2664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(bar(), 42) 2674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(actions, expected_actions) 2684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass TestClassDecorators(unittest.TestCase): 2704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_simple(self): 2724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def plain(x): 2734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm x.extra = 'Hello' 2744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return x 2754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @plain 2764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm class C(object): pass 2774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(C.extra, 'Hello') 2784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_double(self): 2804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def ten(x): 2814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm x.extra = 10 2824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return x 2834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def add_five(x): 2844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm x.extra += 5 2854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return x 2864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @add_five 2884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @ten 2894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm class C(object): pass 2904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(C.extra, 15) 2914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def test_order(self): 2934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def applied_first(x): 2944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm x.extra = 'first' 2954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return x 2964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def applied_second(x): 2974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm x.extra = 'second' 2984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return x 2994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @applied_second 3004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm @applied_first 3014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm class C(object): pass 3024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.assertEqual(C.extra, 'second') 3034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_main(): 3054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm test_support.run_unittest(TestDecorators) 3064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm test_support.run_unittest(TestClassDecorators) 3074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmif __name__=="__main__": 3094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm test_main() 310