Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,44 @@ Usage

::

>>> import json
>>> from ast import parse
>>> from ast2json import ast2json

>>> ast = ast2json(parse(open('some_python_source_file.py').read()))
>>> print json.dumps(ast, indent=4)
>>> print(ast2json(parse(open('some_python_source_file.py').read(), indent=4))

If you are lazy, "str2json" will apply the "parse" method of ast on a string for you, so you'll be able to write:
If you want just the dict use:

::

>>> str2json(open('some_python_source_file.py').read())
>>> from ast2json import ast2dict
>>> str2dict(open('some_python_source_file.py').read())

Example
=======

This is the result of converting 'print "Hello World!"' (and applying json.dumps on the result).
This is the result of converting 'print("Hello World!")'.

::

{
"body": [
{
"_type": "Print",
"node_type": "Print",
"nl": true,
"col_offset": 0,
"dest": null,
"values": [
{
"s": "Hello World!",
"_type": "Str",
"node_type": "Str",
"lineno": 1,
"col_offset": 6
}
],
"lineno": 1
}
],
"_type": "Module"
"node_type": "Module"
}


Expand Down
84 changes: 61 additions & 23 deletions ast2json.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright (c) 2013, Laurent Peuch <cortex@worlddomination.be>
# Copyright (c) 2015, Eddy Ernesto del Valle Pino <xigmatron@gmail.com>
#
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
Expand All @@ -24,39 +25,76 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import json

from _ast import AST
from ast import parse


def ast2json(node):
assert isinstance(node, AST)
to_return = {}
to_return['_type'] = node.__class__.__name__
class AstJsonEncoder(json.JSONEncoder):

def default(self, obj):
if isinstance(obj, AST):
value = {
attr: getattr(obj, attr)
for attr in dir(obj)
if not attr.startswith('_')
}
value['node_type'] = obj.__class__.__name__
return value
return super(AstJsonEncoder, self) .default(obj)


def ast2json(node, *args, **kwargs):
return AstJsonEncoder(*args, **kwargs).encode(node)


def ast2dict(node):
result = {}
result['node_type'] = node.__class__.__name__.lower()
for attr in dir(node):
if attr.startswith("_"):
continue
to_return[attr] = get_value(getattr(node, attr))
if not attr.startswith("_") and attr not in ('lineno', 'col_offset'):
value = getattr(node, attr)
if isinstance(value, AST):
value = ast2dict(value)
elif isinstance(value, list):
value = [ast2dict(n) for n in value]
result[attr] = value
return result


return to_return
class Tag:

def __init__(self, name=None, attrs=None, children=None):
self.name = (name or attrs.pop('node_type', '')).lower()
self.attrs = {}
self.children = [Tag(attrs=child) for child in children or []]
for attr, value in (attrs or {}).items():
if isinstance(value, list):
self.children.append(Tag(name=attr, children=value))
elif isinstance(value, dict):
self.children.append(Tag(name=attr, children=[value]))
else:
self.attrs[attr] = value

def str2json(string):
return ast2json(parse(string))
def __str__(self):
attrs = []
for attr, value in self.attrs.items():
attrs.append('%(attr)s="%(value)s"' % locals())
attrs = ' '.join(attrs)
head = '%(name)s %(attrs)s' % {'name': self.name, 'attrs': attrs}
return '<%(head)s>\n%(children)s</%(name)s>' % {
'name': self.name,
'head': head.strip(),
'children': '\n'.join(str(node) for node in self.children) + '\n'
}


def get_value(attr_value):
if attr_value is None:
return attr_value
if isinstance(attr_value, (int, basestring, float, long, complex, bool)):
return attr_value
if isinstance(attr_value, list):
return [get_value(x) for x in attr_value]
if isinstance(attr_value, AST):
return ast2json(attr_value)
else:
raise Exception("unknow case for '%s' of type '%s'" % (attr_value, type(attr_value)))
def ast2xml(node):
return Tag(attrs=ast2dict(node))


if __name__ == '__main__':
import json
print json.dumps(ast2json(parse(open(__file__, "r").read())), indent=4)
import yaml
import sys
print(yaml.dump(ast2dict(parse(open(sys.argv[1]).read()))))