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