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)
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()
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()