Example #1
0
def loads(s, **kwargs):
    """
    Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
    document) to a Python object.
    """
    if not isinstance(s, string_type):
        raise TypeError("Expected s to be a str, got %s" % type(s))

    try:
        fp = unicodeIO(s)
    except TypeError:
        fp = strIO(s)

    return parse(fp, **kwargs)
Example #2
0
def loads(s, **kwargs):
    """
    Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
    document) to a Python object.
    """
    if not isinstance(s, string_type):
        raise TypeError("Expected s to be a str, got %s" % type(s))

    try:
        fp = unicodeIO(s)
    except TypeError:
        fp = strIO(s)

    return parse(fp, **kwargs)
Example #3
0
def parse(source, mapper=dict):
    """
    Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a VDF)
    to a Python object.

    ``mapper`` specifies the Python object used after deserializetion. ``dict` is
    used by default. Alternatively, ``collections.OrderedDict`` can be used if you
    wish to preserve key order. Or any object that acts like a ``dict``.
    """
    if not issubclass(mapper, dict):
        raise TypeError("Expected mapper to be subclass of dict, got %s", type(mapper))
    if hasattr(source, "read"):
        fp = source
    elif isinstance(source, string_type):
        try:
            fp = unicodeIO(source)
        except TypeError:
            fp = strIO(source)
    else:
        raise TypeError("Expected source to be str or file-like object")

    # skip past BOMs
    fp.seek(bomlen(fp.read(10)))

    # init
    stack = [mapper()]
    expect_bracket = False

    re_keyvalue = re.compile(
        r'^("(?P<qkey>(?:\\.|[^\\"])+)"|(?P<key>[a-z0-9\-\_]+))'
        r"([ \t]*("
        r'"(?P<qval>(?:\\.|[^\\"])*)(?P<vq_end>")?'
        r"|(?P<val>[a-z0-9\-\_]+)"
        r"))?",
        flags=re.I,
    )

    for line in fp:
        line = line.lstrip()

        # skip empty and comment lines
        if line == "" or line[0] == "/":
            continue

        # one level deeper
        if line[0] == "{":
            expect_bracket = False
            continue

        if expect_bracket:
            raise SyntaxError("vdf.parse: expected openning bracket")

        # one level back
        if line[0] == "}":
            if len(stack) > 1:
                stack.pop()
                continue

            raise SyntaxError("vdf.parse: one too many closing parenthasis")

        # parse keyvalue pairs
        while True:
            match = re_keyvalue.match(line)

            if not match:
                raise SyntaxError("vdf.parse: invalid syntax")

            key = match.group("key") if match.group("qkey") is None else match.group("qkey")
            val = match.group("val") if match.group("qval") is None else match.group("qval")

            # we have a key with value in parenthesis, so we make a new dict obj (level deeper)
            if val is None:
                stack[-1][key] = mapper()
                stack.append(stack[-1][key])
                expect_bracket = True

            # we've matched a simple keyvalue pair, map it to the last dict obj in the stack
            else:
                # if the value is line consume one more line and try to match again,
                # until we get the KeyValue pair
                if match.group("vq_end") is None and match.group("qval") is not None:
                    line += next(fp)
                    continue

                stack[-1][key] = val

            # exit the loop
            break

    if len(stack) != 1:
        raise SyntaxError("vdf.parse: unclosed parenthasis or quotes")

    return stack.pop()
Example #4
0
def parse(source, mapper=dict):
    """
    Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a VDF)
    to a Python object.

    ``mapper`` specifies the Python object used after deserializetion. ``dict` is
    used by default. Alternatively, ``collections.OrderedDict`` can be used if you
    wish to preserve key order. Or any object that acts like a ``dict``.
    """
    if not issubclass(mapper, dict):
        raise TypeError("Expected mapper to be subclass of dict, got %s", type(mapper))
    if hasattr(source, 'read'):
        fp = source
    elif isinstance(source, string_type):
        try:
            fp = unicodeIO(source)
        except TypeError:
            fp = strIO(source)
    else:
        raise TypeError("Expected source to be str or file-like object")

    # skip past BOMs
    fp.seek(bomlen(fp.read(10)))

    # init
    stack = [mapper()]
    expect_bracket = False

    re_keyvalue = re.compile(r'^("(?P<qkey>(?:\\.|[^\\"])+)"|(?P<key>[a-z0-9\-\_]+))'
                             r'([ \t]*('
                             r'"(?P<qval>(?:\\.|[^\\"])*)(?P<vq_end>")?'
                             r'|(?P<val>[a-z0-9\-\_]+)'
                             r'))?',
                             flags=re.I
                             )

    for line in fp:
        line = line.lstrip()

        # skip empty and comment lines
        if line == "" or line[0] == '/':
            continue

        # one level deeper
        if line[0] == "{":
            expect_bracket = False
            continue

        if expect_bracket:
            raise SyntaxError("vdf.parse: expected openning bracket")

        # one level back
        if line[0] == "}":
            if len(stack) > 1:
                stack.pop()
                continue

            raise SyntaxError("vdf.parse: one too many closing parenthasis")

        # parse keyvalue pairs
        while True:
            match = re_keyvalue.match(line)

            if not match:
                raise SyntaxError("vdf.parse: invalid syntax")

            key = match.group('key') if match.group('qkey') is None else match.group('qkey')
            val = match.group('val') if match.group('qval') is None else match.group('qval')

            # we have a key with value in parenthesis, so we make a new dict obj (level deeper)
            if val is None:
                stack[-1][key] = mapper()
                stack.append(stack[-1][key])
                expect_bracket = True

            # we've matched a simple keyvalue pair, map it to the last dict obj in the stack
            else:
                # if the value is line consume one more line and try to match again,
                # until we get the KeyValue pair
                if match.group('vq_end') is None and match.group('qval') is not None:
                    line += next(fp)
                    continue

                stack[-1][key] = val

            # exit the loop
            break

    if len(stack) != 1:
        raise SyntaxError("vdf.parse: unclosed parenthasis or quotes")

    return stack.pop()