123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- import datetime
- import re
- import sys
- from pip._vendor.toml.decoder import InlineTableDict
- if sys.version_info >= (3,):
- unicode = str
- def dump(o, f):
- """Writes out dict as toml to a file
- Args:
- o: Object to dump into toml
- f: File descriptor where the toml should be stored
- Returns:
- String containing the toml corresponding to dictionary
- Raises:
- TypeError: When anything other than file descriptor is passed
- """
- if not f.write:
- raise TypeError("You can only dump an object to a file descriptor")
- d = dumps(o)
- f.write(d)
- return d
- def dumps(o, encoder=None):
- """Stringifies input dict as toml
- Args:
- o: Object to dump into toml
- preserve: Boolean parameter. If true, preserve inline tables.
- Returns:
- String containing the toml corresponding to dict
- """
- retval = ""
- if encoder is None:
- encoder = TomlEncoder(o.__class__)
- addtoretval, sections = encoder.dump_sections(o, "")
- retval += addtoretval
- while sections:
- newsections = encoder.get_empty_table()
- for section in sections:
- addtoretval, addtosections = encoder.dump_sections(
- sections[section], section)
- if addtoretval or (not addtoretval and not addtosections):
- if retval and retval[-2:] != "\n\n":
- retval += "\n"
- retval += "[" + section + "]\n"
- if addtoretval:
- retval += addtoretval
- for s in addtosections:
- newsections[section + "." + s] = addtosections[s]
- sections = newsections
- return retval
- def _dump_str(v):
- if sys.version_info < (3,) and hasattr(v, 'decode') and isinstance(v, str):
- v = v.decode('utf-8')
- v = "%r" % v
- if v[0] == 'u':
- v = v[1:]
- singlequote = v.startswith("'")
- if singlequote or v.startswith('"'):
- v = v[1:-1]
- if singlequote:
- v = v.replace("\\'", "'")
- v = v.replace('"', '\\"')
- v = v.split("\\x")
- while len(v) > 1:
- i = -1
- if not v[0]:
- v = v[1:]
- v[0] = v[0].replace("\\\\", "\\")
- # No, I don't know why != works and == breaks
- joinx = v[0][i] != "\\"
- while v[0][:i] and v[0][i] == "\\":
- joinx = not joinx
- i -= 1
- if joinx:
- joiner = "x"
- else:
- joiner = "u00"
- v = [v[0] + joiner + v[1]] + v[2:]
- return unicode('"' + v[0] + '"')
- def _dump_float(v):
- return "{0:.16}".format(v).replace("e+0", "e+").replace("e-0", "e-")
- def _dump_time(v):
- utcoffset = v.utcoffset()
- if utcoffset is None:
- return v.isoformat()
- # The TOML norm specifies that it's local time thus we drop the offset
- return v.isoformat()[:-6]
- class TomlEncoder(object):
- def __init__(self, _dict=dict, preserve=False):
- self._dict = _dict
- self.preserve = preserve
- self.dump_funcs = {
- str: _dump_str,
- unicode: _dump_str,
- list: self.dump_list,
- bool: lambda v: unicode(v).lower(),
- int: lambda v: v,
- float: _dump_float,
- datetime.datetime: lambda v: v.isoformat().replace('+00:00', 'Z'),
- datetime.time: _dump_time,
- datetime.date: lambda v: v.isoformat()
- }
- def get_empty_table(self):
- return self._dict()
- def dump_list(self, v):
- retval = "["
- for u in v:
- retval += " " + unicode(self.dump_value(u)) + ","
- retval += "]"
- return retval
- def dump_inline_table(self, section):
- """Preserve inline table in its compact syntax instead of expanding
- into subsection.
- https://github.com/toml-lang/toml#user-content-inline-table
- """
- retval = ""
- if isinstance(section, dict):
- val_list = []
- for k, v in section.items():
- val = self.dump_inline_table(v)
- val_list.append(k + " = " + val)
- retval += "{ " + ", ".join(val_list) + " }\n"
- return retval
- else:
- return unicode(self.dump_value(section))
- def dump_value(self, v):
- # Lookup function corresponding to v's type
- dump_fn = self.dump_funcs.get(type(v))
- if dump_fn is None and hasattr(v, '__iter__'):
- dump_fn = self.dump_funcs[list]
- # Evaluate function (if it exists) else return v
- return dump_fn(v) if dump_fn is not None else self.dump_funcs[str](v)
- def dump_sections(self, o, sup):
- retstr = ""
- if sup != "" and sup[-1] != ".":
- sup += '.'
- retdict = self._dict()
- arraystr = ""
- for section in o:
- section = unicode(section)
- qsection = section
- if not re.match(r'^[A-Za-z0-9_-]+$', section):
- if '"' in section:
- qsection = "'" + section + "'"
- else:
- qsection = '"' + section + '"'
- if not isinstance(o[section], dict):
- arrayoftables = False
- if isinstance(o[section], list):
- for a in o[section]:
- if isinstance(a, dict):
- arrayoftables = True
- if arrayoftables:
- for a in o[section]:
- arraytabstr = "\n"
- arraystr += "[[" + sup + qsection + "]]\n"
- s, d = self.dump_sections(a, sup + qsection)
- if s:
- if s[0] == "[":
- arraytabstr += s
- else:
- arraystr += s
- while d:
- newd = self._dict()
- for dsec in d:
- s1, d1 = self.dump_sections(d[dsec], sup +
- qsection + "." +
- dsec)
- if s1:
- arraytabstr += ("[" + sup + qsection +
- "." + dsec + "]\n")
- arraytabstr += s1
- for s1 in d1:
- newd[dsec + "." + s1] = d1[s1]
- d = newd
- arraystr += arraytabstr
- else:
- if o[section] is not None:
- retstr += (qsection + " = " +
- unicode(self.dump_value(o[section])) + '\n')
- elif self.preserve and isinstance(o[section], InlineTableDict):
- retstr += (qsection + " = " +
- self.dump_inline_table(o[section]))
- else:
- retdict[qsection] = o[section]
- retstr += arraystr
- return (retstr, retdict)
- class TomlPreserveInlineDictEncoder(TomlEncoder):
- def __init__(self, _dict=dict):
- super(TomlPreserveInlineDictEncoder, self).__init__(_dict, True)
- class TomlArraySeparatorEncoder(TomlEncoder):
- def __init__(self, _dict=dict, preserve=False, separator=","):
- super(TomlArraySeparatorEncoder, self).__init__(_dict, preserve)
- if separator.strip() == "":
- separator = "," + separator
- elif separator.strip(' \t\n\r,'):
- raise ValueError("Invalid separator for arrays")
- self.separator = separator
- def dump_list(self, v):
- t = []
- retval = "["
- for u in v:
- t.append(self.dump_value(u))
- while t != []:
- s = []
- for u in t:
- if isinstance(u, list):
- for r in u:
- s.append(r)
- else:
- retval += " " + unicode(u) + self.separator
- t = s
- retval += "]"
- return retval
|