(self)
| 231 | "Application order of decorators is incorrect") |
| 232 | |
| 233 | def test_eval_order(self): |
| 234 | # Evaluating a decorated function involves four steps for each |
| 235 | # decorator-maker (the function that returns a decorator): |
| 236 | # |
| 237 | # 1: Evaluate the decorator-maker name |
| 238 | # 2: Evaluate the decorator-maker arguments (if any) |
| 239 | # 3: Call the decorator-maker to make a decorator |
| 240 | # 4: Call the decorator |
| 241 | # |
| 242 | # When there are multiple decorators, these steps should be |
| 243 | # performed in the above order for each decorator, but we should |
| 244 | # iterate through the decorators in the reverse of the order they |
| 245 | # appear in the source. |
| 246 | |
| 247 | actions = [] |
| 248 | |
| 249 | def make_decorator(tag): |
| 250 | actions.append('makedec' + tag) |
| 251 | def decorate(func): |
| 252 | actions.append('calldec' + tag) |
| 253 | return func |
| 254 | return decorate |
| 255 | |
| 256 | class NameLookupTracer (object): |
| 257 | def __init__(self, index): |
| 258 | self.index = index |
| 259 | |
| 260 | def __getattr__(self, fname): |
| 261 | if fname == 'make_decorator': |
| 262 | opname, res = ('evalname', make_decorator) |
| 263 | elif fname == 'arg': |
| 264 | opname, res = ('evalargs', str(self.index)) |
| 265 | else: |
| 266 | assert False, "Unknown attrname %s" % fname |
| 267 | actions.append('%s%d' % (opname, self.index)) |
| 268 | return res |
| 269 | |
| 270 | c1, c2, c3 = map(NameLookupTracer, [ 1, 2, 3 ]) |
| 271 | |
| 272 | expected_actions = [ 'evalname1', 'evalargs1', 'makedec1', |
| 273 | 'evalname2', 'evalargs2', 'makedec2', |
| 274 | 'evalname3', 'evalargs3', 'makedec3', |
| 275 | 'calldec3', 'calldec2', 'calldec1' ] |
| 276 | |
| 277 | actions = [] |
| 278 | @c1.make_decorator(c1.arg) |
| 279 | @c2.make_decorator(c2.arg) |
| 280 | @c3.make_decorator(c3.arg) |
| 281 | def foo(): return 42 |
| 282 | self.assertEqual(foo(), 42) |
| 283 | |
| 284 | self.assertEqual(actions, expected_actions) |
| 285 | |
| 286 | # Test the equivalence claim in chapter 7 of the reference manual. |
| 287 | # |
| 288 | actions = [] |
| 289 | def bar(): return 42 |
| 290 | bar = c1.make_decorator(c1.arg)(c2.make_decorator(c2.arg)(c3.make_decorator(c3.arg)(bar))) |
nothing calls this directly
no test coverage detected