From add33601c2826a151718da295b15fbb8cf656e53 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sun, 15 Aug 2004 07:21:25 +0000 Subject: [PATCH] Correct the order of application for decorators. Meant to be bottom-up and not top-down. Now matches the PEP. --- Lib/test/test_decorators.py | 23 ++++++++++++++++------- Misc/NEWS | 3 +++ Python/compile.c | 5 ++++- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_decorators.py b/Lib/test/test_decorators.py index dbe45cf3fd3..8010ea37f3d 100644 --- a/Lib/test/test_decorators.py +++ b/Lib/test/test_decorators.py @@ -129,7 +129,8 @@ class TestDecorators(unittest.TestCase): # XXX: This doesn't work unless memoize is the last decorator - # see the comment in countcalls. counts = {} - @countcalls(counts) @memoize + @memoize + @countcalls(counts) def double(x): return x * 2 @@ -186,12 +187,20 @@ class TestDecorators(unittest.TestCase): self.assertEqual(C.foo.booh, 42) def test_order(self): - class C(object): - @funcattrs(abc=1) @staticmethod - def foo(): return 42 - # This wouldn't work if staticmethod was called first - self.assertEqual(C.foo(), 42) - self.assertEqual(C().foo(), 42) + # Test that decorators are conceptually applied right-recursively; + # that means bottom-up + def ordercheck(num): + def deco(func): + return lambda: num + return deco + + # Should go ordercheck(1)(ordercheck(2)(blah)) which should lead to + # blah() == 1 + @ordercheck(1) + @ordercheck(2) + def blah(): pass + self.assertEqual(blah(), 1, "decorators are meant to be applied " + "bottom-up") def test_main(): test_support.run_unittest(TestDecorators) diff --git a/Misc/NEWS b/Misc/NEWS index 43e7553dcf7..e564c2b6937 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 2.4 alpha 3? Core and builtins ----------------- +- Fix the order of application of decorators. The proper order is bottom-up; + the first decorator listed is the last one called. + - SF patch #1005778. Fix a seg fault if the list size changed while calling list.index(). This could happen if a rich comparison function modified the list. diff --git a/Python/compile.c b/Python/compile.c index de295365284..79620c209fe 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4132,7 +4132,10 @@ com_decorators(struct compiling *c, node *n) REQ(CHILD(n, nch - 1), NEWLINE); ndecorators = 0; - for (i = NCH(n) - 1; i >= 0; --i) { + /* the application order for decorators is the reverse of how they are + listed; bottom-up */ + nch -= 1; + for (i = 0; i < nch; i+=1) { node *ch = CHILD(n, i); if (TYPE(ch) != NEWLINE) { com_decorator(c, ch);