1111# Py2 & Py3 compability
1212if sys .version_info [0 ] >= 3 :
1313 string_type = str
14+ iter_items = 'items'
1415 BOMS = '\ufffe \ufeff '
1516
1617 def bomlen (line ):
@@ -21,6 +22,7 @@ def bomlen(line):
2122 except ImportError :
2223 from StringIO import StringIO as strIO
2324 string_type = basestring
25+ iter_items = 'iteritems'
2426 BOMS = '\xef \xbb \xbf \xff \xfe \xfe \xff '
2527 BOMS_UNICODE = '\\ ufffe\\ ufeff' .decode ('unicode-escape' )
2628
@@ -55,6 +57,7 @@ def parse(source, mapper=dict):
5557 # init
5658 obj = mapper ()
5759 stack = [obj ]
60+ parent_key = None
5861 expect_bracket = False
5962
6063 re_keyvalue = re .compile (r'^"(?P<key>(?:\\.|[^\\"])*)"'
@@ -93,11 +96,21 @@ def parse(source, mapper=dict):
9396 if not match :
9497 raise SyntaxError ("vdf.parse: invalid syntax" )
9598
99+ key = match .group ('key' )
100+ value = match .group ('value' )
101+ parent = stack [- 1 ]
102+
103+ # if first subkey is '0' assume this an array
104+ # and turn tha parrent into a list
105+ if len (parent ) == 0 and key == "0" :
106+ parent = stack [- 1 ] = list ()
107+ if parent_key is not None :
108+ stack [- 2 ][parent_key ] = parent
109+
96110 # we have a key with value in parenthesis, so we make a new dict obj (level deeper)
97- if match .group ('value' ) is None :
98- key = match .group ('key' )
99- stack [- 1 ][key ] = mapper ()
100- stack .append (stack [- 1 ][key ])
111+ if value is None :
112+ value = mapper ()
113+ stack .append (value )
101114 expect_bracket = True
102115
103116 # we've matched a simple keyvalue pair, map it to the last dict obj in the stack
@@ -108,15 +121,20 @@ def parse(source, mapper=dict):
108121 line += "\n " + next (fp ).rstrip ()
109122 continue
110123
111- stack [- 1 ][match .group ('key' )] = match .group ('value' )
124+ if isinstance (parent , list ):
125+ parent .append (value )
126+ parent_key = len (parent ) - 1
127+ else :
128+ parent [key ] = value
129+ parent_key = key
112130
113131 # exit the loop
114132 break
115133
116134 if len (stack ) != 1 :
117135 raise SyntaxError ("vdf.parse: unclosed parenthasis or quotes" )
118136
119- return obj
137+ return stack . pop ()
120138
121139
122140def loads (fp , ** kwargs ):
@@ -141,8 +159,8 @@ def dumps(data, pretty=False):
141159 """
142160 Serialize ``obj`` to VDF formatted ``str``.
143161 """
144- if not isinstance (data , dict ):
145- raise TypeError ("Expected data to be a dict or subclass of dict " )
162+ if not isinstance (data , ( dict , list ) ):
163+ raise TypeError ("Expected data to be an instance of`` dict`` or ``list`` " )
146164 if not isinstance (pretty , bool ):
147165 raise TypeError ("Expected pretty to be bool" )
148166
@@ -154,8 +172,8 @@ def dump(data, fp, pretty=False):
154172 Serialize ``obj`` as a VDF formatted stream to ``fp`` (a
155173 ``.write()``-supporting file-like object).
156174 """
157- if not isinstance (data , dict ):
158- raise TypeError ("Expected data to be a dict" )
175+ if not isinstance (data , ( dict , list ) ):
176+ raise TypeError ("Expected data to be an instance of`` dict`` or ``list`` " )
159177 if not hasattr (fp , 'write' ):
160178 raise TypeError ("Expected fp to have write() method" )
161179
@@ -170,8 +188,13 @@ def _dump_gen(data, pretty=False, level=0):
170188 if pretty :
171189 line_indent = indent * level
172190
173- for key , value in data .items ():
174- if isinstance (value , dict ):
191+ if isinstance (data , list ):
192+ itr = enumerate (data )
193+ else :
194+ itr = getattr (data , iter_items )()
195+
196+ for key , value in itr :
197+ if isinstance (value , (dict , list )):
175198 yield '%s"%s"\n %s{\n ' % (line_indent , key , line_indent )
176199 for chunk in _dump_gen (value , pretty , level + 1 ):
177200 yield chunk
0 commit comments