Home | History | Annotate | Download | only in test
      1 import sys, itertools, unittest
      2 from test import test_support
      3 import ast
      4 
      5 def to_tuple(t):
      6     if t is None or isinstance(t, (basestring, int, long, complex)):
      7         return t
      8     elif isinstance(t, list):
      9         return [to_tuple(e) for e in t]
     10     result = [t.__class__.__name__]
     11     if hasattr(t, 'lineno') and hasattr(t, 'col_offset'):
     12         result.append((t.lineno, t.col_offset))
     13     if t._fields is None:
     14         return tuple(result)
     15     for f in t._fields:
     16         result.append(to_tuple(getattr(t, f)))
     17     return tuple(result)
     18 
     19 
     20 # These tests are compiled through "exec"

     21 # There should be atleast one test per statement

     22 exec_tests = [
     23     # FunctionDef

     24     "def f(): pass",
     25     # ClassDef

     26     "class C:pass",
     27     # Return

     28     "def f():return 1",
     29     # Delete

     30     "del v",
     31     # Assign

     32     "v = 1",
     33     # AugAssign

     34     "v += 1",
     35     # Print

     36     "print >>f, 1, ",
     37     # For

     38     "for v in v:pass",
     39     # While

     40     "while v:pass",
     41     # If

     42     "if v:pass",
     43     # Raise

     44     "raise Exception, 'string'",
     45     # TryExcept

     46     "try:\n  pass\nexcept Exception:\n  pass",
     47     # TryFinally

     48     "try:\n  pass\nfinally:\n  pass",
     49     # Assert

     50     "assert v",
     51     # Import

     52     "import sys",
     53     # ImportFrom

     54     "from sys import v",
     55     # Exec

     56     "exec 'v'",
     57     # Global

     58     "global v",
     59     # Expr

     60     "1",
     61     # Pass,

     62     "pass",
     63     # Break

     64     "break",
     65     # Continue

     66     "continue",
     67     # for statements with naked tuples (see http://bugs.python.org/issue6704)

     68     "for a,b in c: pass",
     69     "[(a,b) for a,b in c]",
     70     "((a,b) for a,b in c)",
     71 ]
     72 
     73 # These are compiled through "single"

     74 # because of overlap with "eval", it just tests what

     75 # can't be tested with "eval"

     76 single_tests = [
     77     "1+2"
     78 ]
     79 
     80 # These are compiled through "eval"

     81 # It should test all expressions

     82 eval_tests = [
     83   # BoolOp

     84   "a and b",
     85   # BinOp

     86   "a + b",
     87   # UnaryOp

     88   "not v",
     89   # Lambda

     90   "lambda:None",
     91   # Dict

     92   "{ 1:2 }",
     93   # ListComp

     94   "[a for b in c if d]",
     95   # GeneratorExp

     96   "(a for b in c if d)",
     97   # Yield - yield expressions can't work outside a function

     98   #

     99   # Compare

    100   "1 < 2 < 3",
    101   # Call

    102   "f(1,2,c=3,*d,**e)",
    103   # Repr

    104   "`v`",
    105   # Num

    106   "10L",
    107   # Str

    108   "'string'",
    109   # Attribute

    110   "a.b",
    111   # Subscript

    112   "a[b:c]",
    113   # Name

    114   "v",
    115   # List

    116   "[1,2,3]",
    117   # Tuple

    118   "1,2,3",
    119   # Combination

    120   "a.b.c.d(a.b[1:2])",
    121 
    122 ]
    123 
    124 # TODO: expr_context, slice, boolop, operator, unaryop, cmpop, comprehension

    125 # excepthandler, arguments, keywords, alias

    126 
    127 class AST_Tests(unittest.TestCase):
    128 
    129     def _assertTrueorder(self, ast_node, parent_pos):
    130         if not isinstance(ast_node, ast.AST) or ast_node._fields is None:
    131             return
    132         if isinstance(ast_node, (ast.expr, ast.stmt, ast.excepthandler)):
    133             node_pos = (ast_node.lineno, ast_node.col_offset)
    134             self.assertTrue(node_pos >= parent_pos)
    135             parent_pos = (ast_node.lineno, ast_node.col_offset)
    136         for name in ast_node._fields:
    137             value = getattr(ast_node, name)
    138             if isinstance(value, list):
    139                 for child in value:
    140                     self._assertTrueorder(child, parent_pos)
    141             elif value is not None:
    142                 self._assertTrueorder(value, parent_pos)
    143 
    144     def test_snippets(self):
    145         for input, output, kind in ((exec_tests, exec_results, "exec"),
    146                                     (single_tests, single_results, "single"),
    147                                     (eval_tests, eval_results, "eval")):
    148             for i, o in itertools.izip(input, output):
    149                 ast_tree = compile(i, "?", kind, ast.PyCF_ONLY_AST)
    150                 self.assertEqual(to_tuple(ast_tree), o)
    151                 self._assertTrueorder(ast_tree, (0, 0))
    152 
    153     def test_slice(self):
    154         slc = ast.parse("x[::]").body[0].value.slice
    155         self.assertIsNone(slc.upper)
    156         self.assertIsNone(slc.lower)
    157         self.assertIsInstance(slc.step, ast.Name)
    158         self.assertEqual(slc.step.id, "None")
    159 
    160     def test_from_import(self):
    161         im = ast.parse("from . import y").body[0]
    162         self.assertIsNone(im.module)
    163 
    164     def test_base_classes(self):
    165         self.assertTrue(issubclass(ast.For, ast.stmt))
    166         self.assertTrue(issubclass(ast.Name, ast.expr))
    167         self.assertTrue(issubclass(ast.stmt, ast.AST))
    168         self.assertTrue(issubclass(ast.expr, ast.AST))
    169         self.assertTrue(issubclass(ast.comprehension, ast.AST))
    170         self.assertTrue(issubclass(ast.Gt, ast.AST))
    171 
    172     def test_nodeclasses(self):
    173         x = ast.BinOp(1, 2, 3, lineno=0)
    174         self.assertEqual(x.left, 1)
    175         self.assertEqual(x.op, 2)
    176         self.assertEqual(x.right, 3)
    177         self.assertEqual(x.lineno, 0)
    178 
    179         # node raises exception when not given enough arguments

    180         self.assertRaises(TypeError, ast.BinOp, 1, 2)
    181 
    182         # can set attributes through kwargs too

    183         x = ast.BinOp(left=1, op=2, right=3, lineno=0)
    184         self.assertEqual(x.left, 1)
    185         self.assertEqual(x.op, 2)
    186         self.assertEqual(x.right, 3)
    187         self.assertEqual(x.lineno, 0)
    188 
    189         # this used to fail because Sub._fields was None

    190         x = ast.Sub()
    191 
    192     def test_pickling(self):
    193         import pickle
    194         mods = [pickle]
    195         try:
    196             import cPickle
    197             mods.append(cPickle)
    198         except ImportError:
    199             pass
    200         protocols = [0, 1, 2]
    201         for mod in mods:
    202             for protocol in protocols:
    203                 for ast in (compile(i, "?", "exec", 0x400) for i in exec_tests):
    204                     ast2 = mod.loads(mod.dumps(ast, protocol))
    205                     self.assertEqual(to_tuple(ast2), to_tuple(ast))
    206 
    207 
    208 class ASTHelpers_Test(unittest.TestCase):
    209 
    210     def test_parse(self):
    211         a = ast.parse('foo(1 + 1)')
    212         b = compile('foo(1 + 1)', '<unknown>', 'exec', ast.PyCF_ONLY_AST)
    213         self.assertEqual(ast.dump(a), ast.dump(b))
    214 
    215     def test_dump(self):
    216         node = ast.parse('spam(eggs, "and cheese")')
    217         self.assertEqual(ast.dump(node),
    218             "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
    219             "args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], "
    220             "keywords=[], starargs=None, kwargs=None))])"
    221         )
    222         self.assertEqual(ast.dump(node, annotate_fields=False),
    223             "Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
    224             "Str('and cheese')], [], None, None))])"
    225         )
    226         self.assertEqual(ast.dump(node, include_attributes=True),
    227             "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
    228             "lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), "
    229             "lineno=1, col_offset=5), Str(s='and cheese', lineno=1, "
    230             "col_offset=11)], keywords=[], starargs=None, kwargs=None, "
    231             "lineno=1, col_offset=0), lineno=1, col_offset=0)])"
    232         )
    233 
    234     def test_copy_location(self):
    235         src = ast.parse('1 + 1', mode='eval')
    236         src.body.right = ast.copy_location(ast.Num(2), src.body.right)
    237         self.assertEqual(ast.dump(src, include_attributes=True),
    238             'Expression(body=BinOp(left=Num(n=1, lineno=1, col_offset=0), '
    239             'op=Add(), right=Num(n=2, lineno=1, col_offset=4), lineno=1, '
    240             'col_offset=0))'
    241         )
    242 
    243     def test_fix_missing_locations(self):
    244         src = ast.parse('write("spam")')
    245         src.body.append(ast.Expr(ast.Call(ast.Name('spam', ast.Load()),
    246                                           [ast.Str('eggs')], [], None, None)))
    247         self.assertEqual(src, ast.fix_missing_locations(src))
    248         self.assertEqual(ast.dump(src, include_attributes=True),
    249             "Module(body=[Expr(value=Call(func=Name(id='write', ctx=Load(), "
    250             "lineno=1, col_offset=0), args=[Str(s='spam', lineno=1, "
    251             "col_offset=6)], keywords=[], starargs=None, kwargs=None, "
    252             "lineno=1, col_offset=0), lineno=1, col_offset=0), "
    253             "Expr(value=Call(func=Name(id='spam', ctx=Load(), lineno=1, "
    254             "col_offset=0), args=[Str(s='eggs', lineno=1, col_offset=0)], "
    255             "keywords=[], starargs=None, kwargs=None, lineno=1, "
    256             "col_offset=0), lineno=1, col_offset=0)])"
    257         )
    258 
    259     def test_increment_lineno(self):
    260         src = ast.parse('1 + 1', mode='eval')
    261         self.assertEqual(ast.increment_lineno(src, n=3), src)
    262         self.assertEqual(ast.dump(src, include_attributes=True),
    263             'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
    264             'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
    265             'col_offset=0))'
    266         )
    267         # issue10869: do not increment lineno of root twice

    268         src = ast.parse('1 + 1', mode='eval')
    269         self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
    270         self.assertEqual(ast.dump(src, include_attributes=True),
    271             'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
    272             'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
    273             'col_offset=0))'
    274         )
    275 
    276     def test_iter_fields(self):
    277         node = ast.parse('foo()', mode='eval')
    278         d = dict(ast.iter_fields(node.body))
    279         self.assertEqual(d.pop('func').id, 'foo')
    280         self.assertEqual(d, {'keywords': [], 'kwargs': None,
    281                              'args': [], 'starargs': None})
    282 
    283     def test_iter_child_nodes(self):
    284         node = ast.parse("spam(23, 42, eggs='leek')", mode='eval')
    285         self.assertEqual(len(list(ast.iter_child_nodes(node.body))), 4)
    286         iterator = ast.iter_child_nodes(node.body)
    287         self.assertEqual(next(iterator).id, 'spam')
    288         self.assertEqual(next(iterator).n, 23)
    289         self.assertEqual(next(iterator).n, 42)
    290         self.assertEqual(ast.dump(next(iterator)),
    291             "keyword(arg='eggs', value=Str(s='leek'))"
    292         )
    293 
    294     def test_get_docstring(self):
    295         node = ast.parse('def foo():\n  """line one\n  line two"""')
    296         self.assertEqual(ast.get_docstring(node.body[0]),
    297                          'line one\nline two')
    298 
    299     def test_literal_eval(self):
    300         self.assertEqual(ast.literal_eval('[1, 2, 3]'), [1, 2, 3])
    301         self.assertEqual(ast.literal_eval('{"foo": 42}'), {"foo": 42})
    302         self.assertEqual(ast.literal_eval('(True, False, None)'), (True, False, None))
    303         self.assertRaises(ValueError, ast.literal_eval, 'foo()')
    304 
    305     def test_literal_eval_issue4907(self):
    306         self.assertEqual(ast.literal_eval('2j'), 2j)
    307         self.assertEqual(ast.literal_eval('10 + 2j'), 10 + 2j)
    308         self.assertEqual(ast.literal_eval('1.5 - 2j'), 1.5 - 2j)
    309         self.assertRaises(ValueError, ast.literal_eval, '2 + (3 + 4j)')
    310 
    311 
    312 def test_main():
    313     with test_support.check_py3k_warnings(("backquote not supported",
    314                                              SyntaxWarning)):
    315         test_support.run_unittest(AST_Tests, ASTHelpers_Test)
    316 
    317 def main():
    318     if __name__ != '__main__':
    319         return
    320     if sys.argv[1:] == ['-g']:
    321         for statements, kind in ((exec_tests, "exec"), (single_tests, "single"),
    322                                  (eval_tests, "eval")):
    323             print kind+"_results = ["
    324             for s in statements:
    325                 print repr(to_tuple(compile(s, "?", kind, 0x400)))+","
    326             print "]"
    327         print "main()"
    328         raise SystemExit
    329     test_main()
    330 
    331 #### EVERYTHING BELOW IS GENERATED #####

    332 exec_results = [
    333 ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, []), [('Pass', (1, 9))], [])]),
    334 ('Module', [('ClassDef', (1, 0), 'C', [], [('Pass', (1, 8))], [])]),
    335 ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, []), [('Return', (1, 8), ('Num', (1, 15), 1))], [])]),
    336 ('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])]),
    337 ('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Num', (1, 4), 1))]),
    338 ('Module', [('AugAssign', (1, 0), ('Name', (1, 0), 'v', ('Store',)), ('Add',), ('Num', (1, 5), 1))]),
    339 ('Module', [('Print', (1, 0), ('Name', (1, 8), 'f', ('Load',)), [('Num', (1, 11), 1)], False)]),
    340 ('Module', [('For', (1, 0), ('Name', (1, 4), 'v', ('Store',)), ('Name', (1, 9), 'v', ('Load',)), [('Pass', (1, 11))], [])]),
    341 ('Module', [('While', (1, 0), ('Name', (1, 6), 'v', ('Load',)), [('Pass', (1, 8))], [])]),
    342 ('Module', [('If', (1, 0), ('Name', (1, 3), 'v', ('Load',)), [('Pass', (1, 5))], [])]),
    343 ('Module', [('Raise', (1, 0), ('Name', (1, 6), 'Exception', ('Load',)), ('Str', (1, 17), 'string'), None)]),
    344 ('Module', [('TryExcept', (1, 0), [('Pass', (2, 2))], [('ExceptHandler', (3, 0), ('Name', (3, 7), 'Exception', ('Load',)), None, [('Pass', (4, 2))])], [])]),
    345 ('Module', [('TryFinally', (1, 0), [('Pass', (2, 2))], [('Pass', (4, 2))])]),
    346 ('Module', [('Assert', (1, 0), ('Name', (1, 7), 'v', ('Load',)), None)]),
    347 ('Module', [('Import', (1, 0), [('alias', 'sys', None)])]),
    348 ('Module', [('ImportFrom', (1, 0), 'sys', [('alias', 'v', None)], 0)]),
    349 ('Module', [('Exec', (1, 0), ('Str', (1, 5), 'v'), None, None)]),
    350 ('Module', [('Global', (1, 0), ['v'])]),
    351 ('Module', [('Expr', (1, 0), ('Num', (1, 0), 1))]),
    352 ('Module', [('Pass', (1, 0))]),
    353 ('Module', [('Break', (1, 0))]),
    354 ('Module', [('Continue', (1, 0))]),
    355 ('Module', [('For', (1, 0), ('Tuple', (1, 4), [('Name', (1, 4), 'a', ('Store',)), ('Name', (1, 6), 'b', ('Store',))], ('Store',)), ('Name', (1, 11), 'c', ('Load',)), [('Pass', (1, 14))], [])]),
    356 ('Module', [('Expr', (1, 0), ('ListComp', (1, 1), ('Tuple', (1, 2), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'a', ('Store',)), ('Name', (1, 13), 'b', ('Store',))], ('Store',)), ('Name', (1, 18), 'c', ('Load',)), [])]))]),
    357 ('Module', [('Expr', (1, 0), ('GeneratorExp', (1, 1), ('Tuple', (1, 2), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'a', ('Store',)), ('Name', (1, 13), 'b', ('Store',))], ('Store',)), ('Name', (1, 18), 'c', ('Load',)), [])]))]),
    358 ]
    359 single_results = [
    360 ('Interactive', [('Expr', (1, 0), ('BinOp', (1, 0), ('Num', (1, 0), 1), ('Add',), ('Num', (1, 2), 2)))]),
    361 ]
    362 eval_results = [
    363 ('Expression', ('BoolOp', (1, 0), ('And',), [('Name', (1, 0), 'a', ('Load',)), ('Name', (1, 6), 'b', ('Load',))])),
    364 ('Expression', ('BinOp', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Add',), ('Name', (1, 4), 'b', ('Load',)))),
    365 ('Expression', ('UnaryOp', (1, 0), ('Not',), ('Name', (1, 4), 'v', ('Load',)))),
    366 ('Expression', ('Lambda', (1, 0), ('arguments', [], None, None, []), ('Name', (1, 7), 'None', ('Load',)))),
    367 ('Expression', ('Dict', (1, 0), [('Num', (1, 2), 1)], [('Num', (1, 4), 2)])),
    368 ('Expression', ('ListComp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])),
    369 ('Expression', ('GeneratorExp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])),
    370 ('Expression', ('Compare', (1, 0), ('Num', (1, 0), 1), [('Lt',), ('Lt',)], [('Num', (1, 4), 2), ('Num', (1, 8), 3)])),
    371 ('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2)], [('keyword', 'c', ('Num', (1, 8), 3))], ('Name', (1, 11), 'd', ('Load',)), ('Name', (1, 15), 'e', ('Load',)))),
    372 ('Expression', ('Repr', (1, 0), ('Name', (1, 1), 'v', ('Load',)))),
    373 ('Expression', ('Num', (1, 0), 10L)),
    374 ('Expression', ('Str', (1, 0), 'string')),
    375 ('Expression', ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))),
    376 ('Expression', ('Subscript', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Slice', ('Name', (1, 2), 'b', ('Load',)), ('Name', (1, 4), 'c', ('Load',)), None), ('Load',))),
    377 ('Expression', ('Name', (1, 0), 'v', ('Load',))),
    378 ('Expression', ('List', (1, 0), [('Num', (1, 1), 1), ('Num', (1, 3), 2), ('Num', (1, 5), 3)], ('Load',))),
    379 ('Expression', ('Tuple', (1, 0), [('Num', (1, 0), 1), ('Num', (1, 2), 2), ('Num', (1, 4), 3)], ('Load',))),
    380 ('Expression', ('Call', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8), ('Attribute', (1, 8), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Num', (1, 12), 1), ('Num', (1, 14), 2), None), ('Load',))], [], None, None)),
    381 ]
    382 main()
    383