Revert unwanted changes.

This commit is contained in:
Georg Brandl 2008-06-07 16:04:01 +00:00
parent 7be19aabe2
commit bf0610a1ca
3 changed files with 95 additions and 101 deletions

85
Doc/library/_ast.rst Normal file
View File

@ -0,0 +1,85 @@
.. _ast:
Abstract Syntax Trees
=====================
.. module:: _ast
:synopsis: Abstract Syntax Tree classes.
.. sectionauthor:: Martin v. Löwis <martin@v.loewis.de>
.. versionadded:: 2.5
The ``_ast`` module helps Python applications to process trees of the Python
abstract syntax grammar. The abstract syntax itself might change with each
Python release; this module helps to find out programmatically what the current
grammar looks like.
An abstract syntax tree can be generated by passing :data:`_ast.PyCF_ONLY_AST`
as a flag to the :func:`compile` builtin function. The result will be a tree of
objects whose classes all inherit from :class:`_ast.AST`.
A modified abstract syntax tree can be compiled into a Python code object using
the built-in :func:`compile` function.
The actual classes are derived from the ``Parser/Python.asdl`` file, which is
reproduced below. There is one class defined for each left-hand side symbol in
the abstract grammar (for example, ``_ast.stmt`` or ``_ast.expr``). In addition,
there is one class defined for each constructor on the right-hand side; these
classes inherit from the classes for the left-hand side trees. For example,
``_ast.BinOp`` inherits from ``_ast.expr``. For production rules with
alternatives (aka "sums"), the left-hand side class is abstract: only instances
of specific constructor nodes are ever created.
Each concrete class has an attribute ``_fields`` which gives the names of all
child nodes.
Each instance of a concrete class has one attribute for each child node, of the
type as defined in the grammar. For example, ``_ast.BinOp`` instances have an
attribute ``left`` of type ``_ast.expr``. Instances of ``_ast.expr`` and
``_ast.stmt`` subclasses also have lineno and col_offset attributes. The lineno
is the line number of source text (1 indexed so the first line is line 1) and
the col_offset is the utf8 byte offset of the first token that generated the
node. The utf8 offset is recorded because the parser uses utf8 internally.
If these attributes are marked as optional in the grammar (using a question
mark), the value might be ``None``. If the attributes can have zero-or-more
values (marked with an asterisk), the values are represented as Python lists.
All possible attributes must be present and have valid values when compiling an
AST with :func:`compile`.
The constructor of a class ``_ast.T`` parses their arguments as follows:
* If there are positional arguments, there must be as many as there are items in
``T._fields``; they will be assigned as attributes of these names.
* If there are keyword arguments, they will set the attributes of the same names
to the given values.
For example, to create and populate a ``UnaryOp`` node, you could use ::
node = _ast.UnaryOp()
node.op = _ast.USub()
node.operand = _ast.Num()
node.operand.n = 5
node.operand.lineno = 0
node.operand.col_offset = 0
node.lineno = 0
node.col_offset = 0
or the more compact ::
node = _ast.UnaryOp(_ast.USub(), _ast.Num(5, lineno=0, col_offset=0),
lineno=0, col_offset=0)
Abstract Grammar
----------------
The module defines a string constant ``__version__`` which is the decimal
subversion revision number of the file shown below.
The abstract grammar is currently defined as follows:
.. literalinclude:: ../../Parser/Python.asdl

View File

@ -15,7 +15,7 @@ These modules include:
.. toctree:: .. toctree::
parser.rst parser.rst
ast.rst _ast.rst
symbol.rst symbol.rst
token.rst token.rst
keyword.rst keyword.rst

View File

