1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-05 00:02:29 -04:00
This commit is contained in:
Shlomi Fish 2017-04-17 05:26:40 +03:00
parent ebeec6b751
commit 3be5f2a99a
3 changed files with 163 additions and 103 deletions
pysollib/configobj
tests/style

View file

@ -19,19 +19,24 @@
from __future__ import generators
import sys
import os
import re
from types import StringTypes
from warnings import warn
INTP_VER = sys.version_info[:2]
if INTP_VER < (2, 2):
raise RuntimeError("Python v.2.2 or later needed")
import os, re
if sys.version_info > (3,):
unicode = str
compiler = None
try:
import compiler
except ImportError:
# for IronPython
pass
from types import StringTypes
from warnings import warn
try:
from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
except ImportError:
@ -103,12 +108,6 @@ except NameError:
i += 1
yield i, item
try:
True, False
except NameError:
True, False = 1, 0
__version__ = '4.4.0'
__revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $'
@ -164,9 +163,11 @@ def getObj(s):
p = compiler.parse(s)
return p.getChildren()[1].getChildren()[0].getChildren()[1]
class UnknownType(Exception):
pass
class Builder:
def build(self, o):
@ -222,11 +223,13 @@ class Builder:
def build_UnaryAdd(self, o):
return self.build_Const(o.getChildren()[0])
def unrepr(s):
if not s:
return s
return Builder().build(getObj(s))
def _splitlines(instring):
"""Split a string on lines, without losing line endings or truncating."""
@ -242,11 +245,13 @@ class ConfigObjError(SyntaxError):
self.message = message
SyntaxError.__init__(self, message)
class NestingError(ConfigObjError):
"""
This error indicates a level of nesting that doesn't match.
"""
class ParseError(ConfigObjError):
"""
This error indicates that a line is badly written.
@ -254,19 +259,23 @@ class ParseError(ConfigObjError):
nor a valid section marker line.
"""
class DuplicateError(ConfigObjError):
"""
The keyword or section specified already exists.
"""
class ConfigspecError(ConfigObjError):
"""
An error occurred whilst parsing a configspec.
"""
class InterpolationError(ConfigObjError):
"""Base class for the two interpolation errors."""
class InterpolationLoopError(InterpolationError):
"""Maximum interpolation depth exceeded in string interpolation."""
@ -275,12 +284,14 @@ class InterpolationLoopError(InterpolationError):
self,
'interpolation loop detected in value "%s".' % option)
class RepeatSectionError(ConfigObjError):
"""
This error indicates additional sections in a section with a
``__many__`` (repeated) section.
"""
class MissingInterpolationOption(InterpolationError):
"""A value specified for interpolation was missing."""
@ -289,6 +300,7 @@ class MissingInterpolationOption(InterpolationError):
self,
'missing option "%s" in interpolation.' % option)
class UnreprError(ConfigObjError):
"""An error parsing in unrepr mode."""
@ -320,7 +332,7 @@ class InterpolationEngine(object):
This is similar to a depth-first-search algorithm.
"""
# Have we been here already?
if backtrail.has_key((key, section.name)):
if ((key, section.name) in backtrail):
# Yes - infinite loop detected
raise InterpolationLoopError(key)
# Place a marker on our backtrail so we won't come back here again
@ -442,11 +454,13 @@ class TemplateInterpolation(InterpolationEngine):
# Anything else: ignore completely, just return it unchanged
return None, match.group(), None
interpolation_engines = {
'configparser': ConfigParserInterpolation,
'template': TemplateInterpolation,
}
class Section(dict):
"""
A dictionary-like object that represents a section in a config file.
@ -512,10 +526,11 @@ class Section(dict):
except AttributeError:
# not yet: first time running _interpolate(), so pick the engine
name = self.main.interpolation
if name == True: # note that "if name:" would be incorrect here
if name: # note that "if name:" would be incorrect here
# backwards-compatibility: interpolation=True means use default
name = DEFAULT_INTERPOLATION
name = name.lower() # so that "Template", "template", etc. all work
# so that "Template", "template", etc. all work
name = name.lower()
class_ = interpolation_engines.get(name, None)
if class_ is None:
# invalid value for self.main.interpolation
@ -549,9 +564,9 @@ class Section(dict):
creating a new sub-section.
"""
if not isinstance(key, StringTypes):
raise ValueError, 'The key "%s" is not a string.' % key
raise ValueError('The key "%s" is not a string.' % key)
# add the comment
if not self.comments.has_key(key):
if key not in self.comments:
self.comments[key] = []
self.inline_comments[key] = ''
# remove the entry from defaults
@ -559,13 +574,13 @@ class Section(dict):
self.defaults.remove(key)
#
if isinstance(value, Section):
if not self.has_key(key):
if key not in self:
self.sections.append(key)
dict.__setitem__(self, key, value)
elif isinstance(value, dict) and not unrepr:
# First create the new depth level,
# then create the section
if not self.has_key(key):
if key not in self:
self.sections.append(key)
new_depth = self.depth + 1
dict.__setitem__(
@ -578,7 +593,7 @@ class Section(dict):
indict=value,
name=key))
else:
if not self.has_key(key):
if key not in self:
self.scalars.append(key)
if not self.main.stringify:
if isinstance(value, StringTypes):
@ -586,10 +601,10 @@ class Section(dict):
elif isinstance(value, (list, tuple)):
for entry in value:
if not isinstance(entry, StringTypes):
raise TypeError, (
raise TypeError(
'Value is not a string "%s".' % entry)
else:
raise TypeError, 'Value is not a string "%s".' % value
raise TypeError('Value is not a string "%s".' % value)
dict.__setitem__(self, key, value)
def __delitem__(self, key):
@ -635,9 +650,9 @@ class Section(dict):
"""Pops the first (key,val)"""
sequence = (self.scalars + self.sections)
if not sequence:
raise KeyError, ": 'popitem(): dictionary is empty'"
raise KeyError(": 'popitem(): dictionary is empty'")
key = sequence[0]
val = self[key]
val = self[key]
del self[key]
return key, val
@ -692,7 +707,7 @@ class Section(dict):
def __repr__(self):
return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
for key in (self.scalars + self.sections)])
for key in (self.scalars + self.sections)])
__str__ = __repr__
@ -742,11 +757,12 @@ class Section(dict):
>>> c2 = ConfigObj(a)
>>> c2.merge(c1)
>>> c2
{'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}
{'section1': {'option1': 'False', 'subsection': \
{'more_options': 'False'}}}
"""
for key, val in indict.items():
if (key in self and isinstance(self[key], dict) and
isinstance(val, dict)):
isinstance(val, dict)):
self[key].merge(val)
else:
self[key] = val
@ -765,7 +781,7 @@ class Section(dict):
elif oldkey in self.sections:
the_list = self.sections
else:
raise KeyError, 'Key "%s" not found.' % oldkey
raise KeyError('Key "%s" not found.' % oldkey)
pos = the_list.index(oldkey)
#
val = self[oldkey]
@ -781,7 +797,7 @@ class Section(dict):
self.inline_comments[newkey] = inline_comment
def walk(self, function, raise_errors=True,
call_on_sections=False, **keywargs):
call_on_sections=False, **keywargs):
"""
Walk every member and call a function on the keyword and value.
@ -890,6 +906,7 @@ class Section(dict):
1
"""
warn('use of ``decode`` is deprecated.', DeprecationWarning)
def decode(section, key, encoding=encoding, warn=True):
""" """
val = section[key]
@ -916,6 +933,7 @@ class Section(dict):
Uses the ``walk`` method.
"""
warn('use of ``encode`` is deprecated.', DeprecationWarning)
def encode(section, key, encoding=encoding):
""" """
val = section[key]
@ -935,7 +953,7 @@ class Section(dict):
def istrue(self, key):
"""A deprecated version of ``as_bool``."""
warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
'instead.', DeprecationWarning)
'instead.', DeprecationWarning)
return self.as_bool(key)
def as_bool(self, key):
@ -947,8 +965,8 @@ class Section(dict):
If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
``True``.
If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
``False``.
If the string is one of ``False``, ``Off``, ``No``, or ``0`` it
returns ``False``.
``as_bool`` is not case sensitive.
@ -967,9 +985,9 @@ class Section(dict):
0
"""
val = self[key]
if val == True:
if val is True:
return True
elif val == False:
elif val is False:
return False
else:
try:
@ -1038,7 +1056,7 @@ class ConfigObj(Section):
(.*) # value (including list values and comments)
$ # line end
''',
re.VERBOSE)
re.VERBOSE)
_sectionmarker = re.compile(r'''^
(\s*) # 1: indentation
@ -1051,7 +1069,7 @@ class ConfigObj(Section):
((?:\s*\])+) # 4: section marker close
\s*(\#.*)? # 5: optional comment
$''',
re.VERBOSE)
re.VERBOSE)
# this regexp pulls list values out as a single string
# or single values and comments
@ -1081,7 +1099,7 @@ class ConfigObj(Section):
)
\s*(\#.*)? # optional comment
$''',
re.VERBOSE)
re.VERBOSE)
# use findall to get the members of a list value
_listvalueexp = re.compile(r'''
@ -1092,7 +1110,7 @@ class ConfigObj(Section):
)
\s*,\s* # comma
''',
re.VERBOSE)
re.VERBOSE)
# this regexp is used for the value
# when lists are switched off
@ -1105,7 +1123,7 @@ class ConfigObj(Section):
)
\s*(\#.*)? # optional comment
$''',
re.VERBOSE)
re.VERBOSE)
# regexes for finding triple quoted values on one line
_single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
@ -1146,7 +1164,7 @@ class ConfigObj(Section):
defaults = OPTION_DEFAULTS.copy()
for entry in options.keys():
if entry not in defaults.keys():
raise TypeError, 'Unrecognised option "%s".' % entry
raise TypeError('Unrecognised option "%s".' % entry)
# TODO: check the values too.
#
# Add any explicit options to the defaults
@ -1180,7 +1198,7 @@ class ConfigObj(Section):
infile = open(infile).read() or []
elif self.file_error:
# raise an error if the file doesn't exist
raise IOError, 'Config file not found: "%s".' % self.filename
raise IOError('Config file not found: "%s".' % self.filename)
else:
# file doesn't already exist
if self.create_empty:
@ -1212,8 +1230,8 @@ 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 filename,'
' file like object, or list of lines.')
#
if infile:
# don't do it for the empty ConfigObj
@ -1240,7 +1258,7 @@ class ConfigObj(Section):
info = "at line %s." % self._errors[0].line_number
if len(self._errors) > 1:
msg = ("Parsing failed with several errors.\nFirst error %s" %
info)
info)
error = ConfigObjError(msg)
else:
error = self._errors[0]
@ -1261,7 +1279,7 @@ class ConfigObj(Section):
def __repr__(self):
return 'ConfigObj({%s})' % ', '.join(
[('%s: %s' % (repr(key), repr(self[key]))) for key in
(self.scalars + self.sections)])
(self.scalars + self.sections)])
def _handle_bom(self, infile):
"""
@ -1286,7 +1304,7 @@ class ConfigObj(Section):
passed in as a single string.
"""
if ((self.encoding is not None) and
(self.encoding.lower() not in BOM_LIST)):
(self.encoding.lower() not in BOM_LIST)):
# No need to check for a BOM
# the encoding specified doesn't have one
# just decode
@ -1309,8 +1327,8 @@ class ConfigObj(Section):
# skip UTF8
continue
if infile.startswith(BOM):
### BOM discovered
##self.BOM = True
# BOM discovered
# self.BOM = True
# Don't need to remove BOM
return self._decode(infile, encoding)
#
@ -1383,7 +1401,8 @@ class ConfigObj(Section):
return infile.decode(encoding).splitlines(True)
for i, line in enumerate(infile):
if not isinstance(line, unicode):
# NOTE: The isinstance test here handles mixed lists of unicode/string
# NOTE: The isinstance test here handles mixed
# lists of unicode/string
# NOTE: But the decode will break on any non-string values
# NOTE: Or could raise a ``UnicodeDecodeError``
infile[i] = line.decode(encoding)
@ -1473,7 +1492,7 @@ class ConfigObj(Section):
NestingError, infile, cur_index)
#
sect_name = self._unquote(sect_name)
if parent.has_key(sect_name):
if sect_name in parent:
self._handle_error(
'Duplicate section name at line %s.',
DuplicateError, infile, cur_index)
@ -1519,12 +1538,14 @@ class ConfigObj(Section):
comment = ''
try:
value = unrepr(value)
except Exception, e:
except Exception as e:
if type(e) == UnknownType:
msg = 'Unknown name or type in value at line %s.'
msg = 'Unknown name or type ' + \
'in value at line %s.'
else:
msg = 'Parse error in value at line %s.'
self._handle_error(msg, UnreprError, infile,
self._handle_error(
msg, UnreprError, infile,
cur_index)
continue
else:
@ -1532,12 +1553,14 @@ class ConfigObj(Section):
comment = ''
try:
value = unrepr(value)
except Exception, e:
except Exception as e:
if isinstance(e, UnknownType):
msg = 'Unknown name or type in value at line %s.'
msg = 'Unknown name or type ' + \
'in value at line %s.'
else:
msg = 'Parse error in value at line %s.'
self._handle_error(msg, UnreprError, infile,
self._handle_error(
msg, UnreprError, infile,
cur_index)
continue
else:
@ -1551,7 +1574,7 @@ class ConfigObj(Section):
continue
#
key = self._unquote(key)
if this_section.has_key(key):
if key in this_section:
self._handle_error(
'Duplicate keyword name at line %s.',
DuplicateError, infile, cur_index)
@ -1648,12 +1671,12 @@ class ConfigObj(Section):
elif len(value) == 1:
return self._quote(value[0], multiline=False) + ','
return ', '.join([self._quote(val, multiline=False)
for val in value])
for val in value])
if not isinstance(value, StringTypes):
if self.stringify:
value = str(value)
else:
raise TypeError, 'Value "%s" is not a string.' % value
raise TypeError('Value "%s" is not a string.' % value)
squot = "'%s'"
dquot = '"%s"'
noquot = "%s"
@ -1662,23 +1685,24 @@ class ConfigObj(Section):
tdquot = "'''%s'''"
if not value:
return '""'
if (not self.list_values and '\n' not in value) or not (multiline and
((("'" in value) and ('"' in value)) or ('\n' in value))):
if ((not self.list_values and '\n' not in value) or not
(multiline and
((("'" in value) and ('"' in value)) or ('\n' in value)))):
if not self.list_values:
# we don't quote if ``list_values=False``
quot = noquot
# 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 "%s" cannot be safely quoted.' %
value)
elif ((value[0] not in wspace_plus) and
(value[-1] not in wspace_plus) and
(',' not in value)):
quot = noquot
else:
if ("'" in value) and ('"' in value):
raise ConfigObjError, (
raise ConfigObjError(
'Value "%s" cannot be safely quoted.' % value)
elif '"' in value:
quot = squot
@ -1689,7 +1713,7 @@ class ConfigObj(Section):
else:
# if value has '\n' or "'" *and* '"', it will need triple quotes
if (value.find('"""') != -1) and (value.find("'''") != -1):
raise ConfigObjError, (
raise ConfigObjError(
'Value "%s" cannot be safely quoted.' % value)
if value.find('"""') == -1:
quot = tdquot
@ -1787,11 +1811,11 @@ class ConfigObj(Section):
raise_errors=True,
file_error=True,
list_values=False)
except ConfigObjError, e:
except ConfigObjError as e:
# FIXME: Should these errors have a reference
# to the already parsed ConfigObj ?
raise ConfigspecError('Parsing configspec failed: %s' % e)
except IOError, e:
except IOError as e:
raise IOError('Reading configspec failed: %s' % e)
self._set_configspec_value(configspec, self)
@ -1821,7 +1845,7 @@ class ConfigObj(Section):
section._cs_section_comments[entry] = configspec.comments[entry]
section._cs_section_inline_comments[entry] = (
configspec.inline_comments[entry])
if not section.has_key(entry):
if entry not in section:
section[entry] = {}
self._set_configspec_value(configspec[entry], section[entry])
@ -1832,9 +1856,9 @@ class ConfigObj(Section):
scalar_keys = configspec.scalars
except AttributeError:
section_keys = [entry for entry in configspec
if isinstance(configspec[entry], dict)]
if isinstance(configspec[entry], dict)]
scalar_keys = [entry for entry in configspec
if not isinstance(configspec[entry], dict)]
if not isinstance(configspec[entry], dict)]
if '__many__' in section_keys and len(section_keys) > 1:
# FIXME: can we supply any useful information here ?
raise RepeatSectionError
@ -1852,7 +1876,7 @@ class ConfigObj(Section):
#
section.configspec = scalars
for entry in sections:
if not section.has_key(entry):
if entry not in section:
section[entry] = {}
self._handle_repeat(section[entry], sections[entry])
@ -1967,8 +1991,9 @@ class ConfigObj(Section):
# NOTE: This will *screw* UTF16, each line will start with the BOM
if self.encoding:
out = [l.encode(self.encoding) for l in out]
if (self.BOM and ((self.encoding is None) or
(BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
if (self.BOM and
((self.encoding is None) or
(BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
# Add the UTF8 BOM
if not out:
out.append('')
@ -1976,12 +2001,12 @@ class ConfigObj(Section):
return out
#
# Turn the list to a string, joined with correct newlines
output = (self._a_to_u(self.newlines or os.linesep)
).join(out)
output = (self._a_to_u(self.newlines or os.linesep)).join(out)
if self.encoding:
output = output.encode(self.encoding)
if (self.BOM and ((self.encoding is None) or
(BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
if (self.BOM and
((self.encoding is None) or
(BOM_LIST.get(self.encoding.lower()) == 'utf_8'))):
# Add the UTF8 BOM
output = BOM_UTF8 + output
if outfile is not None:
@ -1992,7 +2017,7 @@ class ConfigObj(Section):
h.close()
def validate(self, validator, preserve_errors=False, copy=False,
section=None):
section=None):
"""
Test the ConfigObj against a configspec.
@ -2029,7 +2054,7 @@ class ConfigObj(Section):
"""
if section is None:
if self.configspec is None:
raise ValueError, 'No configspec supplied.'
raise ValueError('No configspec supplied.')
if preserve_errors:
if VdtMissingValue is None:
raise ImportError('Missing validate module.')
@ -2058,12 +2083,12 @@ class ConfigObj(Section):
for entry in order:
if entry == '__many__':
continue
if (not entry in section.scalars) or (entry in section.defaults):
if (entry not in section.scalars) or (entry in section.defaults):
# missing entries
# or entries from defaults
missing = True
val = None
if copy and not entry in section.scalars:
if copy and entry not in section.scalars:
# copy comments
section.comments[entry] = (
section._configspec_comments.get(entry, []))
@ -2078,7 +2103,7 @@ class ConfigObj(Section):
val,
missing=missing
)
except validator.baseErrorClass, e:
except validator.baseErrorClass as e:
if not preserve_errors or isinstance(e, VdtMissingValue):
out[entry] = False
else:
@ -2117,11 +2142,11 @@ class ConfigObj(Section):
section.inline_comments[entry] = (
section._cs_section_inline_comments[entry])
check = self.validate(validator, preserve_errors=preserve_errors,
copy=copy, section=section[entry])
copy=copy, section=section[entry])
out[entry] = check
if check == False:
if check is False:
ret_true = False
elif check == True:
elif check is True:
ret_false = False
else:
ret_true = False
@ -2134,6 +2159,7 @@ class ConfigObj(Section):
else:
return out
class SimpleVal(object):
"""
A simple validator.
@ -2155,6 +2181,7 @@ class SimpleVal(object):
raise self.baseErrorClass
return member
# Check / processing functions for options
def flatten_errors(cfg, res, levels=None, results=None):
"""
@ -2245,7 +2272,8 @@ def flatten_errors(cfg, res, levels=None, results=None):
[root], option3 = the value "Bad_value" is of the wrong type.
[root], section1, option2 = 0
[root], section1, option3 = the value "Bad_value" is of the wrong type.
[root], section2, another_option = the value "Probably" is of the wrong type.
[root], section2, another_option = the value "Probably" is of
the wrong type.
[root], section3, section3b, section3b-sub, [missing] = 0
[root], section3, section3b, value2 = the value "a" is of the wrong type.
[root], section3, section3b, value3 = the value "11" is too big.
@ -2263,7 +2291,7 @@ def flatten_errors(cfg, res, levels=None, results=None):
levels.pop()
return results
for (key, val) in res.items():
if val == True:
if val is True:
continue
if isinstance(cfg.get(key), dict):
# Go down one level
@ -2278,4 +2306,5 @@ def flatten_errors(cfg, res, levels=None, results=None):
#
return results
"""*A programming language is a medium of expression.* - Paul Graham"""

View file

@ -162,11 +162,15 @@ __all__ = (
)
import sys
import re
INTP_VER = sys.version_info[:2]
if INTP_VER < (2, 2):
raise RuntimeError("Python v.2.2 or later needed")
import re
if sys.version_info > (3,):
long = int
unicode = str
StringTypes = (str, unicode)
@ -258,6 +262,7 @@ except NameError:
else:
return 0
def dottedQuadToNum(ip):
"""
Convert decimal dotted quad string to long integer
@ -281,19 +286,21 @@ def dottedQuadToNum(ip):
"""
# import here to avoid it when ip_addr values are not used
import socket, struct
import socket
import struct
try:
return struct.unpack('!L',
socket.inet_aton(ip.strip()))[0]
socket.inet_aton(ip.strip()))[0]
except socket.error:
# bug in inet_aton, corrected in Python 2.3
if ip.strip() == '255.255.255.255':
return 0xFFFFFFFFL
return long('0xFFFFFFFF', 0)
else:
raise ValueError('Not a good dotted-quad IP: %s' % ip)
return
def numToDottedQuad(num):
"""
Convert long int to dotted quad string
@ -317,7 +324,8 @@ def numToDottedQuad(num):
"""
# import here to avoid it when ip_addr values are not used
import socket, struct
import socket
import struct
# no need to intercept here, 4294967295L is fine
try:
@ -326,6 +334,7 @@ def numToDottedQuad(num):
except (socket.error, struct.error, OverflowError):
raise ValueError('Not a good numeric IP: %s' % num)
class ValidateError(Exception):
"""
This error indicates that the check failed.
@ -339,9 +348,11 @@ class ValidateError(Exception):
ValidateError
"""
class VdtMissingValue(ValidateError):
"""No value was supplied to a check that needed one."""
class VdtUnknownCheckError(ValidateError):
"""An unknown check function was requested"""
@ -355,6 +366,7 @@ class VdtUnknownCheckError(ValidateError):
self,
'the check "%s" is unknown.' % value)
class VdtParamError(SyntaxError):
"""An incorrect parameter was passed"""
@ -369,6 +381,7 @@ class VdtParamError(SyntaxError):
'passed an incorrect value "%s" for parameter "%s".' % (
value, name))
class VdtTypeError(ValidateError):
"""The value supplied was of the wrong type"""
@ -382,6 +395,7 @@ class VdtTypeError(ValidateError):
self,
'the value "%s" is of the wrong type.' % value)
class VdtValueError(ValidateError):
"""
The value supplied was of the correct type, but was not an allowed value.
@ -397,6 +411,7 @@ class VdtValueError(ValidateError):
self,
'the value "%s" is unacceptable.' % value)
class VdtValueTooSmallError(VdtValueError):
"""The value supplied was of the correct type, but was too small."""
@ -410,6 +425,7 @@ class VdtValueTooSmallError(VdtValueError):
self,
'the value "%s" is too small.' % value)
class VdtValueTooBigError(VdtValueError):
"""The value supplied was of the correct type, but was too big."""
@ -423,6 +439,7 @@ class VdtValueTooBigError(VdtValueError):
self,
'the value "%s" is too big.' % value)
class VdtValueTooShortError(VdtValueError):
"""The value supplied was of the correct type, but was too short."""
@ -436,6 +453,7 @@ class VdtValueTooShortError(VdtValueError):
self,
'the value "%s" is too short.' % (value,))
class VdtValueTooLongError(VdtValueError):
"""The value supplied was of the correct type, but was too long."""
@ -447,7 +465,8 @@ class VdtValueTooLongError(VdtValueError):
"""
ValidateError.__init__(
self,
'the value "%s" is too long.' % (value,))
'the value "%s" is too long.' % (value,))
class Validator(object):
"""
@ -527,7 +546,6 @@ class Validator(object):
# this regex takes apart keyword arguments
_key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$')
# this regex finds keyword=list(....) type values
_list_arg = _list_arg
@ -539,7 +557,6 @@ class Validator(object):
_paramfinder = re.compile(_paramstring, re.VERBOSE)
_matchfinder = re.compile(_matchstring, re.VERBOSE)
def __init__(self, functions=None):
"""
>>> vtri = Validator()
@ -634,8 +651,6 @@ class Validator(object):
except KeyError:
raise VdtUnknownCheckError(fun_name)
else:
## print fun_args
## print fun_kwargs
return fun(value, *fun_args, **fun_kwargs)
def _unquote(self, val):
@ -689,7 +704,7 @@ def _is_num_param(names, values, to_float=False):
elif isinstance(val, (int, long, float, StringTypes)):
try:
out_params.append(fun(val))
except ValueError, e:
except ValueError as e:
raise VdtParamError(name, val)
else:
raise VdtParamError(name, val)
@ -701,6 +716,7 @@ def _is_num_param(names, values, to_float=False):
# note: if the params are specified wrongly in your input string,
# you will also raise errors.
def is_integer(value, min=None, max=None):
"""
A check that tests that a given value is an integer (int, or long)
@ -757,6 +773,7 @@ def is_integer(value, min=None, max=None):
raise VdtValueTooBigError(value)
return value
def is_float(value, min=None, max=None):
"""
A check that tests that a given value is a float
@ -808,11 +825,13 @@ def is_float(value, min=None, max=None):
raise VdtValueTooBigError(value)
return value
bool_dict = {
True: True, 'on': True, '1': True, 'true': True, 'yes': True,
False: False, 'off': False, '0': False, 'false': False, 'no': False,
}
def is_boolean(value):
"""
Check if the value represents a boolean.
@ -865,9 +884,9 @@ def is_boolean(value):
# we do an equality test rather than an identity test
# this ensures Python 2.2 compatibility
# and allows 0 and 1 to represent True and False
if value == False:
if value is False:
return False
elif value == True:
elif value is True:
return True
else:
raise VdtTypeError(value)
@ -912,6 +931,7 @@ def is_ip_addr(value):
raise VdtValueError(value)
return value
def is_list(value, min=None, max=None):
"""
Check that the value is a list of values.
@ -953,6 +973,7 @@ def is_list(value, min=None, max=None):
raise VdtValueTooLongError(value)
return value
def is_string(value, min=None, max=None):
"""
Check that the supplied value is a string.
@ -988,6 +1009,7 @@ def is_string(value, min=None, max=None):
raise VdtValueTooLongError(value)
return value
def is_int_list(value, min=None, max=None):
"""
Check that the value is a list of integers.
@ -1010,6 +1032,7 @@ def is_int_list(value, min=None, max=None):
"""
return [is_integer(mem) for mem in is_list(value, min, max)]
def is_bool_list(value, min=None, max=None):
"""
Check that the value is a list of booleans.
@ -1034,6 +1057,7 @@ def is_bool_list(value, min=None, max=None):
"""
return [is_boolean(mem) for mem in is_list(value, min, max)]
def is_float_list(value, min=None, max=None):
"""
Check that the value is a list of floats.
@ -1056,6 +1080,7 @@ def is_float_list(value, min=None, max=None):
"""
return [is_float(mem) for mem in is_list(value, min, max)]
def is_string_list(value, min=None, max=None):
"""
Check that the value is a list of strings.
@ -1081,6 +1106,7 @@ def is_string_list(value, min=None, max=None):
raise VdtTypeError(value)
return [is_string(mem) for mem in is_list(value, min, max)]
def is_ip_addr_list(value, min=None, max=None):
"""
Check that the value is a list of IP addresses.
@ -1101,6 +1127,7 @@ def is_ip_addr_list(value, min=None, max=None):
"""
return [is_ip_addr(mem) for mem in is_list(value, min, max)]
fun_dict = {
'integer': is_integer,
'float': is_float,
@ -1109,6 +1136,7 @@ fun_dict = {
'boolean': is_boolean,
}
def is_mixed_list(value, *args):
"""
Check that the value is a list.
@ -1128,7 +1156,8 @@ def is_mixed_list(value, *args):
The length of the list must match the number of positional
arguments you supply.
>>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')"
>>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string',
'boolean')"
>>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True))
>>> check_res == [1, 2.0, '1.2.3.4', 'a', True]
1
@ -1143,7 +1172,8 @@ def is_mixed_list(value, *args):
VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short.
>>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b'))
Traceback (most recent call last):
VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long.
VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')"
is too long.
>>> vtor.check(mix_str, 0)
Traceback (most recent call last):
VdtTypeError: the value "0" is of the wrong type.
@ -1176,9 +1206,10 @@ def is_mixed_list(value, *args):
raise VdtValueTooLongError(value)
try:
return [fun_dict[arg](val) for arg, val in zip(args, value)]
except KeyError, e:
except KeyError as e:
raise VdtParamError('mixed_list', e)
def is_option(value, *options):
"""
This check matches the value to any of a set of options.
@ -1194,10 +1225,11 @@ def is_option(value, *options):
"""
if not isinstance(value, StringTypes):
raise VdtTypeError(value)
if not value in options:
if value not in options:
raise VdtValueError(value)
return value
def _test(value, *args, **keywargs):
"""
A function that exists for test purposes.
@ -1470,4 +1502,3 @@ if __name__ == '__main__':
Code cleanup
"""

View file

@ -10,7 +10,7 @@ use String::ShellQuote qw/ shell_quote /;
# my $cmd = shell_quote( 'flake8', '.' );
my $cmd = shell_quote( 'flake8',
grep { not($_ eq './pysollib/pysoltk.py') } glob('./pysollib/*.py') );
grep { not($_ eq './pysollib/pysoltk.py') } glob('./pysollib/*.py ./pysollib/configobj/*.py') );
# TEST
eq_or_diff( scalar(`$cmd`), '', "flake8 is happy with the code." );