Merge branch 'conflayers'

This commit is contained in:
Florian Bruhin 2014-04-13 21:52:49 +02:00
commit fb6d0a5c62
3 changed files with 123 additions and 32 deletions

View File

@ -172,14 +172,16 @@ class Config(QObject):
else: else:
lines += wrapper.wrap('Valid values: {}'.format(', '.join( lines += wrapper.wrap('Valid values: {}'.format(', '.join(
valid_values))) valid_values)))
lines += wrapper.wrap('Default: {}'.format(option.default)) lines += wrapper.wrap('Default: {}'.format(
option.values['default']))
return lines return lines
def _str_items(self, section): def _str_items(self, section):
"""Get the option items as string for section.""" """Get the option items as string for section."""
lines = [] lines = []
for optname, option in section.items(): for optname, option in section.items():
keyval = '{} = {}'.format(optname, option) keyval = '{} = {}'.format(optname, option.get_first_value(
startlayer='conf'))
lines.append(keyval) lines.append(keyval)
return lines return lines
@ -272,11 +274,26 @@ class Config(QObject):
""" """
# FIXME completion for values # FIXME completion for values
try: try:
self.set(section, option, value) self.set('conf', section, option, value)
except (NoOptionError, NoSectionError, ValidationError) as e: except (NoOptionError, NoSectionError, ValidationError) as e:
message.error("set: {} - {}".format(e.__class__.__name__, e)) message.error("set: {} - {}".format(e.__class__.__name__, e))
def set(self, section, option, value): @cmdutils.register(name='set_temp', instance='config',
completion=['section', 'option'])
def set_temp_wrapper(self, section, option, value):
"""Set a temporary option.
Wrapper for self.set() to output exceptions in the status bar.
Arguments:
*args: Get passed to self.set().
"""
try:
self.set('temp', section, option, value)
except (NoOptionError, NoSectionError, ValidationError) as e:
message.error("set: {} - {}".format(e.__class__.__name__, e))
def set(self, layer, section, option, value):
"""Set an option. """Set an option.
Args: Args:
@ -296,11 +313,11 @@ class Config(QObject):
value = self._interpolation.before_set(self, section, option, value = self._interpolation.before_set(self, section, option,
value) value)
try: try:
sectdict = self.config[section] sect = self.config[section]
except KeyError: except KeyError:
raise NoSectionError(section) raise NoSectionError(section)
try: try:
sectdict[self.optionxform(option)] = value sect.setv(layer, option, value)
except KeyError: except KeyError:
raise NoOptionError(option, section) raise NoOptionError(option, section)
else: else:
@ -322,13 +339,16 @@ class Config(QObject):
Return: Return:
The changed config part as string. The changed config part as string.
""" """
# FIXME adopt this for layering
lines = [] lines = []
for secname, section in self.config.items(): for secname, section in self.config.items():
changed_opts = [] changed_opts = []
for optname, option in section.items(): for optname, option in section.items():
if (option.rawvalue is not None and if (option.values.temp is not None and
option.rawvalue != option.default): option.values.temp != option.default or
keyval = '{} = {}'.format(optname, option) option.values.conf is not None and
option.values.conf != option.default):
keyval = '{} = {}'.format(optname, option) # FIXME layer?
changed_opts.append(keyval) changed_opts.append(keyval)
if changed_opts: if changed_opts:
lines.append('[{}]'.format(secname)) lines.append('[{}]'.format(secname))
@ -409,7 +429,7 @@ class SectionProxy(MutableMapping):
return self._conf.get(self._name, key) return self._conf.get(self._name, key)
def __setitem__(self, key, value): def __setitem__(self, key, value):
return self._conf.set(self._name, key, value) return self._conf.set('conf', self._name, key, value)
def __delitem__(self, key): def __delitem__(self, key):
if not (self._conf.has_option(self._name, key) and if not (self._conf.has_option(self._name, key) and

View File

@ -64,13 +64,13 @@ class KeyValue:
return self.values[key] return self.values[key]
def __setitem__(self, key, value): def __setitem__(self, key, value):
"""Set the value for key. """Set the config value for key.
Args: Args:
key: The key to set the value for, as a string. key: The key to set the value for, as a string.
value: The value to set, as a string value: The value to set, as a string
""" """
self.values[key].value = value self.setv('conf', key, value)
def __iter__(self): def __iter__(self):
"""Iterate over all set values.""" """Iterate over all set values."""
@ -85,15 +85,29 @@ class KeyValue:
"""Return whether the section contains a given key.""" """Return whether the section contains a given key."""
return key in self.values return key in self.values
def setv(self, layer, key, value):
"""Set the value on a layer.
Arguments:
layer: The layer to set the value on, an element name of the
ValueLayers dict.
key: The key of the element to set.
value: The value to set.
"""
self.values[key].setv(layer, value)
def items(self): def items(self):
"""Get dict item tuples.""" """Get dict item tuples."""
return self.values.items() return self.values.items()
def from_cp(self, sect): def from_cp(self, sect):
"""Initialize the values from a configparser section.""" """Initialize the values from a configparser section.
We assume all keys already exist from the defaults.
"""
for k, v in sect.items(): for k, v in sect.items():
logging.debug("'{}' = '{}'".format(k, v)) logging.debug("'{}' = '{}'".format(k, v))
self.values[k].value = v self.values[k].setv('conf', v)
class ValueList: class ValueList:
@ -117,6 +131,9 @@ class ValueList:
# KeyValue section. # KeyValue section.
""" """
# FIXME use a ChainMap for this
# FIXME how to handle value layers here?
def __init__(self, keytype, valtype, *defaults): def __init__(self, keytype, valtype, *defaults):
"""Wrap types over default values. Take care when overriding this.""" """Wrap types over default values. Take care when overriding this."""
self.keytype = keytype self.keytype = keytype
@ -149,14 +166,13 @@ class ValueList:
return self.default[key] return self.default[key]
def __setitem__(self, key, value): def __setitem__(self, key, value):
"""Set the value for key. """Set the config value for key.
Args: Args:
key: The key to set the value for, as a string. key: The key to set the value for, as a string.
value: The value to set, as a string value: The value to set, as a string
""" """
self.values[key] = SettingValue(self.valtype) self.setv('conf', key, value)
self.values[key].value = value
def __iter__(self): def __iter__(self):
"""Iterate over all set values.""" """Iterate over all set values."""
@ -174,6 +190,22 @@ class ValueList:
self.update_valdict() self.update_valdict()
return key in self.valdict return key in self.valdict
def setv(self, layer, key, value):
"""Set the value on a layer.
Arguments:
layer: The layer to set the value on, an element name of the
ValueLayers dict.
key: The key of the element to set.
value: The value to set.
"""
if key in self.values:
self.values[key].setv(layer, value)
else:
val = SettingValue(self.valtype)
val.setv(layer, value)
self.values[key] = val
def items(self): def items(self):
"""Get dict items.""" """Get dict items."""
self.update_valdict() self.update_valdict()
@ -186,4 +218,4 @@ class ValueList:
for k, v in sect.items(): for k, v in sect.items():
keytype.validate(k) keytype.validate(k)
valtype.validate(v) valtype.validate(v)
self.values[k] = SettingValue(self.valtype, v) self.setv('conf', k, v)

View File

@ -17,6 +17,8 @@
"""A single value (with multiple layers possibly) in the config.""" """A single value (with multiple layers possibly) in the config."""
from collections import OrderedDict
class SettingValue: class SettingValue:
@ -26,9 +28,9 @@ class SettingValue:
Attributes: Attributes:
typ: A BaseType subclass. typ: A BaseType subclass.
default: Default value if the user has not overridden it, as a string. value: (readonly property) The currently valid, most important value.
value: (property) The currently valid, most important value. _values: An OrderedDict with the values on different layers, with the
rawvalue: The current value as a raw string. most significant layer first.
""" """
def __init__(self, typ, default=None): def __init__(self, typ, default=None):
@ -39,25 +41,62 @@ class SettingValue:
default: Raw value to set. default: Raw value to set.
""" """
self.typ = typ() self.typ = typ()
self.rawvalue = None self._values = OrderedDict.fromkeys(['temp', 'conf', 'default'])
self.default = default self._values['default'] = default
def __str__(self): def __str__(self):
"""Get raw string value.""" """Get raw string value."""
return self.value return self.value
@property
def value(self):
"""Get the currently valid value."""
return self.get_first_value()
@property
def values(self):
"""Readonly property for _values."""
return self._values
def getlayers(self, startlayer):
"""Get a dict of values starting with startlayer.
Args:
startlayer: The first layer to include.
"""
idx = list(self._values.keys()).index(startlayer)
d = OrderedDict(list(self._values.items())[idx:])
return d
def get_first_value(self, startlayer=None):
"""Get the first valid value starting from startlayer.
Args:
startlayer: The first layer to include.
"""
# pylint: disable=useless-else-on-loop
if startlayer is None:
d = self._values
else:
d = self.getlayers(startlayer)
for val in d.values():
if val is not None:
return val
else:
raise ValueError("No valid config value found!")
def transformed(self): def transformed(self):
"""Get the transformed value.""" """Get the transformed value."""
v = self.value v = self.value
return self.typ.transform(v) return self.typ.transform(v)
@property def setv(self, layer, value):
def value(self): """Set the value on a layer.
"""Get the currently valid value."""
return self.rawvalue if self.rawvalue is not None else self.default
@value.setter Arguments:
def value(self, val): layer: The layer to set the value on, an element name of the
"""Set the currently valid value.""" ValueLayers dict.
self.typ.validate(val) value: The value to set.
self.rawvalue = val """
self.typ.validate(value)
self._values[layer] = value