comparison env/lib/python3.9/site-packages/pip/_vendor/toml/encoder.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 import datetime
2 import re
3 import sys
4 from decimal import Decimal
5
6 from pip._vendor.toml.decoder import InlineTableDict
7
8 if sys.version_info >= (3,):
9 unicode = str
10
11
12 def dump(o, f, encoder=None):
13 """Writes out dict as toml to a file
14
15 Args:
16 o: Object to dump into toml
17 f: File descriptor where the toml should be stored
18 encoder: The ``TomlEncoder`` to use for constructing the output string
19
20 Returns:
21 String containing the toml corresponding to dictionary
22
23 Raises:
24 TypeError: When anything other than file descriptor is passed
25 """
26
27 if not f.write:
28 raise TypeError("You can only dump an object to a file descriptor")
29 d = dumps(o, encoder=encoder)
30 f.write(d)
31 return d
32
33
34 def dumps(o, encoder=None):
35 """Stringifies input dict as toml
36
37 Args:
38 o: Object to dump into toml
39 encoder: The ``TomlEncoder`` to use for constructing the output string
40
41 Returns:
42 String containing the toml corresponding to dict
43
44 Examples:
45 ```python
46 >>> import toml
47 >>> output = {
48 ... 'a': "I'm a string",
49 ... 'b': ["I'm", "a", "list"],
50 ... 'c': 2400
51 ... }
52 >>> toml.dumps(output)
53 'a = "I\'m a string"\nb = [ "I\'m", "a", "list",]\nc = 2400\n'
54 ```
55 """
56
57 retval = ""
58 if encoder is None:
59 encoder = TomlEncoder(o.__class__)
60 addtoretval, sections = encoder.dump_sections(o, "")
61 retval += addtoretval
62 outer_objs = [id(o)]
63 while sections:
64 section_ids = [id(section) for section in sections.values()]
65 for outer_obj in outer_objs:
66 if outer_obj in section_ids:
67 raise ValueError("Circular reference detected")
68 outer_objs += section_ids
69 newsections = encoder.get_empty_table()
70 for section in sections:
71 addtoretval, addtosections = encoder.dump_sections(
72 sections[section], section)
73
74 if addtoretval or (not addtoretval and not addtosections):
75 if retval and retval[-2:] != "\n\n":
76 retval += "\n"
77 retval += "[" + section + "]\n"
78 if addtoretval:
79 retval += addtoretval
80 for s in addtosections:
81 newsections[section + "." + s] = addtosections[s]
82 sections = newsections
83 return retval
84
85
86 def _dump_str(v):
87 if sys.version_info < (3,) and hasattr(v, 'decode') and isinstance(v, str):
88 v = v.decode('utf-8')
89 v = "%r" % v
90 if v[0] == 'u':
91 v = v[1:]
92 singlequote = v.startswith("'")
93 if singlequote or v.startswith('"'):
94 v = v[1:-1]
95 if singlequote:
96 v = v.replace("\\'", "'")
97 v = v.replace('"', '\\"')
98 v = v.split("\\x")
99 while len(v) > 1:
100 i = -1
101 if not v[0]:
102 v = v[1:]
103 v[0] = v[0].replace("\\\\", "\\")
104 # No, I don't know why != works and == breaks
105 joinx = v[0][i] != "\\"
106 while v[0][:i] and v[0][i] == "\\":
107 joinx = not joinx
108 i -= 1
109 if joinx:
110 joiner = "x"
111 else:
112 joiner = "u00"
113 v = [v[0] + joiner + v[1]] + v[2:]
114 return unicode('"' + v[0] + '"')
115
116
117 def _dump_float(v):
118 return "{}".format(v).replace("e+0", "e+").replace("e-0", "e-")
119
120
121 def _dump_time(v):
122 utcoffset = v.utcoffset()
123 if utcoffset is None:
124 return v.isoformat()
125 # The TOML norm specifies that it's local time thus we drop the offset
126 return v.isoformat()[:-6]
127
128
129 class TomlEncoder(object):
130
131 def __init__(self, _dict=dict, preserve=False):
132 self._dict = _dict
133 self.preserve = preserve
134 self.dump_funcs = {
135 str: _dump_str,
136 unicode: _dump_str,
137 list: self.dump_list,
138 bool: lambda v: unicode(v).lower(),
139 int: lambda v: v,
140 float: _dump_float,
141 Decimal: _dump_float,
142 datetime.datetime: lambda v: v.isoformat().replace('+00:00', 'Z'),
143 datetime.time: _dump_time,
144 datetime.date: lambda v: v.isoformat()
145 }
146
147 def get_empty_table(self):
148 return self._dict()
149
150 def dump_list(self, v):
151 retval = "["
152 for u in v:
153 retval += " " + unicode(self.dump_value(u)) + ","
154 retval += "]"
155 return retval
156
157 def dump_inline_table(self, section):
158 """Preserve inline table in its compact syntax instead of expanding
159 into subsection.
160
161 https://github.com/toml-lang/toml#user-content-inline-table
162 """
163 retval = ""
164 if isinstance(section, dict):
165 val_list = []
166 for k, v in section.items():
167 val = self.dump_inline_table(v)
168 val_list.append(k + " = " + val)
169 retval += "{ " + ", ".join(val_list) + " }\n"
170 return retval
171 else:
172 return unicode(self.dump_value(section))
173
174 def dump_value(self, v):
175 # Lookup function corresponding to v's type
176 dump_fn = self.dump_funcs.get(type(v))
177 if dump_fn is None and hasattr(v, '__iter__'):
178 dump_fn = self.dump_funcs[list]
179 # Evaluate function (if it exists) else return v
180 return dump_fn(v) if dump_fn is not None else self.dump_funcs[str](v)
181
182 def dump_sections(self, o, sup):
183 retstr = ""
184 if sup != "" and sup[-1] != ".":
185 sup += '.'
186 retdict = self._dict()
187 arraystr = ""
188 for section in o:
189 section = unicode(section)
190 qsection = section
191 if not re.match(r'^[A-Za-z0-9_-]+$', section):
192 qsection = _dump_str(section)
193 if not isinstance(o[section], dict):
194 arrayoftables = False
195 if isinstance(o[section], list):
196 for a in o[section]:
197 if isinstance(a, dict):
198 arrayoftables = True
199 if arrayoftables:
200 for a in o[section]:
201 arraytabstr = "\n"
202 arraystr += "[[" + sup + qsection + "]]\n"
203 s, d = self.dump_sections(a, sup + qsection)
204 if s:
205 if s[0] == "[":
206 arraytabstr += s
207 else:
208 arraystr += s
209 while d:
210 newd = self._dict()
211 for dsec in d:
212 s1, d1 = self.dump_sections(d[dsec], sup +
213 qsection + "." +
214 dsec)
215 if s1:
216 arraytabstr += ("[" + sup + qsection +
217 "." + dsec + "]\n")
218 arraytabstr += s1
219 for s1 in d1:
220 newd[dsec + "." + s1] = d1[s1]
221 d = newd
222 arraystr += arraytabstr
223 else:
224 if o[section] is not None:
225 retstr += (qsection + " = " +
226 unicode(self.dump_value(o[section])) + '\n')
227 elif self.preserve and isinstance(o[section], InlineTableDict):
228 retstr += (qsection + " = " +
229 self.dump_inline_table(o[section]))
230 else:
231 retdict[qsection] = o[section]
232 retstr += arraystr
233 return (retstr, retdict)
234
235
236 class TomlPreserveInlineDictEncoder(TomlEncoder):
237
238 def __init__(self, _dict=dict):
239 super(TomlPreserveInlineDictEncoder, self).__init__(_dict, True)
240
241
242 class TomlArraySeparatorEncoder(TomlEncoder):
243
244 def __init__(self, _dict=dict, preserve=False, separator=","):
245 super(TomlArraySeparatorEncoder, self).__init__(_dict, preserve)
246 if separator.strip() == "":
247 separator = "," + separator
248 elif separator.strip(' \t\n\r,'):
249 raise ValueError("Invalid separator for arrays")
250 self.separator = separator
251
252 def dump_list(self, v):
253 t = []
254 retval = "["
255 for u in v:
256 t.append(self.dump_value(u))
257 while t != []:
258 s = []
259 for u in t:
260 if isinstance(u, list):
261 for r in u:
262 s.append(r)
263 else:
264 retval += " " + unicode(u) + self.separator
265 t = s
266 retval += "]"
267 return retval
268
269
270 class TomlNumpyEncoder(TomlEncoder):
271
272 def __init__(self, _dict=dict, preserve=False):
273 import numpy as np
274 super(TomlNumpyEncoder, self).__init__(_dict, preserve)
275 self.dump_funcs[np.float16] = _dump_float
276 self.dump_funcs[np.float32] = _dump_float
277 self.dump_funcs[np.float64] = _dump_float
278 self.dump_funcs[np.int16] = self._dump_int
279 self.dump_funcs[np.int32] = self._dump_int
280 self.dump_funcs[np.int64] = self._dump_int
281
282 def _dump_int(self, v):
283 return "{}".format(int(v))
284
285
286 class TomlPreserveCommentEncoder(TomlEncoder):
287
288 def __init__(self, _dict=dict, preserve=False):
289 from pip._vendor.toml.decoder import CommentValue
290 super(TomlPreserveCommentEncoder, self).__init__(_dict, preserve)
291 self.dump_funcs[CommentValue] = lambda v: v.dump(self.dump_value)
292
293
294 class TomlPathlibEncoder(TomlEncoder):
295
296 def _dump_pathlib_path(self, v):
297 return _dump_str(str(v))
298
299 def dump_value(self, v):
300 if (3, 4) <= sys.version_info:
301 import pathlib
302 if isinstance(v, pathlib.PurePath):
303 v = str(v)
304 return super(TomlPathlibEncoder, self).dump_value(v)