Ticket #113: ticket113.2.diff
| File ticket113.2.diff, 10.1 KB (added by cmlenz, 16 years ago) |
|---|
-
genshi/template/tests/eval.py
379 379 expr.evaluate({'something': Something()}) 380 380 self.fail('Expected UndefinedError') 381 381 except UndefinedError, e: 382 self.assertEqual('<Something> has no member named "nil"', str(e)) 382 383 exc_type, exc_value, exc_traceback = sys.exc_info() 384 search_string = "<Expression 'something.nil'>" 383 385 frame = exc_traceback.tb_next 384 frames = []385 386 while frame.tb_next: 386 387 frame = frame.tb_next 387 frames.append(frame)388 self.assertEqual('<Something> has no member named "nil"', str(e))389 self.assertEqual("<Expression 'something.nil'>",390 frames[-3].tb_frame.f_code.co_name)391 self.assertEqual('index.html',392 frames[-3].tb_frame.f_code.co_filename)393 self.assertEqual(50, frame s[-3].tb_lineno)388 code = frame.tb_frame.f_code 389 if code.co_name == search_string: 390 break 391 else: 392 self.fail("never found the frame I was looking for") 393 self.assertEqual('index.html', code.co_filename) 394 self.assertEqual(50, frame.tb_lineno) 394 395 395 396 def test_error_getitem_undefined_string(self): 396 397 class Something(object): … … 402 403 expr.evaluate({'something': Something()}) 403 404 self.fail('Expected UndefinedError') 404 405 except UndefinedError, e: 406 self.assertEqual('<Something> has no member named "nil"', str(e)) 405 407 exc_type, exc_value, exc_traceback = sys.exc_info() 408 search_string = '''<Expression 'something["nil"]'>''' 406 409 frame = exc_traceback.tb_next 407 frames = []408 410 while frame.tb_next: 409 411 frame = frame.tb_next 410 frames.append(frame)411 self.assertEqual('<Something> has no member named "nil"', str(e))412 self.assertEqual('''<Expression 'something["nil"]'>''',413 frames[-3].tb_frame.f_code.co_name)414 self.assertEqual('index.html',415 frames[-3].tb_frame.f_code.co_filename)416 self.assertEqual(50, frame s[-3].tb_lineno)412 code = frame.tb_frame.f_code 413 if code.co_name == search_string: 414 break 415 else: 416 self.fail("never found the frame I was looking for") 417 self.assertEqual('index.html', code.co_filename) 418 self.assertEqual(50, frame.tb_lineno) 417 419 418 420 419 421 class SuiteTestCase(unittest.TestCase): … … 431 433 assert 'donothing' in data 432 434 self.assertEqual(None, data['donothing']()) 433 435 436 def test_def_with_multiple_statements(self): 437 suite = Suite("""def donothing(): 438 if True: 439 return foo 440 """) 441 data = {'foo': 'bar'} 442 suite.execute(data) 443 assert 'donothing' in data 444 self.assertEqual('bar', data['donothing']()) 445 434 446 def test_delete(self): 435 447 suite = Suite("""foo = 42 436 448 del foo … … 504 516 suite.execute(data) 505 517 self.assertEqual(4, data['x']) 506 518 519 def test_augmented_attribute_assignment(self): 520 suite = Suite("d['k'] += 42") 521 d = {"k": 1} 522 suite.execute({"d": d}) 523 self.assertEqual(43, d["k"]) 507 524 525 def test_local_augmented_assign(self): 526 Suite("x = 1; x += 42; assert x == 43").execute({}) 527 528 def test_assign_in_list(self): 529 suite = Suite("[d['k']] = 'foo',; assert d['k'] == 'foo'") 530 d = {"k": "bar"} 531 suite.execute({"d": d}) 532 self.assertEqual("foo", d["k"]) 533 534 def test_exec(self): 535 suite = Suite("x = 1; exec d['k']; assert x == 42, x") 536 suite.execute({"d": {"k": "x = 42"}}) 537 538 def test_return(self): 539 suite = Suite(""" 540 def f(): 541 return v 542 543 assert f() == 42 544 """) 545 suite.execute({"v": 42}) 546 547 def test_assign_to_dict_item(self): 548 suite = Suite("d['k'] = 'foo'") 549 data = {'d': {}} 550 suite.execute(data) 551 self.assertEqual('foo', data['d']['k']) 552 553 def test_assign_to_attribute(self): 554 class Something(object): pass 555 something = Something() 556 suite = Suite("obj.attr = 'foo'") 557 data = {"obj": something} 558 suite.execute(data) 559 self.assertEqual('foo', something.attr) 560 561 def test_delattr(self): 562 class Something(object): 563 def __init__(self): 564 self.attr = 'foo' 565 obj = Something() 566 Suite("del obj.attr").execute({'obj': obj}) 567 self.failIf(hasattr(obj, 'attr')) 568 569 def test_delitem(self): 570 d = {'k': 'foo'} 571 Suite("del d['k']").execute({'d': d}) 572 self.failIf('k' in d, `d`) 573 574 508 575 def suite(): 509 576 suite = unittest.TestSuite() 510 577 suite.addTest(doctest.DocTestSuite(Expression.__module__)) -
genshi/template/eval.py
140 140 """Executes Python statements used in templates. 141 141 142 142 >>> data = dict(test='Foo', items=[1, 2, 3], dict={'some': 'thing'}) 143 >>> Suite( 'foo = dict.some').execute(data)143 >>> Suite("foo = dict['some']").execute(data) 144 144 >>> data['foo'] 145 145 'thing' 146 146 """ … … 361 361 return parse(source, mode) 362 362 363 363 def _compile(node, source=None, mode='eval', filename=None, lineno=-1): 364 tree = TemplateASTTransformer().visit(node) 364 xform = {'eval': ExpressionASTTransformer}.get(mode, TemplateASTTransformer) 365 tree = xform().visit(node) 365 366 if isinstance(filename, unicode): 366 367 # unicode file names not allowed for code objects 367 368 filename = filename.encode('utf-8', 'replace') … … 397 398 Every visitor method can be overridden to return an AST node that has been 398 399 altered or replaced in some way. 399 400 """ 400 _visitors = {}401 401 402 402 def visit(self, node): 403 403 if node is None: 404 404 return None 405 v = self._visitors.get(node.__class__) 406 if not v: 407 v = getattr(self.__class__, 'visit%s' % node.__class__.__name__, 408 self.__class__._visitDefault) 409 self._visitors[node.__class__] = v 410 return v(self, node) 405 if type(node) is tuple: 406 return tuple([self.visit(n) for n in node]) 407 visitor = getattr(self, 'visit%s' % node.__class__.__name__, 408 self._visitDefault) 409 return visitor(node) 411 410 412 411 def _visitDefault(self, node): 413 412 return node … … 475 474 node.expr = self.visit(node.expr) 476 475 return node 477 476 477 def visitAssAttr(self, node): 478 node.expr = self.visit(node.expr) 479 return node 480 481 def visitAugAssign(self, node): 482 node.node = self.visit(node.node) 483 node.expr = self.visit(node.expr) 484 return node 485 478 486 def visitDecorators(self, node): 479 487 node.nodes = [self.visit(x) for x in node.nodes] 480 488 return node 481 489 490 def visitExec(self, node): 491 node.expr = self.visit(node.expr) 492 node.locals = self.visit(node.locals) 493 node.globals = self.visit(node.globals) 494 return node 495 482 496 def visitFor(self, node): 483 497 node.assign = self.visit(node.assign) 484 498 node.list = self.visit(node.list) … … 503 517 node.expr3 = self.visit(node.expr3) 504 518 return node 505 519 520 def visitReturn(self, node): 521 node.value = self.visit(node.value) 522 return node 523 506 524 def visitTryExcept(self, node): 507 525 node.body = self.visit(node.body) 508 526 node.handlers = self.visit(node.handlers) … … 536 554 node.nodes = [self.visit(x) for x in node.nodes] 537 555 return node 538 556 visitAnd = visitOr = visitBitand = visitBitor = visitBitxor = _visitBoolOp 539 visitAssTuple = _visitBoolOp557 visitAssTuple = visitAssList = _visitBoolOp 540 558 541 559 def _visitBinOp(self, node): 542 560 node.left = self.visit(node.left) … … 651 669 self.locals[-1].add(node.name) 652 670 return node 653 671 672 def visitAugAssign(self, node): 673 if isinstance(node.node, ast.Name): 674 name = node.node.name 675 node.node = ast.Subscript(ast.Name('data'), 'OP_APPLY', 676 [ast.Const(name)]) 677 node.expr = self.visit(node.expr) 678 return ast.If([ 679 (ast.Compare(ast.Const(name), [('in', ast.Name('data'))]), 680 ast.Stmt([node]))], 681 ast.Stmt([ast.Raise(ast.CallFunc(ast.Name('UndefinedError'), 682 [ast.Const(name)]), 683 None, None)])) 684 else: 685 return ASTTransformer.visitAugAssign(self, node) 686 654 687 def visitClass(self, node): 655 688 self.locals.append(set()) 656 689 node = ASTTransformer.visitClass(self, node) … … 675 708 self.locals.pop() 676 709 return node 677 710 678 def visitGetattr(self, node):679 return ast.CallFunc(ast.Name('_lookup_attr'), [680 ast.Name('data'), self.visit(node.expr),681 ast.Const(node.attrname)682 ])683 684 711 def visitLambda(self, node): 685 712 self.locals.append(set(flatten(node.argnames))) 686 713 node = ASTTransformer.visitLambda(self, node) … … 703 730 func_args = [ast.Name('data'), ast.Const(node.name)] 704 731 return ast.CallFunc(ast.Name('_lookup_name'), func_args) 705 732 733 734 class ExpressionASTTransformer(TemplateASTTransformer): 735 """Concrete AST transformer that implements the AST transformations needed 736 for code embedded in templates. 737 """ 738 739 def visitGetattr(self, node): 740 return ast.CallFunc(ast.Name('_lookup_attr'), [ 741 ast.Name('data'), self.visit(node.expr), 742 ast.Const(node.attrname) 743 ]) 744 706 745 def visitSubscript(self, node): 707 746 return ast.CallFunc(ast.Name('_lookup_item'), [ 708 747 ast.Name('data'), self.visit(node.expr),
