· 8 years ago · Jan 28, 2018, 07:06 PM
1"""
2# Examples:
3# as line magic:
4In [1]: %dump_ast print("hi")
5Module(body=[
6 Expr(value=Call(func=Name(id='print', ctx=Load()), args=[
7 Str(s='hi'),
8 ], keywords=[])),
9 ])
10# as cell magic:
11In [2]: %%dump_ast_cell
12 ...: for i in range(10):
13 ...: i**i
14 ...:
15Module(body=[
16 For(target=Name(id='i', ctx=Store()), iter=Call(func=Name(id='range', ctx=Load()), args=[
17 Num(n=10),
18 ], keywords=[]), body=[
19 Expr(value=BinOp(left=Name(id='i', ctx=Load()), op=Pow(), right=Name(id='i', ctx=Load()))),
20 ], orelse=[]),
21 ])
22"""
23A pretty-printing dump function for the ast module. The code was copied from
24the ast.dump function and modified slightly to pretty-print.
25
26Alex Leone (acleone ~AT~ gmail.com), 2010-01-30
27
28From http://alexleone.blogspot.co.uk/2010/01/python-ast-pretty-printer.html
29"""
30
31from ast import *
32from IPython.core.magic import (Magics, magics_class, cell_magic, line_magic)
33from IPython.core.magic_arguments import (argument, magic_arguments, parse_argstring)
34__file__ = '__main__.py'
35def dump(node, annotate_fields=True, include_attributes=False, indent=' '):
36 """
37 Return a formatted dump of the tree in *node*. This is mainly useful for
38 debugging purposes. The returned string will show the names and the values
39 for fields. This makes the code impossible to evaluate, so if evaluation is
40 wanted *annotate_fields* must be set to False. Attributes such as line
41 numbers and column offsets are not dumped by default. If this is wanted,
42 *include_attributes* can be set to True.
43 """
44 def _format(node, level=0):
45 if isinstance(node, AST):
46 fields = [(a, _format(b, level)) for a, b in iter_fields(node)]
47 if include_attributes and node._attributes:
48 fields.extend([(a, _format(getattr(node, a), level))
49 for a in node._attributes])
50 return ''.join([
51 node.__class__.__name__,
52 '(',
53 ', '.join(('%s=%s' % field for field in fields)
54 if annotate_fields else
55 (b for a, b in fields)),
56 ')'])
57 elif isinstance(node, list):
58 lines = ['[']
59 lines.extend((indent * (level + 2) + _format(x, level + 2) + ','
60 for x in node))
61 if len(lines) > 1:
62 lines.append(indent * (level + 1) + ']')
63 else:
64 lines[-1] += ']'
65 return '\n'.join(lines)
66 return repr(node)
67
68 if not isinstance(node, AST):
69 raise TypeError('expected AST, got %r' % node.__class__.__name__)
70 return _format(node)
71
72def parseprint(code, filename="<string>", mode="exec", **kwargs):
73 """Parse some code from a string and pretty-print it."""
74 node = parse(code, '<dump_ast>',mode=mode) # An ode to the code
75 print(dump(node, **kwargs))
76
77# Short name: pdp = parse, dump, print
78pdp = parseprint
79
80
81
82@magics_class
83class AstMagics(Magics):
84 @magic_arguments()
85 @argument(
86 '-m', '--mode', default='exec',
87 help="The mode in which to parse the code. Can be exec (the default), "
88 "eval or single.")
89 @cell_magic
90 def dump_ast_cell(self, line, cell=None):
91 """Parse the code in the cell, and pretty-print the AST."""
92 args = parse_argstring(self.dump_ast_cell, line)
93 parseprint(line if cell == None else line + "\n" + cell, mode=args.mode)
94 @line_magic
95 def dump_ast(self, line):
96 """Parse the code in the cell, and pretty-print the AST."""
97 parseprint(line)
98
99
100
101def load_ipython_extension(ip):
102 print("loading pprint for ast module in ipython")
103 ip.register_magics(AstMagics)
104
105if __name__ == '__main__':
106 import sys, tokenize
107 for filename in sys.argv[1:]:
108 print('=' * 50)
109 print('AST tree for', filename)
110 print('=' * 50)
111 with tokenize.open(filename) as f:
112 fstr = f.read()
113
114 parseprint(fstr, filename=filename, include_attributes=True)
115 print()
116#else:
117# del parseprint, dump
118
119
120from ast import *
121from IPython.core.magic import (Magics, magics_class, cell_magic, line_magic)
122from IPython.core.magic_arguments import (argument, magic_arguments, parse_argstring)
123
124def dump(node, annotate_fields=True, include_attributes=False, indent=' '):
125 """
126 Return a formatted dump of the tree in *node*. This is mainly useful for
127 debugging purposes. The returned string will show the names and the values
128 for fields. This makes the code impossible to evaluate, so if evaluation is
129 wanted *annotate_fields* must be set to False. Attributes such as line
130 numbers and column offsets are not dumped by default. If this is wanted,
131 *include_attributes* can be set to True.
132 """
133 def _format(node, level=0):
134 if isinstance(node, AST):
135 fields = [(a, _format(b, level)) for a, b in iter_fields(node)]
136 if include_attributes and node._attributes:
137 fields.extend([(a, _format(getattr(node, a), level))
138 for a in node._attributes])
139 return ''.join([
140 node.__class__.__name__,
141 '(',
142 ', '.join(('%s=%s' % field for field in fields)
143 if annotate_fields else
144 (b for a, b in fields)),
145 ')'])
146 elif isinstance(node, list):
147 lines = ['[']
148 lines.extend((indent * (level + 2) + _format(x, level + 2) + ','
149 for x in node))
150 if len(lines) > 1:
151 lines.append(indent * (level + 1) + ']')
152 else:
153 lines[-1] += ']'
154 return '\n'.join(lines)
155 return repr(node)
156
157 if not isinstance(node, AST):
158 raise TypeError('expected AST, got %r' % node.__class__.__name__)
159 return _format(node)
160
161def parseprint(code, filename="<string>", mode="exec", **kwargs):
162 """Parse some code from a string and pretty-print it."""
163 node = parse(code, '<dump_ast>',mode=mode) # An ode to the code
164 print(dump(node, **kwargs))
165
166# Short name: pdp = parse, dump, print
167pdp = parseprint
168
169
170
171@magics_class
172class AstMagics(Magics):
173 @magic_arguments()
174 @argument(
175 '-m', '--mode', default='exec',
176 help="The mode in which to parse the code. Can be exec (the default), "
177 "eval or single.")
178 @cell_magic
179 def dump_ast_cell(self, line, cell=None):
180 """Parse the code in the cell, and pretty-print the AST."""
181 args = parse_argstring(self.dump_ast_cell, line)
182 parseprint(line if cell == None else line + "\n" + cell, mode=args.mode)
183 @line_magic
184 def dump_ast(self, line):
185 """Parse the code in the cell, and pretty-print the AST."""
186 parseprint(line)
187
188
189
190def load_ipython_extension(ip):
191 print("loading pprint for ast module in ipython")
192 ip.register_magics(AstMagics)
193
194if __name__ == '__main__':
195 import sys, tokenize
196 for filename in sys.argv[1:]:
197 print('=' * 50)
198 print('AST tree for', filename)
199 print('=' * 50)
200 with tokenize.open(filename) as f:
201 fstr = f.read()
202
203 parseprint(fstr, filename=filename, include_attributes=True)
204 print()
205#else:
206# del parseprint, dump