@ -1,6 +1,6 @@
import sys, itertools, unittest import sys, itertools, unittest
from test import test_support from test import test_support
import ast import _ast
def to_tuple(t): def to_tuple(t):
if t is None or isinstance(t, (basestring, int, long, complex)): if t is None or isinstance(t, (basestring, int, long, complex)):
@ -123,9 +123,9 @@ eval_tests = [
class AST_Tests(unittest.TestCase): class AST_Tests(unittest.TestCase):
def _assert_order(self, ast_node, parent_pos): def _assert_order(self, ast_node, parent_pos):
if not isinstance(ast_node, ast.AST) or ast_node._fields is None: if not isinstance(ast_node, _ast.AST) or ast_node._fields is None:
return return
if isinstance(ast_node, (ast.expr, ast.stmt, ast.excepthandler)): if isinstance(ast_node, (_ast.expr, _ast.stmt, _ast.excepthandler)):
node_pos = (ast_node.lineno, ast_node.col_offset) node_pos = (ast_node.lineno, ast_node.col_offset)
self.assert_(node_pos >= parent_pos) self.assert_(node_pos >= parent_pos)
parent_pos = (ast_node.lineno, ast_node.col_offset) parent_pos = (ast_node.lineno, ast_node.col_offset)
@ -142,29 +142,29 @@ class AST_Tests(unittest.TestCase):
(single_tests, single_results, "single"), (single_tests, single_results, "single"),
(eval_tests, eval_results, "eval")): (eval_tests, eval_results, "eval")):
for i, o in itertools.izip(input, output): for i, o in itertools.izip(input, output):
ast_tree = compile(i, "?", kind, ast.PyCF_ONLY_AST) ast_tree = compile(i, "?", kind, _ast.PyCF_ONLY_AST)
self.assertEquals(to_tuple(ast_tree), o) self.assertEquals(to_tuple(ast_tree), o)
self._assert_order(ast_tree, (0, 0)) self._assert_order(ast_tree, (0, 0))
def test_nodeclasses(self): def test_nodeclasses(self):
x = ast.BinOp(1, 2, 3, lineno=0) x = _ast.BinOp(1, 2, 3, lineno=0)
self.assertEquals(x.left, 1) self.assertEquals(x.left, 1)
self.assertEquals(x.op, 2) self.assertEquals(x.op, 2)
self.assertEquals(x.right, 3) self.assertEquals(x.right, 3)
self.assertEquals(x.lineno, 0) self.assertEquals(x.lineno, 0)
# node raises exception when not given enough arguments # node raises exception when not given enough arguments
self.assertRaises(TypeError, ast.BinOp, 1, 2) self.assertRaises(TypeError, _ast.BinOp, 1, 2)
# can set attributes through kwargs too # can set attributes through kwargs too
x = ast.BinOp(left=1, op=2, right=3, lineno=0) x = _ast.BinOp(left=1, op=2, right=3, lineno=0)
self.assertEquals(x.left, 1) self.assertEquals(x.left, 1)
self.assertEquals(x.op, 2) self.assertEquals(x.op, 2)
self.assertEquals(x.right, 3) self.assertEquals(x.right, 3)
self.assertEquals(x.lineno, 0) self.assertEquals(x.lineno, 0)
# this used to fail because Sub._fields was None # this used to fail because Sub._fields was None
x = ast.Sub() x = _ast.Sub()
def test_pickling(self): def test_pickling(self):
import pickle import pickle
@ -181,99 +181,8 @@ class AST_Tests(unittest.TestCase):
ast2 = mod.loads(mod.dumps(ast, protocol)) ast2 = mod.loads(mod.dumps(ast, protocol))
self.assertEquals(to_tuple(ast2), to_tuple(ast)) self.assertEquals(to_tuple(ast2), to_tuple(ast))
class ASTHelpers_Test(unittest.TestCase):
def test_parse(self):
a = ast.parse('foo(1 + 1)')
b = compile('foo(1 + 1)', '<unknown>', 'exec', ast.PyCF_ONLY_AST)
self.assertEqual(ast.dump(a), ast.dump(b))
def test_dump(self):
node = ast.parse('spam(eggs, "and cheese")')
self.assertEqual(ast.dump(node),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), "
"args=[Name(id='eggs', ctx=Load()), Str(s='and cheese')], "
"keywords=[], starargs=None, kwargs=None))])"
)
self.assertEqual(ast.dump(node, annotate_fields=False),
"Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), "
"Str('and cheese')], [], None, None))])"
)
self.assertEqual(ast.dump(node, include_attributes=True),
"Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), "
"lineno=1, col_offset=0), args=[Name(id='eggs', ctx=Load(), "
"lineno=1, col_offset=5), Str(s='and cheese', lineno=1, "
"col_offset=11)], keywords=[], starargs=None, kwargs=None, "
"lineno=1, col_offset=0), lineno=1, col_offset=0)])"
)
def test_copy_location(self):
src = ast.parse('1 + 1', mode='eval')
src.body.right = ast.copy_location(ast.Num(2), src.body.right)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=1, col_offset=0), '
'op=Add(), right=Num(n=2, lineno=1, col_offset=4), lineno=1, '
'col_offset=0))'
)
def test_fix_missing_locations(self):
src = ast.parse('write("spam")')
src.body.append(ast.Expr(ast.Call(ast.Name('spam', ast.Load()),
[ast.Str('eggs')], [], None, None)))
self.assertEqual(src, ast.fix_missing_locations(src))
self.assertEqual(ast.dump(src, include_attributes=True),
"Module(body=[Expr(value=Call(func=Name(id='write', ctx=Load(), "
"lineno=1, col_offset=0), args=[Str(s='spam', lineno=1, "
"col_offset=6)], keywords=[], starargs=None, kwargs=None, "
"lineno=1, col_offset=0), lineno=1, col_offset=0), "
"Expr(value=Call(func=Name(id='spam', ctx=Load(), lineno=1, "
"col_offset=0), args=[Str(s='eggs', lineno=1, col_offset=0)], "
"keywords=[], starargs=None, kwargs=None, lineno=1, "
"col_offset=0), lineno=1, col_offset=0)])"
)
def test_increment_lineno(self):
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src, n=3), src)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
def test_iter_fields(self):
node = ast.parse('foo()', mode='eval')
d = dict(ast.iter_fields(node.body))
self.assertEqual(d.pop('func').id, 'foo')
self.assertEqual(d, {'keywords': [], 'kwargs': None,
'args': [], 'starargs': None})
def test_iter_child_nodes(self):
node = ast.parse("spam(23, 42, eggs='leek')", mode='eval')
self.assertEqual(len(list(ast.iter_child_nodes(node.body))), 4)
iterator = ast.iter_child_nodes(node.body)
self.assertEqual(next(iterator).id, 'spam')
self.assertEqual(next(iterator).n, 23)
self.assertEqual(next(iterator).n, 42)
self.assertEqual(ast.dump(next(iterator)),
"keyword(arg='eggs', value=Str(s='leek'))"
)
def test_get_docstring(self):
node = ast.parse('def foo():\n """line one\n line two"""')
self.assertEqual(ast.get_docstring(node.body[0]),
'line one\n line two')
def test_literal_eval(self):
self.assertEqual(ast.literal_eval('[1, 2, 3]'), [1, 2, 3])
self.assertEqual(ast.literal_eval('{"foo": 42}'), {"foo": 42})
self.assertEqual(ast.literal_eval('(True, False, None)'), (True, False, None))
self.assertRaises(ValueError, ast.literal_eval, 'foo()')
def test_main(): def test_main():
test_support.run_unittest(AST_Tests, ASTHelpers_Test) test_support.run_unittest(AST_Tests)
def main(): def main():
if __name__ != '__main__': if __name__ != '__main__':