Initial commit
This commit is contained in:
21
venv/lib/python3.8/site-packages/toml/__init__.py
Normal file
21
venv/lib/python3.8/site-packages/toml/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""Python module which parses and emits TOML.
|
||||
|
||||
Released under the MIT license.
|
||||
"""
|
||||
|
||||
from toml import encoder
|
||||
from toml import decoder
|
||||
|
||||
__version__ = "0.10.0"
|
||||
_spec_ = "0.5.0"
|
||||
|
||||
load = decoder.load
|
||||
loads = decoder.loads
|
||||
TomlDecoder = decoder.TomlDecoder
|
||||
TomlDecodeError = decoder.TomlDecodeError
|
||||
|
||||
dump = encoder.dump
|
||||
dumps = encoder.dumps
|
||||
TomlEncoder = encoder.TomlEncoder
|
||||
TomlArraySeparatorEncoder = encoder.TomlArraySeparatorEncoder
|
||||
TomlPreserveInlineDictEncoder = encoder.TomlPreserveInlineDictEncoder
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
945
venv/lib/python3.8/site-packages/toml/decoder.py
Normal file
945
venv/lib/python3.8/site-packages/toml/decoder.py
Normal file
@@ -0,0 +1,945 @@
|
||||
import datetime
|
||||
import io
|
||||
from os import linesep
|
||||
import re
|
||||
import sys
|
||||
|
||||
from toml.tz import TomlTz
|
||||
|
||||
if sys.version_info < (3,):
|
||||
_range = xrange # noqa: F821
|
||||
else:
|
||||
unicode = str
|
||||
_range = range
|
||||
basestring = str
|
||||
unichr = chr
|
||||
|
||||
|
||||
def _detect_pathlib_path(p):
|
||||
if (3, 4) <= sys.version_info:
|
||||
import pathlib
|
||||
if isinstance(p, pathlib.PurePath):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _ispath(p):
|
||||
if isinstance(p, basestring):
|
||||
return True
|
||||
return _detect_pathlib_path(p)
|
||||
|
||||
|
||||
def _getpath(p):
|
||||
if (3, 6) <= sys.version_info:
|
||||
import os
|
||||
return os.fspath(p)
|
||||
if _detect_pathlib_path(p):
|
||||
return str(p)
|
||||
return p
|
||||
|
||||
|
||||
try:
|
||||
FNFError = FileNotFoundError
|
||||
except NameError:
|
||||
FNFError = IOError
|
||||
|
||||
|
||||
TIME_RE = re.compile("([0-9]{2}):([0-9]{2}):([0-9]{2})(\.([0-9]{3,6}))?")
|
||||
|
||||
|
||||
class TomlDecodeError(ValueError):
|
||||
"""Base toml Exception / Error."""
|
||||
|
||||
def __init__(self, msg, doc, pos):
|
||||
lineno = doc.count('\n', 0, pos) + 1
|
||||
colno = pos - doc.rfind('\n', 0, pos)
|
||||
emsg = '{} (line {} column {} char {})'.format(msg, lineno, colno, pos)
|
||||
ValueError.__init__(self, emsg)
|
||||
self.msg = msg
|
||||
self.doc = doc
|
||||
self.pos = pos
|
||||
self.lineno = lineno
|
||||
self.colno = colno
|
||||
|
||||
|
||||
# Matches a TOML number, which allows underscores for readability
|
||||
_number_with_underscores = re.compile('([0-9])(_([0-9]))*')
|
||||
|
||||
|
||||
def _strictly_valid_num(n):
|
||||
n = n.strip()
|
||||
if not n:
|
||||
return False
|
||||
if n[0] == '_':
|
||||
return False
|
||||
if n[-1] == '_':
|
||||
return False
|
||||
if "_." in n or "._" in n:
|
||||
return False
|
||||
if len(n) == 1:
|
||||
return True
|
||||
if n[0] == '0' and n[1] not in ['.', 'o', 'b', 'x']:
|
||||
return False
|
||||
if n[0] == '+' or n[0] == '-':
|
||||
n = n[1:]
|
||||
if len(n) > 1 and n[0] == '0' and n[1] != '.':
|
||||
return False
|
||||
if '__' in n:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def load(f, _dict=dict, decoder=None):
|
||||
"""Parses named file or files as toml and returns a dictionary
|
||||
|
||||
Args:
|
||||
f: Path to the file to open, array of files to read into single dict
|
||||
or a file descriptor
|
||||
_dict: (optional) Specifies the class of the returned toml dictionary
|
||||
|
||||
Returns:
|
||||
Parsed toml file represented as a dictionary
|
||||
|
||||
Raises:
|
||||
TypeError -- When f is invalid type
|
||||
TomlDecodeError: Error while decoding toml
|
||||
IOError / FileNotFoundError -- When an array with no valid (existing)
|
||||
(Python 2 / Python 3) file paths is passed
|
||||
"""
|
||||
|
||||
if _ispath(f):
|
||||
with io.open(_getpath(f), encoding='utf-8') as ffile:
|
||||
return loads(ffile.read(), _dict, decoder)
|
||||
elif isinstance(f, list):
|
||||
from os import path as op
|
||||
from warnings import warn
|
||||
if not [path for path in f if op.exists(path)]:
|
||||
error_msg = "Load expects a list to contain filenames only."
|
||||
error_msg += linesep
|
||||
error_msg += ("The list needs to contain the path of at least one "
|
||||
"existing file.")
|
||||
raise FNFError(error_msg)
|
||||
if decoder is None:
|
||||
decoder = TomlDecoder()
|
||||
d = decoder.get_empty_table()
|
||||
for l in f:
|
||||
if op.exists(l):
|
||||
d.update(load(l, _dict, decoder))
|
||||
else:
|
||||
warn("Non-existent filename in list with at least one valid "
|
||||
"filename")
|
||||
return d
|
||||
else:
|
||||
try:
|
||||
return loads(f.read(), _dict, decoder)
|
||||
except AttributeError:
|
||||
raise TypeError("You can only load a file descriptor, filename or "
|
||||
"list")
|
||||
|
||||
|
||||
_groupname_re = re.compile(r'^[A-Za-z0-9_-]+$')
|
||||
|
||||
|
||||
def loads(s, _dict=dict, decoder=None):
|
||||
"""Parses string as toml
|
||||
|
||||
Args:
|
||||
s: String to be parsed
|
||||
_dict: (optional) Specifies the class of the returned toml dictionary
|
||||
|
||||
Returns:
|
||||
Parsed toml file represented as a dictionary
|
||||
|
||||
Raises:
|
||||
TypeError: When a non-string is passed
|
||||
TomlDecodeError: Error while decoding toml
|
||||
"""
|
||||
|
||||
implicitgroups = []
|
||||
if decoder is None:
|
||||
decoder = TomlDecoder(_dict)
|
||||
retval = decoder.get_empty_table()
|
||||
currentlevel = retval
|
||||
if not isinstance(s, basestring):
|
||||
raise TypeError("Expecting something like a string")
|
||||
|
||||
if not isinstance(s, unicode):
|
||||
s = s.decode('utf8')
|
||||
|
||||
original = s
|
||||
sl = list(s)
|
||||
openarr = 0
|
||||
openstring = False
|
||||
openstrchar = ""
|
||||
multilinestr = False
|
||||
arrayoftables = False
|
||||
beginline = True
|
||||
keygroup = False
|
||||
dottedkey = False
|
||||
keyname = 0
|
||||
for i, item in enumerate(sl):
|
||||
if item == '\r' and sl[i + 1] == '\n':
|
||||
sl[i] = ' '
|
||||
continue
|
||||
if keyname:
|
||||
if item == '\n':
|
||||
raise TomlDecodeError("Key name found without value."
|
||||
" Reached end of line.", original, i)
|
||||
if openstring:
|
||||
if item == openstrchar:
|
||||
keyname = 2
|
||||
openstring = False
|
||||
openstrchar = ""
|
||||
continue
|
||||
elif keyname == 1:
|
||||
if item.isspace():
|
||||
keyname = 2
|
||||
continue
|
||||
elif item == '.':
|
||||
dottedkey = True
|
||||
continue
|
||||
elif item.isalnum() or item == '_' or item == '-':
|
||||
continue
|
||||
elif (dottedkey and sl[i - 1] == '.' and
|
||||
(item == '"' or item == "'")):
|
||||
openstring = True
|
||||
openstrchar = item
|
||||
continue
|
||||
elif keyname == 2:
|
||||
if item.isspace():
|
||||
if dottedkey:
|
||||
nextitem = sl[i + 1]
|
||||
if not nextitem.isspace() and nextitem != '.':
|
||||
keyname = 1
|
||||
continue
|
||||
if item == '.':
|
||||
dottedkey = True
|
||||
nextitem = sl[i + 1]
|
||||
if not nextitem.isspace() and nextitem != '.':
|
||||
keyname = 1
|
||||
continue
|
||||
if item == '=':
|
||||
keyname = 0
|
||||
dottedkey = False
|
||||
else:
|
||||
raise TomlDecodeError("Found invalid character in key name: '" +
|
||||
item + "'. Try quoting the key name.",
|
||||
original, i)
|
||||
if item == "'" and openstrchar != '"':
|
||||
k = 1
|
||||
try:
|
||||
while sl[i - k] == "'":
|
||||
k += 1
|
||||
if k == 3:
|
||||
break
|
||||
except IndexError:
|
||||
pass
|
||||
if k == 3:
|
||||
multilinestr = not multilinestr
|
||||
openstring = multilinestr
|
||||
else:
|
||||
openstring = not openstring
|
||||
if openstring:
|
||||
openstrchar = "'"
|
||||
else:
|
||||
openstrchar = ""
|
||||
if item == '"' and openstrchar != "'":
|
||||
oddbackslash = False
|
||||
k = 1
|
||||
tripquote = False
|
||||
try:
|
||||
while sl[i - k] == '"':
|
||||
k += 1
|
||||
if k == 3:
|
||||
tripquote = True
|
||||
break
|
||||
if k == 1 or (k == 3 and tripquote):
|
||||
while sl[i - k] == '\\':
|
||||
oddbackslash = not oddbackslash
|
||||
k += 1
|
||||
except IndexError:
|
||||
pass
|
||||
if not oddbackslash:
|
||||
if tripquote:
|
||||
multilinestr = not multilinestr
|
||||
openstring = multilinestr
|
||||
else:
|
||||
openstring = not openstring
|
||||
if openstring:
|
||||
openstrchar = '"'
|
||||
else:
|
||||
openstrchar = ""
|
||||
if item == '#' and (not openstring and not keygroup and
|
||||
not arrayoftables):
|
||||
j = i
|
||||
try:
|
||||
while sl[j] != '\n':
|
||||
sl[j] = ' '
|
||||
j += 1
|
||||
except IndexError:
|
||||
break
|
||||
if item == '[' and (not openstring and not keygroup and
|
||||
not arrayoftables):
|
||||
if beginline:
|
||||
if len(sl) > i + 1 and sl[i + 1] == '[':
|
||||
arrayoftables = True
|
||||
else:
|
||||
keygroup = True
|
||||
else:
|
||||
openarr += 1
|
||||
if item == ']' and not openstring:
|
||||
if keygroup:
|
||||
keygroup = False
|
||||
elif arrayoftables:
|
||||
if sl[i - 1] == ']':
|
||||
arrayoftables = False
|
||||
else:
|
||||
openarr -= 1
|
||||
if item == '\n':
|
||||
if openstring or multilinestr:
|
||||
if not multilinestr:
|
||||
raise TomlDecodeError("Unbalanced quotes", original, i)
|
||||
if ((sl[i - 1] == "'" or sl[i - 1] == '"') and (
|
||||
sl[i - 2] == sl[i - 1])):
|
||||
sl[i] = sl[i - 1]
|
||||
if sl[i - 3] == sl[i - 1]:
|
||||
sl[i - 3] = ' '
|
||||
elif openarr:
|
||||
sl[i] = ' '
|
||||
else:
|
||||
beginline = True
|
||||
elif beginline and sl[i] != ' ' and sl[i] != '\t':
|
||||
beginline = False
|
||||
if not keygroup and not arrayoftables:
|
||||
if sl[i] == '=':
|
||||
raise TomlDecodeError("Found empty keyname. ", original, i)
|
||||
keyname = 1
|
||||
s = ''.join(sl)
|
||||
s = s.split('\n')
|
||||
multikey = None
|
||||
multilinestr = ""
|
||||
multibackslash = False
|
||||
pos = 0
|
||||
for idx, line in enumerate(s):
|
||||
if idx > 0:
|
||||
pos += len(s[idx - 1]) + 1
|
||||
if not multilinestr or multibackslash or '\n' not in multilinestr:
|
||||
line = line.strip()
|
||||
if line == "" and (not multikey or multibackslash):
|
||||
continue
|
||||
if multikey:
|
||||
if multibackslash:
|
||||
multilinestr += line
|
||||
else:
|
||||
multilinestr += line
|
||||
multibackslash = False
|
||||
if len(line) > 2 and (line[-1] == multilinestr[0] and
|
||||
line[-2] == multilinestr[0] and
|
||||
line[-3] == multilinestr[0]):
|
||||
try:
|
||||
value, vtype = decoder.load_value(multilinestr)
|
||||
except ValueError as err:
|
||||
raise TomlDecodeError(str(err), original, pos)
|
||||
currentlevel[multikey] = value
|
||||
multikey = None
|
||||
multilinestr = ""
|
||||
else:
|
||||
k = len(multilinestr) - 1
|
||||
while k > -1 and multilinestr[k] == '\\':
|
||||
multibackslash = not multibackslash
|
||||
k -= 1
|
||||
if multibackslash:
|
||||
multilinestr = multilinestr[:-1]
|
||||
else:
|
||||
multilinestr += "\n"
|
||||
continue
|
||||
if line[0] == '[':
|
||||
arrayoftables = False
|
||||
if len(line) == 1:
|
||||
raise TomlDecodeError("Opening key group bracket on line by "
|
||||
"itself.", original, pos)
|
||||
if line[1] == '[':
|
||||
arrayoftables = True
|
||||
line = line[2:]
|
||||
splitstr = ']]'
|
||||
else:
|
||||
line = line[1:]
|
||||
splitstr = ']'
|
||||
i = 1
|
||||
quotesplits = decoder._get_split_on_quotes(line)
|
||||
quoted = False
|
||||
for quotesplit in quotesplits:
|
||||
if not quoted and splitstr in quotesplit:
|
||||
break
|
||||
i += quotesplit.count(splitstr)
|
||||
quoted = not quoted
|
||||
line = line.split(splitstr, i)
|
||||
if len(line) < i + 1 or line[-1].strip() != "":
|
||||
raise TomlDecodeError("Key group not on a line by itself.",
|
||||
original, pos)
|
||||
groups = splitstr.join(line[:-1]).split('.')
|
||||
i = 0
|
||||
while i < len(groups):
|
||||
groups[i] = groups[i].strip()
|
||||
if len(groups[i]) > 0 and (groups[i][0] == '"' or
|
||||
groups[i][0] == "'"):
|
||||
groupstr = groups[i]
|
||||
j = i + 1
|
||||
while not groupstr[0] == groupstr[-1]:
|
||||
j += 1
|
||||
if j > len(groups) + 2:
|
||||
raise TomlDecodeError("Invalid group name '" +
|
||||
groupstr + "' Something " +
|
||||
"went wrong.", original, pos)
|
||||
groupstr = '.'.join(groups[i:j]).strip()
|
||||
groups[i] = groupstr[1:-1]
|
||||
groups[i + 1:j] = []
|
||||
else:
|
||||
if not _groupname_re.match(groups[i]):
|
||||
raise TomlDecodeError("Invalid group name '" +
|
||||
groups[i] + "'. Try quoting it.",
|
||||
original, pos)
|
||||
i += 1
|
||||
currentlevel = retval
|
||||
for i in _range(len(groups)):
|
||||
group = groups[i]
|
||||
if group == "":
|
||||
raise TomlDecodeError("Can't have a keygroup with an empty "
|
||||
"name", original, pos)
|
||||
try:
|
||||
currentlevel[group]
|
||||
if i == len(groups) - 1:
|
||||
if group in implicitgroups:
|
||||
implicitgroups.remove(group)
|
||||
if arrayoftables:
|
||||
raise TomlDecodeError("An implicitly defined "
|
||||
"table can't be an array",
|
||||
original, pos)
|
||||
elif arrayoftables:
|
||||
currentlevel[group].append(decoder.get_empty_table()
|
||||
)
|
||||
else:
|
||||
raise TomlDecodeError("What? " + group +
|
||||
" already exists?" +
|
||||
str(currentlevel),
|
||||
original, pos)
|
||||
except TypeError:
|
||||
currentlevel = currentlevel[-1]
|
||||
if group not in currentlevel:
|
||||
currentlevel[group] = decoder.get_empty_table()
|
||||
if i == len(groups) - 1 and arrayoftables:
|
||||
currentlevel[group] = [decoder.get_empty_table()]
|
||||
except KeyError:
|
||||
if i != len(groups) - 1:
|
||||
implicitgroups.append(group)
|
||||
currentlevel[group] = decoder.get_empty_table()
|
||||
if i == len(groups) - 1 and arrayoftables:
|
||||
currentlevel[group] = [decoder.get_empty_table()]
|
||||
currentlevel = currentlevel[group]
|
||||
if arrayoftables:
|
||||
try:
|
||||
currentlevel = currentlevel[-1]
|
||||
except KeyError:
|
||||
pass
|
||||
elif line[0] == "{":
|
||||
if line[-1] != "}":
|
||||
raise TomlDecodeError("Line breaks are not allowed in inline"
|
||||
"objects", original, pos)
|
||||
try:
|
||||
decoder.load_inline_object(line, currentlevel, multikey,
|
||||
multibackslash)
|
||||
except ValueError as err:
|
||||
raise TomlDecodeError(str(err), original, pos)
|
||||
elif "=" in line:
|
||||
try:
|
||||
ret = decoder.load_line(line, currentlevel, multikey,
|
||||
multibackslash)
|
||||
except ValueError as err:
|
||||
raise TomlDecodeError(str(err), original, pos)
|
||||
if ret is not None:
|
||||
multikey, multilinestr, multibackslash = ret
|
||||
return retval
|
||||
|
||||
|
||||
def _load_date(val):
|
||||
microsecond = 0
|
||||
tz = None
|
||||
try:
|
||||
if len(val) > 19:
|
||||
if val[19] == '.':
|
||||
if val[-1].upper() == 'Z':
|
||||
subsecondval = val[20:-1]
|
||||
tzval = "Z"
|
||||
else:
|
||||
subsecondvalandtz = val[20:]
|
||||
if '+' in subsecondvalandtz:
|
||||
splitpoint = subsecondvalandtz.index('+')
|
||||
subsecondval = subsecondvalandtz[:splitpoint]
|
||||
tzval = subsecondvalandtz[splitpoint:]
|
||||
elif '-' in subsecondvalandtz:
|
||||
splitpoint = subsecondvalandtz.index('-')
|
||||
subsecondval = subsecondvalandtz[:splitpoint]
|
||||
tzval = subsecondvalandtz[splitpoint:]
|
||||
else:
|
||||
tzval = None
|
||||
subsecondval = subsecondvalandtz
|
||||
if tzval is not None:
|
||||
tz = TomlTz(tzval)
|
||||
microsecond = int(int(subsecondval) *
|
||||
(10 ** (6 - len(subsecondval))))
|
||||
else:
|
||||
tz = TomlTz(val[19:])
|
||||
except ValueError:
|
||||
tz = None
|
||||
if "-" not in val[1:]:
|
||||
return None
|
||||
try:
|
||||
if len(val) == 10:
|
||||
d = datetime.date(
|
||||
int(val[:4]), int(val[5:7]),
|
||||
int(val[8:10]))
|
||||
else:
|
||||
d = datetime.datetime(
|
||||
int(val[:4]), int(val[5:7]),
|
||||
int(val[8:10]), int(val[11:13]),
|
||||
int(val[14:16]), int(val[17:19]), microsecond, tz)
|
||||
except ValueError:
|
||||
return None
|
||||
return d
|
||||
|
||||
|
||||
def _load_unicode_escapes(v, hexbytes, prefix):
|
||||
skip = False
|
||||
i = len(v) - 1
|
||||
while i > -1 and v[i] == '\\':
|
||||
skip = not skip
|
||||
i -= 1
|
||||
for hx in hexbytes:
|
||||
if skip:
|
||||
skip = False
|
||||
i = len(hx) - 1
|
||||
while i > -1 and hx[i] == '\\':
|
||||
skip = not skip
|
||||
i -= 1
|
||||
v += prefix
|
||||
v += hx
|
||||
continue
|
||||
hxb = ""
|
||||
i = 0
|
||||
hxblen = 4
|
||||
if prefix == "\\U":
|
||||
hxblen = 8
|
||||
hxb = ''.join(hx[i:i + hxblen]).lower()
|
||||
if hxb.strip('0123456789abcdef'):
|
||||
raise ValueError("Invalid escape sequence: " + hxb)
|
||||
if hxb[0] == "d" and hxb[1].strip('01234567'):
|
||||
raise ValueError("Invalid escape sequence: " + hxb +
|
||||
". Only scalar unicode points are allowed.")
|
||||
v += unichr(int(hxb, 16))
|
||||
v += unicode(hx[len(hxb):])
|
||||
return v
|
||||
|
||||
|
||||
# Unescape TOML string values.
|
||||
|
||||
# content after the \
|
||||
_escapes = ['0', 'b', 'f', 'n', 'r', 't', '"']
|
||||
# What it should be replaced by
|
||||
_escapedchars = ['\0', '\b', '\f', '\n', '\r', '\t', '\"']
|
||||
# Used for substitution
|
||||
_escape_to_escapedchars = dict(zip(_escapes, _escapedchars))
|
||||
|
||||
|
||||
def _unescape(v):
|
||||
"""Unescape characters in a TOML string."""
|
||||
i = 0
|
||||
backslash = False
|
||||
while i < len(v):
|
||||
if backslash:
|
||||
backslash = False
|
||||
if v[i] in _escapes:
|
||||
v = v[:i - 1] + _escape_to_escapedchars[v[i]] + v[i + 1:]
|
||||
elif v[i] == '\\':
|
||||
v = v[:i - 1] + v[i:]
|
||||
elif v[i] == 'u' or v[i] == 'U':
|
||||
i += 1
|
||||
else:
|
||||
raise ValueError("Reserved escape sequence used")
|
||||
continue
|
||||
elif v[i] == '\\':
|
||||
backslash = True
|
||||
i += 1
|
||||
return v
|
||||
|
||||
|
||||
class InlineTableDict(object):
|
||||
"""Sentinel subclass of dict for inline tables."""
|
||||
|
||||
|
||||
class TomlDecoder(object):
|
||||
|
||||
def __init__(self, _dict=dict):
|
||||
self._dict = _dict
|
||||
|
||||
def get_empty_table(self):
|
||||
return self._dict()
|
||||
|
||||
def get_empty_inline_table(self):
|
||||
class DynamicInlineTableDict(self._dict, InlineTableDict):
|
||||
"""Concrete sentinel subclass for inline tables.
|
||||
It is a subclass of _dict which is passed in dynamically at load
|
||||
time
|
||||
|
||||
It is also a subclass of InlineTableDict
|
||||
"""
|
||||
|
||||
return DynamicInlineTableDict()
|
||||
|
||||
def load_inline_object(self, line, currentlevel, multikey=False,
|
||||
multibackslash=False):
|
||||
candidate_groups = line[1:-1].split(",")
|
||||
groups = []
|
||||
if len(candidate_groups) == 1 and not candidate_groups[0].strip():
|
||||
candidate_groups.pop()
|
||||
while len(candidate_groups) > 0:
|
||||
candidate_group = candidate_groups.pop(0)
|
||||
try:
|
||||
_, value = candidate_group.split('=', 1)
|
||||
except ValueError:
|
||||
raise ValueError("Invalid inline table encountered")
|
||||
value = value.strip()
|
||||
if ((value[0] == value[-1] and value[0] in ('"', "'")) or (
|
||||
value[0] in '-0123456789' or
|
||||
value in ('true', 'false') or
|
||||
(value[0] == "[" and value[-1] == "]") or
|
||||
(value[0] == '{' and value[-1] == '}'))):
|
||||
groups.append(candidate_group)
|
||||
elif len(candidate_groups) > 0:
|
||||
candidate_groups[0] = (candidate_group + "," +
|
||||
candidate_groups[0])
|
||||
else:
|
||||
raise ValueError("Invalid inline table value encountered")
|
||||
for group in groups:
|
||||
status = self.load_line(group, currentlevel, multikey,
|
||||
multibackslash)
|
||||
if status is not None:
|
||||
break
|
||||
|
||||
def _get_split_on_quotes(self, line):
|
||||
doublequotesplits = line.split('"')
|
||||
quoted = False
|
||||
quotesplits = []
|
||||
if len(doublequotesplits) > 1 and "'" in doublequotesplits[0]:
|
||||
singlequotesplits = doublequotesplits[0].split("'")
|
||||
doublequotesplits = doublequotesplits[1:]
|
||||
while len(singlequotesplits) % 2 == 0 and len(doublequotesplits):
|
||||
singlequotesplits[-1] += '"' + doublequotesplits[0]
|
||||
doublequotesplits = doublequotesplits[1:]
|
||||
if "'" in singlequotesplits[-1]:
|
||||
singlequotesplits = (singlequotesplits[:-1] +
|
||||
singlequotesplits[-1].split("'"))
|
||||
quotesplits += singlequotesplits
|
||||
for doublequotesplit in doublequotesplits:
|
||||
if quoted:
|
||||
quotesplits.append(doublequotesplit)
|
||||
else:
|
||||
quotesplits += doublequotesplit.split("'")
|
||||
quoted = not quoted
|
||||
return quotesplits
|
||||
|
||||
def load_line(self, line, currentlevel, multikey, multibackslash):
|
||||
i = 1
|
||||
quotesplits = self._get_split_on_quotes(line)
|
||||
quoted = False
|
||||
for quotesplit in quotesplits:
|
||||
if not quoted and '=' in quotesplit:
|
||||
break
|
||||
i += quotesplit.count('=')
|
||||
quoted = not quoted
|
||||
pair = line.split('=', i)
|
||||
strictly_valid = _strictly_valid_num(pair[-1])
|
||||
if _number_with_underscores.match(pair[-1]):
|
||||
pair[-1] = pair[-1].replace('_', '')
|
||||
while len(pair[-1]) and (pair[-1][0] != ' ' and pair[-1][0] != '\t' and
|
||||
pair[-1][0] != "'" and pair[-1][0] != '"' and
|
||||
pair[-1][0] != '[' and pair[-1][0] != '{' and
|
||||
pair[-1] != 'true' and pair[-1] != 'false'):
|
||||
try:
|
||||
float(pair[-1])
|
||||
break
|
||||
except ValueError:
|
||||
pass
|
||||
if _load_date(pair[-1]) is not None:
|
||||
break
|
||||
i += 1
|
||||
prev_val = pair[-1]
|
||||
pair = line.split('=', i)
|
||||
if prev_val == pair[-1]:
|
||||
raise ValueError("Invalid date or number")
|
||||
if strictly_valid:
|
||||
strictly_valid = _strictly_valid_num(pair[-1])
|
||||
pair = ['='.join(pair[:-1]).strip(), pair[-1].strip()]
|
||||
if '.' in pair[0]:
|
||||
if '"' in pair[0] or "'" in pair[0]:
|
||||
quotesplits = self._get_split_on_quotes(pair[0])
|
||||
quoted = False
|
||||
levels = []
|
||||
for quotesplit in quotesplits:
|
||||
if quoted:
|
||||
levels.append(quotesplit)
|
||||
else:
|
||||
levels += [level.strip() for level in
|
||||
quotesplit.split('.')]
|
||||
quoted = not quoted
|
||||
else:
|
||||
levels = pair[0].split('.')
|
||||
while levels[-1] == "":
|
||||
levels = levels[:-1]
|
||||
for level in levels[:-1]:
|
||||
if level == "":
|
||||
continue
|
||||
if level not in currentlevel:
|
||||
currentlevel[level] = self.get_empty_table()
|
||||
currentlevel = currentlevel[level]
|
||||
pair[0] = levels[-1].strip()
|
||||
elif (pair[0][0] == '"' or pair[0][0] == "'") and \
|
||||
(pair[0][-1] == pair[0][0]):
|
||||
pair[0] = pair[0][1:-1]
|
||||
if len(pair[1]) > 2 and ((pair[1][0] == '"' or pair[1][0] == "'") and
|
||||
pair[1][1] == pair[1][0] and
|
||||
pair[1][2] == pair[1][0] and
|
||||
not (len(pair[1]) > 5 and
|
||||
pair[1][-1] == pair[1][0] and
|
||||
pair[1][-2] == pair[1][0] and
|
||||
pair[1][-3] == pair[1][0])):
|
||||
k = len(pair[1]) - 1
|
||||
while k > -1 and pair[1][k] == '\\':
|
||||
multibackslash = not multibackslash
|
||||
k -= 1
|
||||
if multibackslash:
|
||||
multilinestr = pair[1][:-1]
|
||||
else:
|
||||
multilinestr = pair[1] + "\n"
|
||||
multikey = pair[0]
|
||||
else:
|
||||
value, vtype = self.load_value(pair[1], strictly_valid)
|
||||
try:
|
||||
currentlevel[pair[0]]
|
||||
raise ValueError("Duplicate keys!")
|
||||
except TypeError:
|
||||
raise ValueError("Duplicate keys!")
|
||||
except KeyError:
|
||||
if multikey:
|
||||
return multikey, multilinestr, multibackslash
|
||||
else:
|
||||
currentlevel[pair[0]] = value
|
||||
|
||||
def load_value(self, v, strictly_valid=True):
|
||||
if not v:
|
||||
raise ValueError("Empty value is invalid")
|
||||
if v == 'true':
|
||||
return (True, "bool")
|
||||
elif v == 'false':
|
||||
return (False, "bool")
|
||||
elif v[0] == '"' or v[0] == "'":
|
||||
quotechar = v[0]
|
||||
testv = v[1:].split(quotechar)
|
||||
triplequote = False
|
||||
triplequotecount = 0
|
||||
if len(testv) > 1 and testv[0] == '' and testv[1] == '':
|
||||
testv = testv[2:]
|
||||
triplequote = True
|
||||
closed = False
|
||||
for tv in testv:
|
||||
if tv == '':
|
||||
if triplequote:
|
||||
triplequotecount += 1
|
||||
else:
|
||||
closed = True
|
||||
else:
|
||||
oddbackslash = False
|
||||
try:
|
||||
i = -1
|
||||
j = tv[i]
|
||||
while j == '\\':
|
||||
oddbackslash = not oddbackslash
|
||||
i -= 1
|
||||
j = tv[i]
|
||||
except IndexError:
|
||||
pass
|
||||
if not oddbackslash:
|
||||
if closed:
|
||||
raise ValueError("Stuff after closed string. WTF?")
|
||||
else:
|
||||
if not triplequote or triplequotecount > 1:
|
||||
closed = True
|
||||
else:
|
||||
triplequotecount = 0
|
||||
if quotechar == '"':
|
||||
escapeseqs = v.split('\\')[1:]
|
||||
backslash = False
|
||||
for i in escapeseqs:
|
||||
if i == '':
|
||||
backslash = not backslash
|
||||
else:
|
||||
if i[0] not in _escapes and (i[0] != 'u' and
|
||||
i[0] != 'U' and
|
||||
not backslash):
|
||||
raise ValueError("Reserved escape sequence used")
|
||||
if backslash:
|
||||
backslash = False
|
||||
for prefix in ["\\u", "\\U"]:
|
||||
if prefix in v:
|
||||
hexbytes = v.split(prefix)
|
||||
v = _load_unicode_escapes(hexbytes[0], hexbytes[1:],
|
||||
prefix)
|
||||
v = _unescape(v)
|
||||
if len(v) > 1 and v[1] == quotechar and (len(v) < 3 or
|
||||
v[1] == v[2]):
|
||||
v = v[2:-2]
|
||||
return (v[1:-1], "str")
|
||||
elif v[0] == '[':
|
||||
return (self.load_array(v), "array")
|
||||
elif v[0] == '{':
|
||||
inline_object = self.get_empty_inline_table()
|
||||
self.load_inline_object(v, inline_object)
|
||||
return (inline_object, "inline_object")
|
||||
elif TIME_RE.match(v):
|
||||
h, m, s, _, ms = TIME_RE.match(v).groups()
|
||||
time = datetime.time(int(h), int(m), int(s), int(ms) if ms else 0)
|
||||
return (time, "time")
|
||||
else:
|
||||
parsed_date = _load_date(v)
|
||||
if parsed_date is not None:
|
||||
return (parsed_date, "date")
|
||||
if not strictly_valid:
|
||||
raise ValueError("Weirdness with leading zeroes or "
|
||||
"underscores in your number.")
|
||||
itype = "int"
|
||||
neg = False
|
||||
if v[0] == '-':
|
||||
neg = True
|
||||
v = v[1:]
|
||||
elif v[0] == '+':
|
||||
v = v[1:]
|
||||
v = v.replace('_', '')
|
||||
lowerv = v.lower()
|
||||
if '.' in v or ('x' not in v and ('e' in v or 'E' in v)):
|
||||
if '.' in v and v.split('.', 1)[1] == '':
|
||||
raise ValueError("This float is missing digits after "
|
||||
"the point")
|
||||
if v[0] not in '0123456789':
|
||||
raise ValueError("This float doesn't have a leading "
|
||||
"digit")
|
||||
v = float(v)
|
||||
itype = "float"
|
||||
elif len(lowerv) == 3 and (lowerv == 'inf' or lowerv == 'nan'):
|
||||
v = float(v)
|
||||
itype = "float"
|
||||
if itype == "int":
|
||||
v = int(v, 0)
|
||||
if neg:
|
||||
return (0 - v, itype)
|
||||
return (v, itype)
|
||||
|
||||
def bounded_string(self, s):
|
||||
if len(s) == 0:
|
||||
return True
|
||||
if s[-1] != s[0]:
|
||||
return False
|
||||
i = -2
|
||||
backslash = False
|
||||
while len(s) + i > 0:
|
||||
if s[i] == "\\":
|
||||
backslash = not backslash
|
||||
i -= 1
|
||||
else:
|
||||
break
|
||||
return not backslash
|
||||
|
||||
def load_array(self, a):
|
||||
atype = None
|
||||
retval = []
|
||||
a = a.strip()
|
||||
if '[' not in a[1:-1] or "" != a[1:-1].split('[')[0].strip():
|
||||
strarray = False
|
||||
tmpa = a[1:-1].strip()
|
||||
if tmpa != '' and (tmpa[0] == '"' or tmpa[0] == "'"):
|
||||
strarray = True
|
||||
if not a[1:-1].strip().startswith('{'):
|
||||
a = a[1:-1].split(',')
|
||||
else:
|
||||
# a is an inline object, we must find the matching parenthesis
|
||||
# to define groups
|
||||
new_a = []
|
||||
start_group_index = 1
|
||||
end_group_index = 2
|
||||
in_str = False
|
||||
while end_group_index < len(a[1:]):
|
||||
if a[end_group_index] == '"' or a[end_group_index] == "'":
|
||||
if in_str:
|
||||
backslash_index = end_group_index - 1
|
||||
while (backslash_index > -1 and
|
||||
a[backslash_index] == '\\'):
|
||||
in_str = not in_str
|
||||
backslash_index -= 1
|
||||
in_str = not in_str
|
||||
if in_str or a[end_group_index] != '}':
|
||||
end_group_index += 1
|
||||
continue
|
||||
|
||||
# Increase end_group_index by 1 to get the closing bracket
|
||||
end_group_index += 1
|
||||
|
||||
new_a.append(a[start_group_index:end_group_index])
|
||||
|
||||
# The next start index is at least after the closing
|
||||
# bracket, a closing bracket can be followed by a comma
|
||||
# since we are in an array.
|
||||
start_group_index = end_group_index + 1
|
||||
while (start_group_index < len(a[1:]) and
|
||||
a[start_group_index] != '{'):
|
||||
start_group_index += 1
|
||||
end_group_index = start_group_index + 1
|
||||
a = new_a
|
||||
b = 0
|
||||
if strarray:
|
||||
while b < len(a) - 1:
|
||||
ab = a[b].strip()
|
||||
while (not self.bounded_string(ab) or
|
||||
(len(ab) > 2 and
|
||||
ab[0] == ab[1] == ab[2] and
|
||||
ab[-2] != ab[0] and
|
||||
ab[-3] != ab[0])):
|
||||
a[b] = a[b] + ',' + a[b + 1]
|
||||
ab = a[b].strip()
|
||||
if b < len(a) - 2:
|
||||
a = a[:b + 1] + a[b + 2:]
|
||||
else:
|
||||
a = a[:b + 1]
|
||||
b += 1
|
||||
else:
|
||||
al = list(a[1:-1])
|
||||
a = []
|
||||
openarr = 0
|
||||
j = 0
|
||||
for i in _range(len(al)):
|
||||
if al[i] == '[':
|
||||
openarr += 1
|
||||
elif al[i] == ']':
|
||||
openarr -= 1
|
||||
elif al[i] == ',' and not openarr:
|
||||
a.append(''.join(al[j:i]))
|
||||
j = i + 1
|
||||
a.append(''.join(al[j:]))
|
||||
for i in _range(len(a)):
|
||||
a[i] = a[i].strip()
|
||||
if a[i] != '':
|
||||
nval, ntype = self.load_value(a[i])
|
||||
if atype:
|
||||
if ntype != atype:
|
||||
raise ValueError("Not a homogeneous array")
|
||||
else:
|
||||
atype = ntype
|
||||
retval.append(nval)
|
||||
return retval
|
||||
250
venv/lib/python3.8/site-packages/toml/encoder.py
Normal file
250
venv/lib/python3.8/site-packages/toml/encoder.py
Normal file
@@ -0,0 +1,250 @@
|
||||
import datetime
|
||||
import re
|
||||
import sys
|
||||
|
||||
from 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
|
||||
15
venv/lib/python3.8/site-packages/toml/ordered.py
Normal file
15
venv/lib/python3.8/site-packages/toml/ordered.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from collections import OrderedDict
|
||||
from toml import TomlEncoder
|
||||
from toml import TomlDecoder
|
||||
|
||||
|
||||
class TomlOrderedDecoder(TomlDecoder):
|
||||
|
||||
def __init__(self):
|
||||
super(self.__class__, self).__init__(_dict=OrderedDict)
|
||||
|
||||
|
||||
class TomlOrderedEncoder(TomlEncoder):
|
||||
|
||||
def __init__(self):
|
||||
super(self.__class__, self).__init__(_dict=OrderedDict)
|
||||
21
venv/lib/python3.8/site-packages/toml/tz.py
Normal file
21
venv/lib/python3.8/site-packages/toml/tz.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from datetime import tzinfo, timedelta
|
||||
|
||||
|
||||
class TomlTz(tzinfo):
|
||||
def __init__(self, toml_offset):
|
||||
if toml_offset == "Z":
|
||||
self._raw_offset = "+00:00"
|
||||
else:
|
||||
self._raw_offset = toml_offset
|
||||
self._sign = -1 if self._raw_offset[0] == '-' else 1
|
||||
self._hours = int(self._raw_offset[1:3])
|
||||
self._minutes = int(self._raw_offset[4:6])
|
||||
|
||||
def tzname(self, dt):
|
||||
return "UTC" + self._raw_offset
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self._sign * timedelta(hours=self._hours, minutes=self._minutes)
|
||||
|
||||
def dst(self, dt):
|
||||
return timedelta(0)
|
||||
Reference in New Issue
Block a user