Source code for athlib.jsondict

"""Utilities for working with JSON and json-like structures - deeply nested
Python dicts and lists.

This lets us iterate over child nodes and access elements with a dot-notation.
"""


class MyLocals(object):
    pass


mylocals = MyLocals()


def setErrorCollect(collect):
    mylocals.error_collect = collect


setErrorCollect(False)


def errorValue(x):
    if isinstance(x, (str, unicode)):
        return repr(x) if ' ' in x else x

    return 'None' if x is None else str(x)


def condJSON(v, __name__=''):
    if isinstance(v, dict):
        return JSONDict(v, __name__=__name__)
    elif isinstance(v, list):
        return JSONList(v, __name__=__name__)
    else:
        return v


def condJSONSafe(v, __name__=''):
    if isinstance(v, dict):
        return JSONDictSafe(v, __name__=__name__)
    elif isinstance(v, list):
        return JSONListSafe(v, __name__=__name__)
    else:
        return v


class JSONListIter(object):
    def __init__(self, lst, conv):
        self.lst = lst
        self.i = -1
        self.conv = conv

    def __iter__(self):
        return self

    def next(self):
        if self.i < len(self.lst) - 1:
            self.i += 1
            return self.conv(self.lst[self.i])
        else:
            raise StopIteration


class JSONList(list):
    def __init__(self, v, __name__=''):
        list.__init__(self, v)
        self.__name__ = __name__

    def __getitem__(self, x):
        return condJSON(list.__getitem__(self, x),
                        __name__='%s\t%s' % (self.__name__, errorValue(x)))

    def __iter__(self):
        return JSONListIter(self, condJSON)


class JSONListSafe(JSONList):
    def __getitem__(self, x):
        __name__ = '%s\t%s' % (self.__name__, errorValue(x))

        try:
            return condJSONSafe(list.__getitem__(self, x), __name__=__name__)
        except KeyError:
            if mylocals.error_collect:
                mylocals.error_collect(__name__)

            return JSONStrSafe('')

    def __iter__(self):
        return JSONListIter(self, condJSONSafe)


class JSONStrSafe(str):
    def __getattr__(self, attr):
        return self

    __getitem__ = __getattr__


[docs]class JSONDict(dict): "Allows dotted access" def __new__(cls, v={}, __name__=''): self = dict.__new__(cls, v) self.__name__ = __name__ return self def __getattr__(self, attr, default=None): if attr in self: return condJSON(self[attr], __name__='%s\t%s' % (self.__name__, errorValue(attr))) elif unicode(attr) in self: return condJSON(self[unicode(attr)], __name__='%s\t%s' % (self.__name__, errorValue(attr))) elif attr == '__safe__': return JSONDictSafe(self, __name__=self.__name__) else: raise AttributeError("No attribute or key named '%s'" % attr) def sorted_items(self): return sorted([(k, condJSON(v)) for k, v in self.iteritems()]) def sorted_keys(self): return sorted(self.keys())
[docs]class JSONDictSafe(JSONDict): "Allows dotted access" def __getattr__(self, attr, default=None): if attr in self: return condJSONSafe(self[attr], __name__='%s\t%s' % (self.__name__, errorValue(attr))) elif unicode(attr) in self: return condJSONSafe(self[unicode(attr)], __name__='%s\t%s' % (self.__name__, errorValue(attr))) elif attr == '__safe__': return self else: return JSONStrSafe('') def __getitem__(self, x): __name__ = '%s\t%s' % (self.__name__, errorValue(x)) try: return condJSONSafe(dict.__getitem__(self, x), __name__=__name__) except KeyError: if mylocals.error_collect: mylocals.error_collect(__name__) return JSONStrSafe('') def sorted_items(self): return sorted([(k, condJSONSafe(v)) for k, v in self.iteritems()])