jsontree - build, parse and explore json data

Travis integration TBD

jsontree is a simple module for quickly building manipulating and modifying rich json data in python.

Datetime objects are serialized out ti the ISO format which is easilly used in javascript. ISO formatted datetime strings will be deserialized into datetime objects.

import jsontree
import datetime
data = jsontree.jsontree()
data.username = 'doug'
data.meta.date = datetime.datetime.now()
data.somethingelse = [1,2,3]

data['username'] == 'doug'

ser = jsontree.dumps(data)
backagain = jsontree.loads(ser)
cloned = jsontree.clone(data)

Project Links:

Module Documentation

JSON Tree Library

class jsontree.JSONTreeDecoder(*args, **kwdargs)[source]

Bases: json.decoder.JSONDecoder

JSON decoder class for deserializing to a jsontree object structure and building datetime objects from strings with the ISO datetime format.

decode(s, _w=<built-in method match of re.Pattern object>)

Return the Python representation of s (a str instance containing a JSON document).

raw_decode(s, idx=0)

Decode a JSON document from s (a str beginning with a JSON document) and return a 2-tuple of the Python representation and the index in s where the document ended.

This can be used to decode a JSON document from a string that may have extraneous data at the end.

class jsontree.JSONTreeEncoder(*args, **kwdargs)[source]

Bases: json.encoder.JSONEncoder

JSON encoder class that serializes out jsontree object structures and datetime objects into ISO strings.

default(obj)[source]

Implement this method in a subclass such that it returns a serializable object for o, or calls the base implementation (to raise a TypeError).

For example, to support arbitrary iterators, you could implement default like this:

def default(self, o):
    try:
        iterable = iter(o)
    except TypeError:
        pass
    else:
        return list(iterable)
    # Let the base class default method raise the TypeError
    return JSONEncoder.default(self, o)
encode(o)

Return a JSON string representation of a Python data structure.

>>> from json.encoder import JSONEncoder
>>> JSONEncoder().encode({"foo": ["bar", "baz"]})
'{"foo": ["bar", "baz"]}'
iterencode(o, _one_shot=False)

Encode the given object and yield each string representation as available.

For example:

for chunk in JSONEncoder().iterencode(bigobject):
    mysocket.write(chunk)
jsontree.clone(root, jsontreecls=<class 'jsontree.jsontree'>, datetimeencoder=<function _datetimeencoder>, datetimedecoder=<function _datetimedecoder>)[source]

Clone an object by first searializing out and then loading it back in.

jsontree.dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=<class 'jsontree.JSONTreeEncoder'>, indent=None, separators=None, encoding='utf-8', default=None, sort_keys=False, **kargs)[source]

JSON serialize to file function that defaults the encoding class to be JSONTreeEncoder

jsontree.dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=<class 'jsontree.JSONTreeEncoder'>, indent=None, separators=None, encoding='utf-8', default=None, sort_keys=False, **kargs)[source]

JSON serialize to string function that defaults the encoding class to be JSONTreeEncoder

class jsontree.jsontree(*args, **kwdargs)[source]

Bases: collections.defaultdict

Default dictionary where keys can be accessed as attributes and new entries recursively default to be this class. This means the following code is valid:

>>> mytree = jsontree()
>>> mytree.something.there = 3
>>> mytree['something']['there'] == 3
True
clear() → None. Remove all items from D.
copy() → a shallow copy of D.
default_factory

Factory for default value called by __missing__().

fromkeys()

Create a new dictionary with keys from iterable and values set to value.

get()

Return the value for key if key is in the dictionary, else default.

items() → a set-like object providing a view on D's items
keys() → a set-like object providing a view on D's keys
pop(k[, d]) → v, remove specified key and return the corresponding value.

If key is not found, d is returned if given, otherwise KeyError is raised

popitem() → (k, v), remove and return some (key, value) pair as a

2-tuple; but raise KeyError if D is empty.

setdefault()

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

update([E, ]**F) → None. Update D from dict/iterable E and F.

If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values() → an object providing a view on D's values
jsontree.load(fp, encoding=None, cls=<class 'jsontree.JSONTreeDecoder'>, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kargs)[source]

JSON load from file function that defaults the loading class to be JSONTreeDecoder

jsontree.loads(s, encoding=None, cls=<class 'jsontree.JSONTreeDecoder'>, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kargs)[source]

JSON load from string function that defaults the loading class to be JSONTreeDecoder

jsontree.mapped_jsontree(mapping, *args, **kwdargs)[source]

Helper function that calls mapped_jsontree_class, and passing the rest of the arguments to the constructor of the new class.

>>> number = mapped_jsontree(dict(one='1', two='2', three='3', four='4'),
...                          {'1': 'something', '2': 'hello'})
>>> number.two
'hello'
>>> list(number.items())
[('1', 'something'), ('2', 'hello')]
jsontree.mapped_jsontree_class(mapping)[source]

Return a class which is a jsontree, but with a supplied attribute name mapping. The mapping argument can be a mapping object (dict, jsontree, etc.) or it can be a callable which takes a single argument (the attribute name), and returns a new name.

This is useful in situations where you have a jsontree with keys that are not valid python attribute names, to simplify communication with a client library, or allow for configurable names.

For example:

>>> numjt = mapped_jsontree_class(dict(one='1', two='2', three='3'))
>>> number = numjt()
>>> number.one = 'something'
>>> dict(number)
{'1': 'something'}

This is very useful for abstracting field names that may change between a development sandbox and production environment. Both FogBugz and Jira bug trackers have custom fields with dynamically generated values. These field names can be abstracted out into a configruation mapping, and the jsontree code can be standardized.

This can also be iseful for JavaScript API’s (PHPCake) which insist on having spaces in some key names. A function can be supplied which maps all ‘_’s in the attribute name to spaces:

>>> spacify = lambda name: name.replace('_', ' ')
>>> spacemapped = mapped_jsontree_class(spacify)
>>> sm = spacemapped()
>>> sm.hello_there = 5
>>> sm.hello_there
5
>>> list(sm.keys())
['hello there']

This will also work with non-string keys for translating from libraries that use object keys in python over to string versions of the keys in JSON

>>> numjt = mapped_jsontree_class(dict(one=1, two=2))
>>> number = numjt()
>>> number.one = 'something'
>>> dict(number)
{1: 'something'}
>>> numjt_as_text = mapped_jsontree_class(dict(one='1', two='2'))
>>> dumped_number = dumps(number)
>>> loaded_number = loads(dumped_number, jsontreecls=numjt_as_text)
>>> str(loaded_number.one)
'something'
>>> repr(dict(loaded_number)).replace('u', '') # cheat the python2 tests
"{'1': 'something'}"

Indices and tables