Browse Source

Update ConfigObj 5.1.0 (a68530a) → 5.1.0 (45fbf1b).

pull/1200/head
JackDandy 6 years ago
parent
commit
cbd0c119b9
  1. 1
      CHANGES.md
  2. 265
      lib/configobj/__init__.py
  3. 1
      lib/configobj/_version.py
  4. 93
      lib/configobj/validate.py

1
CHANGES.md

@ -4,6 +4,7 @@
* Update Beautiful Soup 4.7.1 (r497) to 4.8.0 (r526)
* Update cachecontrol library 0.12.4 (bd94f7e) to 0.12.5 (007e8ca)
* Update Certifi 2019.03.09 (401100f) to 2019.06.16 (84dc766)
* Update ConfigObj 5.1.0 (a68530a) to 5.1.0 (45fbf1b)
* Update DiskCache library 3.1.1 (2649ac9) to 4.0.0 (2c79bb9)
* Update feedparser 5.2.1 (2b11c80) to 5.2.1 (cbe18d0)
* Update Hachoir library 2.0a6 (c102cc7) to 2.0a6 (5b9e05a)

265
lib/configobj/__init__.py

@ -1,5 +1,9 @@
# configobj.py
# A config file reader/writer that supports nested sections in config files.
# -*- coding: utf-8 -*-
# pylint: disable=bad-continuation
"""A config file reader/writer that supports nested sections in config files."""
# Copyright (C) 2005-2014:
# (name) : (email)
# Michael Foord: fuzzyman AT voidspace DOT org DOT uk
@ -16,10 +20,17 @@
import os
import re
import sys
import collections
import copy
from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
try:
# Python 3
from collections.abc import Mapping
except ImportError:
# Python 2.7
from collections import Mapping
import six
from ._version import __version__
@ -139,64 +150,6 @@ class UnknownType(Exception):
pass
class Builder(object):
def build(self, o):
if m is None:
raise UnknownType(o.__class__.__name__)
return m(o)
def build_List(self, o):
return list(map(self.build, o.getChildren()))
def build_Const(self, o):
return o.value
def build_Dict(self, o):
d = {}
i = iter(map(self.build, o.getChildren()))
for el in i:
d[el] = next(i)
return d
def build_Tuple(self, o):
return tuple(self.build_List(o))
def build_Name(self, o):
if o.name == 'None':
return None
if o.name == 'True':
return True
if o.name == 'False':
return False
# An undefined Name
raise UnknownType('Undefined Name')
def build_Add(self, o):
real, imag = list(map(self.build_Const, o.getChildren()))
try:
real = float(real)
except TypeError:
raise UnknownType('Add')
if not isinstance(imag, complex) or imag.real != 0.0:
raise UnknownType('Add')
return real+imag
def build_Getattr(self, o):
parent = self.build(o.expr)
return getattr(parent, o.attrname)
def build_UnarySub(self, o):
return -self.build_Const(o.getChildren()[0])
def build_UnaryAdd(self, o):
return self.build_Const(o.getChildren()[0])
_builder = Builder()
def unrepr(s):
if not s:
return s
@ -596,7 +549,7 @@ class Section(dict):
if key not in self:
self.sections.append(key)
dict.__setitem__(self, key, value)
elif isinstance(value, collections.Mapping) and not unrepr:
elif isinstance(value, Mapping) and not unrepr:
# First create the new depth level,
# then create the section
if key not in self:
@ -709,34 +662,34 @@ class Section(dict):
def items(self):
"""D.items() -> list of D's (key, value) pairs, as 2-tuples"""
return list(zip((self.scalars + self.sections), list(self.values())))
return [(key, self[key]) for key in self.keys()]
def keys(self):
"""D.keys() -> list of D's keys"""
return (self.scalars + self.sections)
return self.scalars + self.sections
def values(self):
"""D.values() -> list of D's values"""
return [self[key] for key in (self.scalars + self.sections)]
return [self[key] for key in self.keys()]
def iteritems(self):
"""D.iteritems() -> an iterator over the (key, value) items of D"""
return iter(list(self.items()))
return iter(self.items())
def iterkeys(self):
"""D.iterkeys() -> an iterator over the keys of D"""
return iter((self.scalars + self.sections))
return iter(self.keys())
__iter__ = iterkeys
def itervalues(self):
"""D.itervalues() -> an iterator over the values of D"""
return iter(list(self.values()))
return iter(self.values())
def __repr__(self):
@ -746,7 +699,7 @@ class Section(dict):
return self[key]
except MissingInterpolationOption:
return dict.__getitem__(self, key)
return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(_getval(key))))
return '{%s}' % ', '.join([('{}: {}'.format(repr(key), repr(_getval(key))))
for key in (self.scalars + self.sections)])
__str__ = __repr__
@ -783,10 +736,15 @@ class Section(dict):
return newdict
def merge(self, indict):
def merge(self, indict, decoupled=False):
"""
A recursive update - useful for merging config files.
Note: if ``decoupled`` is ``True``, then the target object (self)
gets its own copy of any mutable objects in the source dictionary
(both sections and values), paid for by more work for ``merge()``
and more memory usage.
>>> a = '''[section1]
... option1 = True
... [[subsection]]
@ -802,10 +760,12 @@ class Section(dict):
>>> c2
ConfigObj({'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}})
"""
for key, val in list(indict.items()):
if (key in self and isinstance(self[key], collections.Mapping) and
isinstance(val, collections.Mapping)):
self[key].merge(val)
for key, val in indict.items():
if decoupled:
val = copy.deepcopy(val)
if (key in self and isinstance(self[key], Mapping) and
isinstance(val, Mapping)):
self[key].merge(val, decoupled=decoupled)
else:
self[key] = val
@ -1069,9 +1029,23 @@ class Section(dict):
self[section].restore_defaults()
def _get_triple_quote(value):
"""Helper for triple-quoting round-trips."""
if ('"""' in value) and ("'''" in value):
raise ConfigObjError('Value cannot be safely quoted: {!r}'.format(value))
return tsquot if "'''" in value else tdquot
class ConfigObj(Section):
"""An object to read, create, and write config files."""
MAX_PARSE_ERROR_DETAILS = 5
# Override/append to this class variable for alternative comment markers
# TODO: also support inline comments (needs dynamic compiling of the regex below)
COMMENT_MARKERS = ['#']
_keyword = re.compile(r'''^ # line start
(\s*) # indentation
( # keyword
@ -1094,7 +1068,7 @@ class ConfigObj(Section):
(?:[^'"\s].*?) # at least one non-space unquoted
) # section name close
((?:\s*\])+) # 4: section marker close
\s*(\#.*)? # 5: optional comment
(\s*(?:\#.*)?)? # 5: optional comment
$''',
re.VERBOSE)
@ -1124,7 +1098,7 @@ class ConfigObj(Section):
)|
(,) # alternatively a single comma - empty list
)
\s*(\#.*)? # optional comment
(\s*(?:\#.*)?)? # optional comment
$''',
re.VERBOSE)
@ -1133,7 +1107,7 @@ class ConfigObj(Section):
(
(?:".*?")| # double quotes
(?:'.*?')| # single quotes
(?:[^'",\#]?.*?) # unquoted
(?:[^'",\#]?.*?) # unquoted
)
\s*,\s* # comma
''',
@ -1148,15 +1122,16 @@ class ConfigObj(Section):
(?:[^'"\#].*?)| # unquoted
(?:) # Empty value
)
\s*(\#.*)? # optional comment
(\s*(?:\#.*)?)? # optional comment
$''',
re.VERBOSE)
# regexes for finding triple quoted values on one line
_single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
_single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
_multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
_multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
_triple_trailer = r"(\s*(?:#.*)?)?$"
_single_line_single = re.compile(r"^'''(.*?)'''" + _triple_trailer)
_single_line_double = re.compile(r'^"""(.*?)"""' + _triple_trailer)
_multi_line_single = re.compile(r"^(.*?)'''" + _triple_trailer)
_multi_line_double = re.compile(r'^(.*?)"""' + _triple_trailer)
_triple_quote = {
"'''": (_single_line_single, _multi_line_single),
@ -1229,8 +1204,12 @@ class ConfigObj(Section):
self._original_configspec = configspec
self._load(infile, configspec)
def _load(self, infile, configspec):
try:
infile = infile.__fspath__()
except AttributeError:
pass
if isinstance(infile, six.string_types):
self.filename = infile
if os.path.isfile(infile):
@ -1281,7 +1260,7 @@ class ConfigObj(Section):
# needs splitting into lines - but needs doing *after* decoding
# in case it's not an 8 bit encoding
else:
raise TypeError('infile must be a filename, file like object, or list of lines.')
raise TypeError('infile must be a path-like object, file like object, or list of lines.')
if content:
# don't do it for the empty ConfigObj
@ -1305,10 +1284,14 @@ class ConfigObj(Section):
self._parse(content)
# if we had any errors, now is the time to raise them
if self._errors:
info = "at line %s." % self._errors[0].line_number
if len(self._errors) > 1:
msg = "Parsing failed with several errors.\nFirst error %s" % info
error = ConfigObjError(msg)
msg = ["Parsing failed with {} errors.".format(len(self._errors))]
for error in self._errors[:self.MAX_PARSE_ERROR_DETAILS]:
msg.append(str(error))
if len(self._errors) > self.MAX_PARSE_ERROR_DETAILS:
msg.append("{} more error(s)!"
.format(len(self._errors) - self.MAX_PARSE_ERROR_DETAILS))
error = ConfigObjError('\n '.join(msg))
else:
error = self._errors[0]
# set the errors attribute; it's a list of tuples:
@ -1364,8 +1347,8 @@ class ConfigObj(Section):
return self[key]
except MissingInterpolationOption:
return dict.__getitem__(self, key)
return ('%s({%s})' % (self.__class__.__name__,
', '.join([('%s: %s' % (repr(key), repr(_getval(key))))
return ('{}({{{}}})'.format(self.__class__.__name__,
', '.join([('{}: {}'.format(repr(key), repr(_getval(key))))
for key in (self.scalars + self.sections)])))
@ -1486,28 +1469,20 @@ class ConfigObj(Section):
return self._decode(infile, 'utf-8')
def _a_to_u(self, aString):
"""Decode ASCII strings to unicode if a self.encoding is specified."""
if isinstance(aString, six.binary_type) and self.encoding:
return aString.decode(self.encoding)
else:
return aString
def _decode(self, infile, encoding):
"""
Decode infile to unicode. Using the specified encoding.
if is a string, it also needs converting to a list.
"""
if isinstance(infile, six.string_types):
return infile.splitlines(True)
if isinstance(infile, six.binary_type):
# NOTE: Could raise a ``UnicodeDecodeError``
if encoding:
return infile.decode(encoding).splitlines(True)
else:
return infile.splitlines(True)
if isinstance(infile, six.string_types):
return infile.splitlines(True)
if encoding:
for i, line in enumerate(infile):
@ -1553,6 +1528,7 @@ class ConfigObj(Section):
maxline = len(infile) - 1
cur_index = -1
reset_comment = False
comment_markers = tuple(self.COMMENT_MARKERS)
while cur_index < maxline:
if reset_comment:
@ -1561,7 +1537,7 @@ class ConfigObj(Section):
line = infile[cur_index]
sline = line.strip()
# do we have anything on the line ?
if not sline or sline.startswith('#'):
if not sline or sline.startswith(comment_markers):
reset_comment = False
comment_list.append(line)
continue
@ -1628,7 +1604,7 @@ class ConfigObj(Section):
mat = self._keyword.match(line)
if mat is None:
self._handle_error(
'Invalid line ({0!r}) (matched as neither section nor keyword)'.format(line),
'Invalid line ({!r}) (matched as neither section nor keyword)'.format(line),
ParseError, infile, cur_index)
else:
# is a keyword value
@ -1651,26 +1627,24 @@ class ConfigObj(Section):
comment = ''
try:
value = unrepr(value)
except Exception as e:
if type(e) == UnknownType:
except Exception as cause:
if isinstance(cause, UnknownType):
msg = 'Unknown name or type in value'
else:
msg = 'Parse error from unrepr-ing multiline value'
self._handle_error(msg, UnreprError, infile,
cur_index)
self._handle_error(msg, UnreprError, infile, cur_index)
continue
else:
if self.unrepr:
comment = ''
try:
value = unrepr(value)
except Exception as e:
if isinstance(e, UnknownType):
except Exception as cause:
if isinstance(cause, UnknownType):
msg = 'Unknown name or type in value'
else:
msg = 'Parse error from unrepr-ing value'
self._handle_error(msg, UnreprError, infile,
cur_index)
self._handle_error(msg, UnreprError, infile, cur_index)
continue
else:
# extract comment and lists
@ -1736,7 +1710,7 @@ class ConfigObj(Section):
"""
line = infile[cur_index]
cur_index += 1
message = '{0} at line {1}.'.format(text, cur_index)
message = '{} at line {}.'.format(text, cur_index)
error = ErrorClass(message, cur_index, line)
if self.raise_errors:
# raise the error - parsing stops here
@ -1810,7 +1784,7 @@ class ConfigObj(Section):
# for normal values either single or double quotes will do
elif '\n' in value:
# will only happen if multiline is off - e.g. '\n' in key
raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
raise ConfigObjError('Value cannot be safely quoted: {!r}'.format(value))
elif ((value[0] not in wspace_plus) and
(value[-1] not in wspace_plus) and
(',' not in value)):
@ -1819,7 +1793,7 @@ class ConfigObj(Section):
quot = self._get_single_quote(value)
else:
# if value has '\n' or "'" *and* '"', it will need triple quotes
quot = self._get_triple_quote(value)
quot = _get_triple_quote(value)
if quot == noquot and '#' in value and self.list_values:
quot = self._get_single_quote(value)
@ -1829,7 +1803,7 @@ class ConfigObj(Section):
def _get_single_quote(self, value):
if ("'" in value) and ('"' in value):
raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
raise ConfigObjError('Value cannot be safely quoted: {!r}'.format(value))
elif '"' in value:
quot = squot
else:
@ -1837,16 +1811,6 @@ class ConfigObj(Section):
return quot
def _get_triple_quote(self, value):
if (value.find('"""') != -1) and (value.find("'''") != -1):
raise ConfigObjError('Value "%s" cannot be safely quoted.' % value)
if value.find('"""') == -1:
quot = tdquot
else:
quot = tsquot
return quot
def _handle_value(self, value):
"""
Given a value string, unquote, remove comment,
@ -1941,12 +1905,12 @@ class ConfigObj(Section):
raise_errors=True,
file_error=True,
_inspec=True)
except ConfigObjError as e:
except ConfigObjError as cause:
# FIXME: Should these errors have a reference
# to the already parsed ConfigObj ?
raise ConfigspecError('Parsing configspec failed: %s' % e)
except IOError as e:
raise IOError('Reading configspec failed: %s' % e)
raise ConfigspecError('Parsing configspec failed: %s' % cause)
except IOError as cause:
raise IOError('Reading configspec failed: %s' % cause)
self.configspec = configspec
@ -1989,27 +1953,32 @@ class ConfigObj(Section):
val = repr(this_entry)
return '%s%s%s%s%s' % (indent_string,
self._decode_element(self._quote(entry, multiline=False)),
self._a_to_u(' = '),
' = ',
val,
self._decode_element(comment))
def _write_marker(self, indent_string, depth, entry, comment):
"""Write a section marker line"""
entry_str = self._decode_element(entry)
title = self._quote(entry_str, multiline=False)
if entry_str and title[0] in '\'"' and title[1:-1] == entry_str:
# titles are in '[]' already, so quoting for contained quotes is not necessary (#74)
title = entry_str
return '%s%s%s%s%s' % (indent_string,
self._a_to_u('[' * depth),
self._quote(self._decode_element(entry), multiline=False),
self._a_to_u(']' * depth),
'[' * depth,
title,
']' * depth,
self._decode_element(comment))
def _handle_comment(self, comment):
"""Deal with a comment."""
if not comment:
return ''
if not comment.strip():
return comment or '' # return trailing whitespace as-is
start = self.indent_type
if not comment.startswith('#'):
start += self._a_to_u(' # ')
if not comment.lstrip().startswith('#'):
start += ' # '
return (start + comment)
@ -2035,8 +2004,8 @@ class ConfigObj(Section):
self.indent_type = DEFAULT_INDENT_TYPE
out = []
cs = self._a_to_u('#')
csp = self._a_to_u('# ')
comment_markers = tuple(self.COMMENT_MARKERS)
comment_marker_default = comment_markers[0] + ' '
if section is None:
int_val = self.interpolation
self.interpolation = False
@ -2044,8 +2013,8 @@ class ConfigObj(Section):
for line in self.initial_comment:
line = self._decode_element(line)
stripped_line = line.strip()
if stripped_line and not stripped_line.startswith(cs):
line = csp + line
if stripped_line and not stripped_line.startswith(comment_markers):
line = comment_marker_default + line
out.append(line)
indent_string = self.indent_type * section.depth
@ -2055,8 +2024,8 @@ class ConfigObj(Section):
continue
for comment_line in section.comments[entry]:
comment_line = self._decode_element(comment_line.lstrip())
if comment_line and not comment_line.startswith(cs):
comment_line = csp + comment_line
if comment_line and not comment_line.startswith(comment_markers):
comment_line = comment_marker_default + comment_line
out.append(indent_string + comment_line)
this_entry = section[entry]
comment = self._handle_comment(section.inline_comments[entry])
@ -2080,8 +2049,8 @@ class ConfigObj(Section):
for line in self.final_comment:
line = self._decode_element(line)
stripped_line = line.strip()
if stripped_line and not stripped_line.startswith(cs):
line = csp + line
if stripped_line and not stripped_line.startswith(comment_markers):
line = comment_marker_default + line
out.append(line)
self.interpolation = int_val
@ -2108,7 +2077,7 @@ class ConfigObj(Section):
and sys.platform == 'win32' and newline == '\r\n'):
# Windows specific hack to avoid writing '\r\r\n'
newline = '\n'
output = self._a_to_u(newline).join(out)
output = newline.join(out)
if not output.endswith(newline):
output += newline
@ -2171,7 +2140,7 @@ class ConfigObj(Section):
if preserve_errors:
# We do this once to remove a top level dependency on the validate module
# Which makes importing configobj faster
from validate import VdtMissingValue
from configobj.validate import VdtMissingValue
self._vdtMissingValue = VdtMissingValue
section = self
@ -2205,12 +2174,12 @@ class ConfigObj(Section):
val,
missing=missing
)
except validator.baseErrorClass as e:
if not preserve_errors or isinstance(e, self._vdtMissingValue):
except validator.baseErrorClass as cause:
if not preserve_errors or isinstance(cause, self._vdtMissingValue):
out[entry] = False
else:
# preserve the error
out[entry] = e
out[entry] = cause
ret_false = False
ret_true = False
else:
@ -2441,7 +2410,7 @@ def flatten_errors(cfg, res, levels=None, results=None):
for (key, val) in list(res.items()):
if val == True:
continue
if isinstance(cfg.get(key), collections.Mapping):
if isinstance(cfg.get(key), Mapping):
# Go down one level
levels.append(key)
flatten_errors(cfg[key], val, levels, results)

1
lib/configobj/_version.py

@ -1 +1,2 @@
"""Project version"""
__version__ = '5.1.0'

93
lib/configobj/validate.py

@ -1,5 +1,9 @@
# validate.py
# A Validator object
# -*- coding: utf-8 -*-
# pylint: disable=
#
# A Validator object.
#
# Copyright (C) 2005-2014:
# (name) : (email)
# Michael Foord: fuzzyman AT voidspace DOT org DOT uk
@ -125,10 +129,12 @@
A badly formatted set of arguments will raise a ``VdtParamError``.
"""
import re
import sys
from pprint import pprint
__version__ = '1.0.1'
__all__ = (
'dottedQuadToNum',
'numToDottedQuad',
@ -161,10 +167,6 @@ __all__ = (
)
import re
import sys
from pprint import pprint
#TODO - #21 - six is part of the repo now, but we didn't switch over to it here
# this could be replaced if six is used for compatibility, or there are no
# more assertions about items being a string
@ -258,17 +260,6 @@ _paramstring = r'''
_matchstring = '^%s*' % _paramstring
# Python pre 2.2.1 doesn't have bool
try:
bool
except NameError:
def bool(val):
"""Simple boolean equivalent function. """
if val:
return 1
else:
return 0
def dottedQuadToNum(ip):
"""
@ -276,17 +267,8 @@ def dottedQuadToNum(ip):
>>> int(dottedQuadToNum('1 '))
1
>>> int(dottedQuadToNum(' 1.2'))
16777218
>>> int(dottedQuadToNum(' 1.2.3 '))
16908291
>>> int(dottedQuadToNum('1.2.3.4'))
16909060
>>> dottedQuadToNum('255.255.255.255')
4294967295
>>> dottedQuadToNum('255.255.255.256')
Traceback (most recent call last):
ValueError: Not a good dotted-quad IP: 255.255.255.256
"""
# import here to avoid it when ip_addr values are not used
@ -379,19 +361,27 @@ class VdtUnknownCheckError(ValidateError):
Traceback (most recent call last):
VdtUnknownCheckError: the check "yoda" is unknown.
"""
ValidateError.__init__(self, 'the check "%s" is unknown.' % (value,))
ValidateError.__init__(self, 'the check "{}" is unknown.'.format(value))
class VdtParamError(SyntaxError):
"""An incorrect parameter was passed"""
def __init__(self, name, value):
NOT_GIVEN = object()
def __init__(self, name_or_msg, value=NOT_GIVEN):
"""
>>> raise VdtParamError('yoda', 'jedi')
Traceback (most recent call last):
VdtParamError: passed an incorrect value "jedi" for parameter "yoda".
>>> raise VdtParamError('preformatted message')
Traceback (most recent call last):
VdtParamError: preformatted message
"""
SyntaxError.__init__(self, 'passed an incorrect value "%s" for parameter "%s".' % (value, name))
if value is self.NOT_GIVEN:
SyntaxError.__init__(self, name_or_msg)
else:
SyntaxError.__init__(self, 'passed an incorrect value "{}" for parameter "{}".'.format(value, name_or_msg))
class VdtTypeError(ValidateError):
@ -403,7 +393,7 @@ class VdtTypeError(ValidateError):
Traceback (most recent call last):
VdtTypeError: the value "jedi" is of the wrong type.
"""
ValidateError.__init__(self, 'the value "%s" is of the wrong type.' % (value,))
ValidateError.__init__(self, 'the value "{}" is of the wrong type.'.format(value))
class VdtValueError(ValidateError):
@ -415,7 +405,7 @@ class VdtValueError(ValidateError):
Traceback (most recent call last):
VdtValueError: the value "jedi" is unacceptable.
"""
ValidateError.__init__(self, 'the value "%s" is unacceptable.' % (value,))
ValidateError.__init__(self, 'the value "{}" is unacceptable.'.format(value))
class VdtValueTooSmallError(VdtValueError):
@ -427,7 +417,7 @@ class VdtValueTooSmallError(VdtValueError):
Traceback (most recent call last):
VdtValueTooSmallError: the value "0" is too small.
"""
ValidateError.__init__(self, 'the value "%s" is too small.' % (value,))
ValidateError.__init__(self, 'the value "{}" is too small.'.format(value))
class VdtValueTooBigError(VdtValueError):
@ -439,7 +429,7 @@ class VdtValueTooBigError(VdtValueError):
Traceback (most recent call last):
VdtValueTooBigError: the value "1" is too big.
"""
ValidateError.__init__(self, 'the value "%s" is too big.' % (value,))
ValidateError.__init__(self, 'the value "{}" is too big.'.format(value))
class VdtValueTooShortError(VdtValueError):
@ -453,7 +443,7 @@ class VdtValueTooShortError(VdtValueError):
"""
ValidateError.__init__(
self,
'the value "%s" is too short.' % (value,))
'the value "{}" is too short.'.format(value))
class VdtValueTooLongError(VdtValueError):
@ -465,7 +455,7 @@ class VdtValueTooLongError(VdtValueError):
Traceback (most recent call last):
VdtValueTooLongError: the value "jedie" is too long.
"""
ValidateError.__init__(self, 'the value "%s" is too long.' % (value,))
ValidateError.__init__(self, 'the value "{}" is too long.'.format(value))
class Validator(object):
@ -537,7 +527,7 @@ class Validator(object):
ConfigObj, an alternative to ConfigParser which supports lists and
can validate a config file using a config schema.
For more details on using Validator with ConfigObj see:
https://configobj.readthedocs.org/en/latest/configobj.html
https://configobj.readthedocs.io/en/latest/configobj.html
"""
# this regex does the initial parsing of the checks
@ -596,6 +586,7 @@ class Validator(object):
Arguments:
check: string representing check to apply (including arguments)
value: object to be checked
Returns value, converted to correct type if necessary
If the check fails, raises a ``ValidateError`` subclass.
@ -642,7 +633,7 @@ class Validator(object):
fun_kwargs = dict(fun_kwargs)
else:
fun_name, fun_args, fun_kwargs, default = self._parse_check(check)
fun_kwargs = dict([(str(key), value) for (key, value) in list(fun_kwargs.items())])
fun_kwargs = {str(key): value for (key, value) in list(fun_kwargs.items())}
self._cache[check] = fun_name, list(fun_args), dict(fun_kwargs), default
return fun_name, fun_args, fun_kwargs, default
@ -766,7 +757,7 @@ def _is_num_param(names, values, to_float=False):
elif isinstance(val, (int, long, float, string_type)):
try:
out_params.append(fun(val))
except ValueError as e:
except ValueError:
raise VdtParamError(name, val)
else:
raise VdtParamError(name, val)
@ -819,7 +810,8 @@ def is_integer(value, min=None, max=None):
>>> vtor.check('integer(0, 9)', False)
0
"""
(min_val, max_val) = _is_num_param(('min', 'max'), (min, max))
(min_val, max_val) = _is_num_param( # pylint: disable=unbalanced-tuple-unpacking
('min', 'max'), (min, max))
if not isinstance(value, (int, long, string_type)):
raise VdtTypeError(value)
if isinstance(value, string_type):
@ -870,7 +862,7 @@ def is_float(value, min=None, max=None):
Traceback (most recent call last):
VdtValueTooBigError: the value "35.0" is too big.
"""
(min_val, max_val) = _is_num_param(
(min_val, max_val) = _is_num_param( # pylint: disable=unbalanced-tuple-unpacking
('min', 'max'), (min, max), to_float=True)
if not isinstance(value, (int, long, float, string_type)):
raise VdtTypeError(value)
@ -1021,7 +1013,8 @@ def is_list(value, min=None, max=None):
Traceback (most recent call last):
VdtTypeError: the value "12" is of the wrong type.
"""
(min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
(min_len, max_len) = _is_num_param( # pylint: disable=unbalanced-tuple-unpacking
('min', 'max'), (min, max))
if isinstance(value, string_type):
raise VdtTypeError(value)
try:
@ -1093,7 +1086,8 @@ def is_string(value, min=None, max=None):
"""
if not isinstance(value, string_type):
raise VdtTypeError(value)
(min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
(min_len, max_len) = _is_num_param( # pylint: disable=unbalanced-tuple-unpacking
('min', 'max'), (min, max))
try:
num_members = len(value)
except TypeError:
@ -1247,10 +1241,17 @@ def force_list(value, min=None, max=None):
fun_dict = {
int: is_integer,
'int': is_integer,
'integer': is_integer,
float: is_float,
'float': is_float,
'ip_addr': is_ip_addr,
str: is_string,
'str': is_string,
'string': is_string,
bool: is_boolean,
'bool': is_boolean,
'boolean': is_boolean,
}
@ -1308,8 +1309,8 @@ def is_mixed_list(value, *args):
raise VdtValueTooLongError(value)
try:
return [fun_dict[arg](val) for arg, val in zip(args, value)]
except KeyError as e:
raise VdtParamError('mixed_list', e)
except KeyError as cause:
raise VdtParamError('mixed_list', cause)
def is_option(value, *options):
@ -1468,4 +1469,6 @@ if __name__ == '__main__':
failures, tests = doctest.testmod(
m, globs=globs,
optionflags=doctest.IGNORE_EXCEPTION_DETAIL | doctest.ELLIPSIS)
assert not failures, '{} failures out of {} tests'.format(failures, tests)
print('{} {} failures out of {} tests'
.format("FAIL" if failures else "*OK*", failures, tests))
sys.exit(bool(failures))

Loading…
Cancel
Save