from __future__ import print_function
import os
import sys
import textwrap
import warnings
import math
from pint import UnitRegistry, set_application_registry
from configobj import (ConfigObj, get_extra_values, flatten_errors,
ConfigObjError)
from validate import Validator, ValidateError
if sys.version_info >= (3, 0):
from io import StringIO
else:
from io import BytesIO as StringIO
#==============================================================================
# LOCAL IMPORTS
#==============================================================================
try:
from colorize.colorize import colorize
except ImportError:
def colorize(*args):
return args[0]
#==============================================================================
# CONSTANTS
#==============================================================================
MANY = '__many__'
CONFIGFILES_KEY = 'configFiles'
ERROR_COLOR = 'Zinnia'
EXTRA_COLOR = 'Forest'
# This is the magic: create a SINGLE UnitRegistry object, or you will not
# be able to compare / add quantities:
# WARNING: THIS STATEMENT CAN TAKE MORE THAN 0.1 second!
UR = UnitRegistry(autoconvert_offset_to_baseunit=True)
set_application_registry(UR)
URQ = UR.Quantity
#------------------------------------------------------------------------------
[docs]def eng_string(x, fmt='%s', si=False, doround=None):
""" Returns float/int value <x> formatted in a simplified engineering
format using an exponent that is a multiple of 3.
Args:
fmt (string): printf-style string used to format the value
before the exponent.
si (boolean): if True, use SI suffix for exponent, e.g. k
instead of e3, n instead of e-9 etc.
doround (boolean): if not None round the number to
`doround` decimal digits
Returns: float/int value <x> formatted in a simplified engineering
format using an exponent that is a multiple of 3.
::
E.g. with fmt='%.2f':
1.23e-08 => 12.30e-9
123 => 123.00
1230.0 => 1.23e3
-1230000.0 => -1.23e6
and with si=True:
1230.0 => 1.23k
-1230000.0 => -1.23M
and with doround=6
0.30000000000000004 => 0.3
"""
sign = ''
if x < 0:
x = -x
sign = '-'
if x > 0:
exp = int(math.floor(math.log10(x)))
else:
exp = 0
exp3 = exp - (exp % 3)
if exp3 == 3 and x < 10e3:
exp3 = 0
x3 = x
else:
x3 = x / (10 ** exp3)
if doround is not None:
x3 = round(x3, doround)
if si and exp3 >= -24 and exp3 <= 24 and exp3 != 0:
exp3_text = 'yzafpnum kMGTPEZY'[(exp3 - (-24)) // 3]
elif exp3 == 0:
exp3_text = ''
else:
exp3_text = 'e%s' % exp3
return ('%s'+fmt+'%s') % (sign, x3, exp3_text)
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
[docs]def isStringLike(s):
""" Returns True if s acts "like" a string, i.e. is str or unicode.
Args:
s (string): instance to inspect
Returns:
True if s acts like a string
"""
try:
s + ''
except:
return False
else:
return True
#------------------------------------------------------------------------------
[docs]def qLike(value, section, key):
""" Return value converted to a quantity like `key` in `section`
Args:
value (float or int): value to convert
section (:class:`qcobj.qconfigobj.QConfigObj`.Section`): instance
key (string): an existing key in `section`
Returns:
A :class:`qcobj.qconfigobj.Q_` instance like the one at section[key] with
magnitude `value`
"""
return Q_(value, section.main.configUnits(section, key))
#------------------------------------------------------------------------------
[docs]def msec2cmyear(ms):
""" Return m/s converted to cm/year Quantity
Args:
ms (float): meters per second
Returns:
cm / year
"""
return (ms * UR.m / UR.s).to(UR.cm / UR.year).magnitude
#------------------------------------------------------------------------------
[docs]def errors(cobj, ok):
""" Return errors in a configuration file in terse format
Args:
cobj (:class:`qcobj.qconfigobj.QConfigObj` instance): instance
ok (dict): results dictionary returned by validate
Returns:
error messages string
"""
fname = cobj.filename
if fname is None:
msg = "ConfigSpec File is invalid:\n"
else:
msg = "Parameter File '%s' is invalid:\n" % cobj.filename
for entry in flatten_errors(cobj, ok):
# each entry is a tuple
section_list, key, error = entry
if key is not None:
section_list.append(key)
else:
section_list.append('<-- section is missing!')
section_string = ''.join(["[%s] " % s for s in section_list])
if error == False:
error = 'Missing value or section.'
msg += "%s =\n --> %s\n" % (section_string, error)
msg += "\n"
return msg
#------------------------------------------------------------------------------
[docs]def makeSpec(name, params, level=0):
""" Create ConfigObj configspec string definition for section `name`
Args:
name (string): name of the section we are building
params (Odict): ordered dict instance with the directives:
The directives are (key, value) where value is a tuple
of (comment, comment, ... comment, 'units, min, max',
default).
In case of int and float optional minimum or min and
max values can be specified separated by ONE SINGLE
blank char
level (int): indentation level
Returns:
configSpec string
"""
s = ''
for key, value in params.items():
for v in value[:-2]:
# Add comment lines, NOT units
s += "# %s\n" % v
v = value[-2]
defval = value[-1]
if v:
# Last comment is NOT empty
if isinstance(v, list):
s += ("%s = option(%s, default=%s)\n" %
(key, ', '.join(v), defval))
elif 'bool' in v:
# Special boolean keyword
s += "%s = boolean(default=%s)\n" % (key, defval)
elif 'int' in v:
# Special int keyword
# Remove blanks
v = v.replace(' ', '')
items = v.split(',')
if len(items) == 1:
s += "%s = integer(default=%s)\n" % (key, defval)
elif len(items) == 2:
s += ("%s = integer(min=%s, default=%s)\n" %
(key, items[1], defval))
else:
s += ("%s = integer(min=%s, max=%s, default=%s)\n" %
(key, items[1], items[2], defval))
elif 'float' in v:
# Special float keyword
# Remove blanks
v = v.replace(' ', '')
items = v.split(',')
if len(items) == 1:
s += "%s = float(default=%s)\n" % (key, defval)
elif len(items) == 2:
s += ("%s = float(min=%s, default=%s)\n" %
(key, items[1], defval))
else:
s += ("%s = float(min=%s, max=%s, default=%s)\n" %
(key, items[1], items[2], defval))
elif 'string_list' in v:
# String List
# Remove blanks
v = v.replace(' ', '')
items = v.split(',')
if len(items) == 1:
s += ("%s = string_list(default=list(%s))\n" % (key,
defval))
elif len(items) == 2:
s += ("%s = string_list(min=%s, default=list(%s))\n" %
(key, items[1], defval))
else:
s += ("%s = string_list(min=%s, max=%s, "
"default=list(%s))\n" %
(key, items[1], items[2], defval))
elif 'string' in v:
# String
s += ("%s = string(default='%s')\n" %
(key, str(defval)))
else:
# keyword has dimensions!
default = str(defval)
# Remove blanks
items = v.split(',')
if len(items) == 1:
# No min, no max
sd = ("%s = quantity(units=%s, default='%s %s')\n" %
(key, items[0].strip(), default, v))
elif len(items) == 2:
# Only min, no max
sd = ("%s = quantity(units=%s, min=%s, "
"default='%s %s')\n" %
(key, items[0].strip(), items[1].strip(),
default, items[0].strip()))
elif len(items) == 3:
# Both min and max
sd = ("%s = quantity(units=%s, min=%s, max=%s, "
"default='%s %s')\n" %
(key, items[0].strip(), items[1].strip(),
items[2].strip(), default,
items[0].strip()))
s += sd
#if key == 'Ti':
#print("sd=", sd, "items=", items)
else:
# Simple string value
s += "%s = string(default='%s')\n" % (key, str(defval))
if name:
header = "%s%s%s\n" % ('[' * level, name, level * ']')
else:
header = ''
retstring = "%s%s" % (header, reindent(s, 4))
return reindent(retstring, level * 4)
#------------------------------------------------------------------------------
[docs]def reindent(s, numSpaces=4, no_empty_lines=False):
""" Return string s reindented by `numSpaces` spaces
Args:
s (string): string to reindent
numSpaces (int): number of spaces to shift to the right
no_empty_lines (bool): if True remove empty lines
Returns:
reindented string
"""
if no_empty_lines:
lines = [numSpaces * " " + line if line
else line for line in s.splitlines()]
else:
lines = [numSpaces * " " + line for line in s.splitlines()]
return "\n".join(lines)
#------------------------------------------------------------------------------
[docs]def setVal(section, key, value):
""" Set `value` to section[key] converted to default units
Args:
section (:class:`qcobj.qconfigobj.QConfigObj`.Section`): instance
key (string): valid key for `section`
value (float or int): value to set at section[key] converted
to Quantity
"""
section[key] = section.main.val_to_default(section, key, value)
#------------------------------------------------------------------------------
[docs]def splitPolygons(s):
""" Return a list of polygons from s. Separator is a blank line.
Separation lines with blanks are digested as well.
Args:
s (string): string defining polygon(s) separated by a blank
line. One vertex per line
Returns:
list with polygons (can be converted to numpy array with
np.loadtxt(StringIO(polygon)
"""
ss = "\n".join([l if l.strip() else '\n'
for l in s.strip().splitlines()])
return ss.split('\n\n')
#------------------------------------------------------------------------------
[docs]def sumVal(section, key, value):
""" Add `value` to section[key] converted to default units
Args:
section (:class:`qcobj.qconfigobj.QConfigObj`.Section`): instance
key (string): valid key for `section`
value (float or int): value to add to section[key]
"""
section[key] += section.main.val_to_default(section, key, value)
#------------------------------------------------------------------------------
[docs]def toBaseUnits(q):
""" Return magnitude of quantity `q` converted to base units
* * Used for polygons * *
Args:
q (:class:`qcobj.qconfigobj.Q_`): instance
Returns:
magnitude of q in base units
"""
return q.to_base_units().magnitude
#------------------------------------------------------------------------------
[docs]def val(section, key):
""" Return value of section[key] in units specified in configspec
Args:
section (:class:`qcobj.qconfigobj.QConfigObj`.Section`): instance
key (string): valid key for `section`
Returns:
values in section[key] converted to units defined in configspec
"""
value = section[key]
units = section.main.configUnits(section, key)
if isinstance(value, (list, tuple)):
try:
return [q.to(units).magnitude for q in value]
except AttributeError:
return [q for q in value]
else:
try:
return value.to(units).magnitude
except AttributeError:
return value
#------------------------------------------------------------------------------
[docs]def vval(d, k):
""" Return magnitude in units specified in configspec for
key `k' in qconfigobj section `d` or simply magnitude if
`d` is a dict instance
Args:
d (dict or :class:`qcobj.qconfigobj.QConfigObj`.Section instance):
dict_like
k (string): key in d
Returns:
result of :func:`qcobj.qconfigobj.val` (d, k) or simply
the magnitude of d[k]
"""
try:
return val(d, k)
except AttributeError:
return d[k].magnitude
#==============================================================================
[docs]class Q_(URQ):
""" A Quantity class with user settable preferred units for
representation
"""
[docs] def __new__(cls, *args, **kargs):
# I'm not proud of it, but it works
if len(args) == 2:
obj = super(Q_, cls).__new__(cls, *args, **kargs)
else:
# args[0] is " 1.2345 aunit * another "
val, _, units = args[0].strip().partition(' ')
obj = super(Q_, cls).__new__(cls, float(val), units)
return obj
[docs] def __reduce__(self):
dummy, reduce_string = super(Q_, self).__reduce__()
return (self.__class__, reduce_string)
[docs] def __str__(self):
""" Return :func:`qcobj.qconfigobj.eng_string` representation
of magnitude rounded at 6 decimals with units
"""
#default = super(Q_, self).__str__()
eng = "%s %s" % (eng_string(self.magnitude, doround=6), self.units)
return eng
[docs] def __repr__(self):
""" Return UnitRegistry Quantity representation
"""
return super(Q_, self).__repr__()
#==============================================================================
[docs]class QConfigObjInvalid(ConfigObjError):
""" Invalid value error
"""
[docs] def __init__(self, value):
super(QConfigObjInvalid, self).__init__(
'invalid cfg file:\n%s' % (value,))
#==============================================================================
#==============================================================================
[docs]class _QConfigObj(ConfigObj):
""" A Quantity aware ConfigObj class
"""
[docs] def __init__(self, *args, **kargs):
""" Create a new instance. kargs are from ConfigObj
Keyword Args:
infile (file instance): Input file (None)
configspec (list of strings): configspec (None)
encoding (string): encoding (None)
interpolation (bool): True
raise_errors (bool): False
list_values (bool): True
create_empty (bool): False
file_error (bool): False
stringify (bool): True,
indent_type (string): None
default_encoding (string): None
unrepr (bool): False
write_empty_values (bool): False
_inspec (bool): False
strict (bool): True
noextra (bool): True
"""
strict = kargs.get('strict', True)
if 'strict' in kargs:
del kargs['strict']
noextra = kargs.get('noextra', True)
if 'noextra' in kargs:
del kargs['noextra']
super(_QConfigObj, self).__init__(*args, **kargs)
self.errorsmsg = ''
self.extramsg = ''
self.report = dict()
if self.configspec:
# Validate against configspec
self.report = self.validate(
QValidator(), preserve_errors=True, copy=True)
self._saveErrors()
self._extra()
else:
self.errorsmsg = '\nWARNING! no configspec! Cannot validate!\n'
if self.errorsmsg and strict:
raise QConfigObjInvalid(colorize(self.errorsmsg, ERROR_COLOR))
if self.extramsg and noextra:
raise QConfigObjExtra(colorize(self.extramsg, EXTRA_COLOR))
[docs] def _saveErrors(self):
""" Save errors in a configuration file in terse format
"""
fname = self.filename
msg = "\nERROR!\n"
if fname is None:
msg = "ConfigSpec File is invalid:\n"
else:
msg = "Parameter File '%s' is invalid:\n" % self.filename
errmsg = ''
for entry in flatten_errors(self, self.report):
# each entry is a tuple
section_list, key, error = entry
if key is not None:
section_list.append(key)
else:
section_list.append('<-- section is missing!')
section_string = ''.join(["[%s]" % s for s in section_list])
if error == False:
error = 'Missing value or section.'
errmsg += "%s =\n --> %s\n" % (section_string, error)
if errmsg:
self.errorsmsg = msg + errmsg + "\n"
[docs] def _specAtPath(self, path):
""" Return configspec section at `path`
Args:
path (list): list of section names
Returns:
configspec section at `path`
"""
section = self.configspec
for p in path:
try:
section = section[p]
except KeyError:
section = section[MANY]
return section
[docs] def validRange(self, path, key):
""" Return valid range for quantity `key` at `path`
Args:
path (list): list of section names
key (string): valid key in section at `path`
Returns:
valid range for quantity `key` at `path`
"""
section = self._specAtPath(path)
# Now section is the configspec section at path
try:
values = section[key].replace('$', '\n')
except AttributeError:
return None
else:
return textwrap.dedent(values)
[docs] def configUnits(self, section, key):
""" Return units string for `key` in `section` or None
Args:
section (:class:`qcobj.qconfigobj.QConfigObj`.Section): instance
key (string): valid key in `section`
Returns:
Return units string for `key` in `section` or None
"""
path = []
while section.name is not None:
path.insert(0, section.name)
section = section.parent
configsec = self.configspec
for secname in path:
try:
configsec = configsec[secname]
except KeyError:
try:
configsec = configsec[MANY]
except KeyError:
print("NO %s section!" % MANY)
configspec = configsec[key]
if not configspec.startswith('quantity'):
units = None
else:
units = extract(extract(configspec, 'units', ','),
'=', '', firststop=False).strip()
return units
[docs] def pretty(self):
""" Return pretty string representation for report attribute
Returns:
pretty string representation for report attribute
"""
def pretty(d, d1, sep=' ', level=0):
""" Return pretty string representation for dictionary `d`
"""
s = ''
for key in d.keys():
value = d[key]
if d1 is True:
value1 = True
else:
try:
value1 = d1[key]
except (TypeError, KeyError):
value1 = None
if isinstance(value, dict):
s += "%s%s%s%s\n" % (sep * level, '[' * (level + 1), key,
']' * (level + 1))
s += pretty(d[key], value1, sep, level + 1)
else:
s += "%s%s: " % (sep * level, key)
if isinstance(value, str):
if value1 is True:
s += '"%s"\n' % value
else:
s += '"%s" -----> %s\n' % (value, value1)
else:
if value1 is True:
if isinstance(value, tuple):
sr = '(%s)\n' % ", ".join(
[repr(vs) for vs in value])
else:
sr = '%r\n' % value
s += sr
else:
s += '%r ---> %s\n' % (repr(value), value1)
return s
return pretty(self, self.report)
[docs] def reference_quantity(self, section, key):
""" Return reference quantity for section[key]
Args:
section (:class:`qcobj.qconfigobj.QConfigObj`.Section): instance
key (string): valid key in `section`
Returns:
Return reference quantity for section[key]
Note:
At present USED ONLY IN :class:GMOD2.boundaryCondition
"""
units = self.configUnits(section, key)
if units is None:
return None
else:
return Q_(1, units)
[docs] def val_to_default(self, section, key, value):
""" Set section[key] with value converted to default units (if any)
Args:
section (:class:`qcobj.qconfigobj.QConfigObj`.Section): instance
key (string): valid key in `section`
value (float or int): new value
Note:
At present used only in addMag and setMag
"""
units = self.configUnits(section, key)
if units is None:
return value
else:
return Q_(value, units)
[docs] def write_to_string(self):
""" Return write content in a string
Returns:
Return write content in a string
"""
tmp = StringIO()
self.write(tmp)
return tmp.getvalue()
#==============================================================================
[docs]class QConfigObj(_QConfigObj):
""" A Quantity aware ConfigObj class with CONFIGFILES_KEY support
"""
[docs] def __init__(self, *args, **kargs):
super(QConfigObj, self).__init__(*args, **kargs)
# WARNING: EXPERIMENTAL CODE: NO CHECK AGAINST ERRORS YET
try:
configfiles = self[CONFIGFILES_KEY]
except KeyError:
configfiles = None
if configfiles:
# There is at least one config file!
if ' ' in configfiles:
configFiles = tuple(configfiles.split())
else:
configFiles = (configfiles, )
# Loop on the remaining file(s)
cfg = ''
for fn in (os.path.basename(self.filename), ) + configFiles:
# Create the full pathname for the file to be included
newpath = os.path.join(os.path.dirname(self.filename), fn)
# Load it
cfg += open(newpath).read()
filename = self.filename
self.clear()
super(QConfigObj, self).__init__(cfg.splitlines(), **kargs)
self.filename = filename
if sys.version_info >= (3, 0):
QConfigObj.__init__.__doc__ = _QConfigObj.__init__.__doc__
else:
QConfigObj.__init__.__func__.__doc__ = _QConfigObj.__init__.__doc__
#==============================================================================
[docs]class VdtUnitsError(ValidateError):
""" Missing `units` keyword in quantity type specifier
"""
[docs] def __init__(self, value):
super(VdtUnitsError, self).__init__(
'missing units keyword for value "%s".' % (value,))
#==============================================================================
[docs]class VdtDimensionalityError(ValidateError):
""" Dimensionality error class
"""
[docs] def __init__(self, dim1, dim2):
super(VdtDimensionalityError, self).__init__(
'dimensions disagree: [%s <> %s].' % (dim1, dim2,))
#==============================================================================
[docs]class VdtRangeError(ValidateError):
""" Range error class
"""
[docs] def __init__(self, value, vmin, vmax, units):
super(VdtRangeError, self).__init__(
'value "%s" out of range: [%s, %s] %s.' %
(value, vmin, vmax, units))
#==============================================================================
[docs]class QValidator(Validator):
""" A Validator for Quantities
See Also:
Validator class
"""
[docs] def __init__(self, *args, **kargs):
super(QValidator, self).__init__(*args, **kargs)
# Set validator function for quantity
self.functions['quantity'] = self.quantity_chek
[docs] def quantity_chek(self, value, *args, **kargs):
""" Check if value has the right dimensions and is in the allowed
range.
Quantity **MUST** be specified in configspec like:
>>> quantity(units='Pa / s', min=0, max=100, default=50 Pa /s)
where:
- min and max *CAN* be positional arguments
- default value can be specified in any dimensionally correct
unit after the first blank
Args:
value (instance): the value we are checking
Returns:
validated quantity (or quantities)
Raises:
VdtUnitsError if no units are specified
ValueError if `value` is not a quantity
SyntaxError if quantity specification uses a wrong syntax
VdtDimensionalityError if value has the wrong physical
dimension
VdtRangeError if value (converted to the units defined
in configspec) is not in range [vmin, vmax]
"""
if 'units' in kargs:
units = kargs['units']
else:
raise VdtUnitsError(value)
vmin = vmax = None
if len(args) > 0:
vmin = float(args[0])
if len(args) > 1:
vmax = float(args[1])
if 'min' in kargs:
vmin = float(kargs['min'])
if 'max' in kargs:
vmax = float(kargs['max'])
#print("quantity_chek=%s [%s<->%s]" % (value, vmin, vmax), args, kargs)
# For configspec only: Is it tuple?
atuple = extract(value)
if atuple:
values = ["%s %s" % (v, units) for v in atuple.split(',')]
# For cfg: Is it a tuple?
elif isinstance(value, (list, tuple)):
values = value
else:
values = (value, )
# Build quantities
quantities = ()
for value in values:
try:
quantity = Q_(value)
except ValueError:
raise ValueError("Value '%s' is NOT a quantity!" % value)
except SyntaxError:
msg = "Quantity Syntax Error in '%s': Old syntax?" % value
warnings.warn(msg, SyntaxWarning)
try:
tmp = value.replace('*', '', 1)
quantity = Q_(tmp)
except SyntaxError:
raise SyntaxError("Value '%s' is NOT a quantity!" % value)
# Check if quantity dimensionality is correct
default = Q_(1, units)
if quantity.dimensionality != default.dimensionality:
raise VdtDimensionalityError(
quantity.dimensionality, default.dimensionality)
# Check if quantity is in range [min, max]:
if quantity.units == default.units:
current_quantity = quantity
else:
current_quantity = quantity.to(default.units)
mag = current_quantity.magnitude
if (vmin is not None) and (mag < vmin):
raise VdtRangeError(value, vmin, vmax, default.units)
if (vmax is not None) and (mag > vmax):
raise VdtRangeError(value, vmin, vmax, default.units)
# Append quantity to tuple
quantities += (quantity, )
if len(quantities) == 1:
return quantity
else:
return quantities
#==============================================================================
if __name__ == '__main__':
import sys
import os
import argparse
parser = argparse.ArgumentParser(
description="\nA Quantity aware ConfigObject Module example.",
add_help=True,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog=os.path.basename(sys.argv[0]))
parser.add_argument('cfg', default=None, nargs='*',
help=("Configuration file. Configuration parameters will be loaded "
"from this file ")
)
options = parser.parse_args(sys.argv[1:])
if options.cfg:
pn = options.cfg
else:
wrongConfigSpec = """
oneten = integer(min=110, max=1010, default=510)
a = quantity(units=meter, min=2, max=10, default='5 m')
b = quantity(units=Pa / s, min=0, max=100, default='50 Pa /s')
temp = quantity(units=degC, min=0, max=30, default='20 degC')
[Section0]
key0 = integer(1, 10, default=5)
key1 = string(default=ccqq)
key2 = boolean(default=False)
[Section1]
c0 = quantity(units=A, 0, 10) # Missing default!
c1 = quantity(units=A, 0, 10, default='0.5 mA')
c2 = quantity(units=ohm, 0, 4700, default='2200 ohm')
# Wrong unit in default
c3 = quantity(units=siemens, min=0, default='2200 ohm')
"""
rightConfigSpec = """
oneten = integer(min=110, max=1010, default=510)
a = quantity(units=meter, min=2, max=10, default='5 m')
b = quantity(units=Pa / s, min=0, max=100, default='50 Pa /s')
temp = quantity(units=degC, min=0, max=30, default='20 degC')
[Section0]
key0 = integer(1, 10, default=5)
key1 = string(default=ccqq)
key2 = boolean(default=False)
[Section1]
c1 = quantity(units=A, 0, 10, default='0.5 mA')
c2 = quantity(units=ohm, 0, 4700, default='2200 ohm')
c3 = quantity(units=siemens, min=0, default='2200 siemens')
"""
pn = StringIO("""
#oneten = 1000
a = 5 cm
#aa = 99 * Pa * s **2
b = 2 Pa / s
extra1 = 111
extra2 = Extra2
temp = 275 K
# Now starts section0,
# the 1st section
[Section0] # Ready...
key0 = 999 # key0 with no units
# Now first key
key1 = contains a string
[Section1] # Another section
# key c1, current
c1 = 300 A # 300 Ampere, wow!
# c2 is resitance
c2 = 4 ohm # low value
c3 = -3 siemens
# A new section, not defined in configSpec
[[Subsection11]]
whee = 88
[[[Subsection111]]]
whoo = 99
""")
try:
print("************* Example without configspec *************")
cobj = QConfigObj(pn, strict=False)
print(cobj)
except QConfigObjInvalid as e:
print("!!!!! Exception was rised, error was:\n%s" % e)
print("\n")
try:
print("************* Example with wrong configspec *************")
cobj = QConfigObj(pn, configspec=wrongConfigSpec.split("\n"))
print(cobj)
except QConfigObjInvalid as e:
print("!!!!! Exception was rised, error was:\n%s" % e)
print("\n")
try:
print("************* Example with right configspec *************")
cobj = QConfigObj(pn, configspec=rightConfigSpec.split("\n"))
print(cobj.pretty())
print("************* cobj.errorsmsg *************")
print(cobj.errorsmsg)
print("************* extramsg *************")
print(cobj.extramsg)
except:
print("This will not be printed ;-)")
raise SystemExit
try:
print("*** Example without configspec, noextra=False ***")
cobj = QConfigObj(pn, noextra=False)
print(cobj)
print("************* cobj.errorsmsg *************")
print(cobj.errorsmsg)
print("************* cobj.extrasmsg *************")
print(cobj.extramsg)
except QConfigObjExtra as e:
print("!!!!! Exception was rised, error was:\n%s" % e)
print("\n")
try:
print("************* Example with right configspec *************")
cobj = QConfigObj(pn, configspec=rightConfigSpec.split("\n"))
print(cobj.pretty())
print("************* cobj.errorsmsg *************")
print(cobj.errorsmsg)
print("************* extramsg *************")
print(cobj.extramsg)
except:
print("This will not be printed ;-)")
print("azz" * 30)
try:
print("************* Example with right configspec *************")
cobj = QConfigObj(pn, configspec=rightConfigSpec.split("\n"),
noextra=True)
print(cobj.pretty())
print("************* cobj.errorsmsg *************")
print(cobj.errorsmsg)
print("************* extramsg *************")
print(cobj.extramsg)
except:
print("This will not be printed ;-)")
#print(cobj.errorsmsg)
#print("************* cobj.extrasmsg *************")
#print(cobj.extramsg)
##cobj = QConfigObj(pn, configspec=configSpec.split("\n"), strict=False,
##noextra=False)
#print(cobj.errorsmsg)
#print("************* cobj *************")
##print(repr(cobj))
#print(cobj.pretty())