Skip to content

Commit

Permalink
Implement JSON Importer.
Browse files Browse the repository at this point in the history
  • Loading branch information
c0fec0de committed Nov 22, 2017
1 parent 71f7ff9 commit 521ab94
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 10 deletions.
1 change: 1 addition & 0 deletions anytree/importer/__init__.py
@@ -1,3 +1,4 @@
"""Importer."""

from .dictimporter import DictImporter # noqa
from .jsonimporter import JsonImporter # noqa
2 changes: 1 addition & 1 deletion anytree/importer/dictimporter.py
Expand Up @@ -5,7 +5,7 @@ class DictImporter(object):

def __init__(self, nodecls=AnyNode):
"""
Import Node from dictionary.
Import Tree from dictionary.
Every dictionary is converted to an instance of `nodecls`.
The dictionaries listed in the children attribute are converted
Expand Down
65 changes: 65 additions & 0 deletions anytree/importer/jsonimporter.py
@@ -0,0 +1,65 @@
import json

from .dictimporter import DictImporter


class JsonImporter(object):

def __init__(self, dictimporter=None, **kwargs):
"""
Import Tree from JSON.
The JSON is read and converted to a dictionary via `dictimporter`.
Keyword Arguments:
dictimporter: Dictionary Importer used (see :any:`DictImporter`).
kwargs: All other arguments are passed to
:any:`json.load`/:any:`json.loads`.
See documentation for reference.
>>> from anytree.importer import JsonImporter
>>> from anytree import RenderTree
>>> importer = JsonImporter()
>>> data = '''
... {
... "a": "root",
... "children": [
... {
... "a": "sub0",
... "children": [
... {
... "a": "sub0A",
... "b": "foo"
... },
... {
... "a": "sub0B"
... }
... ]
... },
... {
... "a": "sub1"
... }
... ]
... }'''
>>> root = importer.import_(data)
>>> print(RenderTree(root))
AnyNode(a='root')
├── AnyNode(a='sub0')
│ ├── AnyNode(a='sub0A', b='foo')
│ └── AnyNode(a='sub0B')
└── AnyNode(a='sub1')
"""
self.dictimporter = dictimporter
self.kwargs = kwargs

def import_(self, data):
"""Read JSON from `data`."""
dictimporter = self.dictimporter or DictImporter()
data = json.loads(data, **self.kwargs)
return dictimporter.import_(data)

def read(self, filehandle):
"""Read JSON from `filehandle`."""
dictimporter = self.dictimporter or DictImporter()
data = json.load(filehandle, **self.kwargs)
return dictimporter.import_(data)
1 change: 1 addition & 0 deletions docs/importer.rst
Expand Up @@ -8,6 +8,7 @@ Available importers:

.. toctree::
importer/dictimporter
importer/jsonimporter

Importer missing? File a request here: Issues_.

Expand Down
7 changes: 7 additions & 0 deletions docs/importer/jsonimporter.rst
@@ -0,0 +1,7 @@
JSON Importer
=============

.. automodule:: anytree.importer.jsonimporter
:members:
:undoc-members:
:show-inheritance:
6 changes: 3 additions & 3 deletions tests/test_dictimporter.py
Expand Up @@ -10,7 +10,7 @@ def test_dict_importer():
"""Dict Importer."""
importer = DictImporter()
exporter = DictExporter()
ref = {
refdata = {
'id': 'root', 'children': [
{'id': 'sub0', 'children': [
{'id': 'sub0B'},
Expand All @@ -24,8 +24,8 @@ def test_dict_importer():
]}
]}
]}
data = deepcopy(ref)
data = deepcopy(refdata)
root = importer.import_(data)
eq_(data, ref)
eq_(data, refdata)
eq_(exporter.export(root), data)

11 changes: 5 additions & 6 deletions tests/test_jsonexporter.py
@@ -1,5 +1,4 @@
import filecmp
import os

from tempfile import NamedTemporaryFile

Expand All @@ -13,13 +12,13 @@ def test_json_exporter():
"""Json Exporter."""
root = AnyNode(id="root")
s0 = AnyNode(id="sub0", parent=root)
s0b = AnyNode(id="sub0B", parent=s0)
s0a = AnyNode(id="sub0A", parent=s0)
AnyNode(id="sub0B", parent=s0)
AnyNode(id="sub0A", parent=s0)
s1 = AnyNode(id="sub1", parent=root)
s1a = AnyNode(id="sub1A", parent=s1)
s1b = AnyNode(id="sub1B", parent=s1)
AnyNode(id="sub1A", parent=s1)
AnyNode(id="sub1B", parent=s1)
s1c = AnyNode(id="sub1C", parent=s1)
s1ca = AnyNode(id="sub1Ca", parent=s1c)
AnyNode(id="sub1Ca", parent=s1c)

lines = [
'{',
Expand Down
73 changes: 73 additions & 0 deletions tests/test_jsonimporter.py
@@ -0,0 +1,73 @@
import filecmp

from tempfile import NamedTemporaryFile

from nose.tools import eq_

from anytree import AnyNode
from anytree.importer import JsonImporter
from anytree.exporter import DictExporter
from anytree.importer import DictImporter


def test_json_importer():
"""Json Importer."""
refdata = {
'id': 'root', 'children': [
{'id': 'sub0', 'children': [
{'id': 'sub0B'},
{'id': 'sub0A'}
]},
{'id': 'sub1', 'children': [
{'id': 'sub1A'},
{'id': 'sub1B'},
{'id': 'sub1C', 'children': [
{'id': 'sub1Ca'}
]}
]}
]}
lines = [
'{',
' "children": [',
' {',
' "children": [',
' {',
' "id": "sub0B"',
' },',
' {',
' "id": "sub0A"',
' }',
' ],',
' "id": "sub0"',
' },',
' {',
' "children": [',
' {',
' "id": "sub1A"',
' },',
' {',
' "id": "sub1B"',
' },',
' {',
' "children": [',
' {',
' "id": "sub1Ca"',
' }',
' ],',
' "id": "sub1C"',
' }',
' ],',
' "id": "sub1"',
' }',
' ],',
' "id": "root"',
'}'
]

imported = DictExporter().export(JsonImporter().import_("\n".join(lines)))
eq_(refdata, imported)
with NamedTemporaryFile(mode="w+") as ref:
ref.write("\n".join(lines))
ref.seek(0)
imported = DictExporter().export(JsonImporter().read(ref))
eq_(refdata, imported)

0 comments on commit 521ab94

Please sign in to comment.