| Index: third_party/recipe_engine/config.py
|
| diff --git a/third_party/recipe_engine/config.py b/third_party/recipe_engine/config.py
|
| deleted file mode 100644
|
| index 693b129670fe34442fbcb407598320b61c84d4e4..0000000000000000000000000000000000000000
|
| --- a/third_party/recipe_engine/config.py
|
| +++ /dev/null
|
| @@ -1,736 +0,0 @@
|
| -# Copyright 2013-2015 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -"""Recipe Configuration Meta DSL.
|
| -
|
| -This module contains, essentially, a DSL for writing composable configurations.
|
| -You start by defining a schema which describes how your configuration blobs will
|
| -be structured, and what data they can contain. For example:
|
| -
|
| - FakeSchema = lambda main_val=True, mode='Happy': ConfigGroup(
|
| - config_group = ConfigGroup(
|
| - item_a = SimpleConfig(int),
|
| - item_b = DictConfig(),
|
| - ),
|
| - extra_setting = SetConfig(str),
|
| -
|
| - MAIN_DETERMINANT = StaticConfig(main_val),
|
| - CONFIG_MODE = StaticConfig(mode),
|
| - )
|
| -
|
| -In short, a 'schema' is a callable which can take zero arguments (it can contain
|
| -default arguments as well, for setting defaults, tweaking the schema, etc.), and
|
| -returning a ConfigGroup.
|
| -
|
| -Every type used in the schema derives from ConfigBase. It has the general
|
| -characteristics that it's a fixed-type container. It tends to impersonate the
|
| -data type that it stores (so you can manipulate the config objects like normal
|
| -python data), but also provides type checking and type conversion assistence
|
| -(so you can easily render your configurations to JSON).
|
| -
|
| -Then you can create a configuration context:
|
| -
|
| - config_ctx = config_item_context(FakeSchema)
|
| -
|
| -config_ctx is a python decorator which you can use to create composable
|
| -configuration functions. For example:
|
| -
|
| - @config_ctx()
|
| - def cool(c):
|
| - if c.CONFIG_MODE == 'Happy':
|
| - c.config_group.item_a = 100
|
| - else:
|
| - c.config_group.item_a = -100
|
| -
|
| - @config_ctx()
|
| - def gnarly(c):
|
| - c.extra_setting = 'gnarly!'
|
| -
|
| - @config_ctx(includes=('cool', 'gnarly'))
|
| - def combo(c):
|
| - if c.MAIN_DETERMINANT:
|
| - c.config_group.item_b['nickname'] = 'purple'
|
| - c.extra_setting += ' cows!'
|
| - else:
|
| - c.config_group.item_b['nickname'] = 'sad times'
|
| -
|
| -If I now call:
|
| -
|
| - combo()
|
| -
|
| -I will get back a configuraton object whose schema is FakeSchema, and whose
|
| -data is the accumulation of cool(), gnarly(), and combo(). I can continue to
|
| -manipulate this configuraton object, use its data, or render it to json.
|
| -
|
| -Using this system should allow you to create rich, composible,
|
| -modular configurations. See the documentation on config_item_context and the
|
| -BaseConfig derivatives for more info.
|
| -"""
|
| -
|
| -import collections
|
| -import functools
|
| -import types
|
| -
|
| -from infra.libs import infra_types
|
| -
|
| -class BadConf(Exception):
|
| - pass
|
| -
|
| -def typeAssert(obj, typearg):
|
| - if not isinstance(obj, typearg):
|
| - raise TypeError("Expected %r to be of type %r" % (obj, typearg))
|
| -
|
| -
|
| -class ConfigContext(object):
|
| - """A configuration context for a recipe module.
|
| -
|
| - Holds configuration schema and also acts as a config_ctx decorator.
|
| - A recipe module can define at most one such context.
|
| - """
|
| -
|
| - def __init__(self, CONFIG_SCHEMA):
|
| - self.CONFIG_ITEMS = {}
|
| - self.MUTEX_GROUPS = {}
|
| - self.CONFIG_SCHEMA = CONFIG_SCHEMA
|
| - self.ROOT_CONFIG_ITEM = None
|
| -
|
| - def __call__(self, group=None, includes=None, deps=None,
|
| - is_root=False, config_vars=None):
|
| - """
|
| - A decorator for functions which modify a given schema of configs.
|
| - Examples continue using the schema and config_items defined in the module
|
| - docstring.
|
| -
|
| - This decorator provides a series of related functions:
|
| - * Any function decorated with this will be registered into this config
|
| - context by __name__. This enables some of the other following features
|
| - to work.
|
| - * Alters the signature of the function so that it can receive an extra
|
| - parameter 'final'. See the documentation for final on inner().
|
| - * Provides various convenience and error checking facilities.
|
| - * In particular, this decorator will prevent you from calling the same
|
| - config_ctx on a given config blob more than once (with the exception
|
| - of setting final=False. See inner())
|
| -
|
| - Args:
|
| - group(str) - Using this decorator with the `group' argument causes the
|
| - decorated function to be a member of that group. Members of a group are
|
| - mutually exclusive on the same configuration blob. For example, only
|
| - one of these two functions could be applied to the config blob c:
|
| - @config_ctx(group='a')
|
| - def bob(c):
|
| - c.extra_setting = "bob mode"
|
| -
|
| - @config_ctx(group='a')
|
| - def bill(c):
|
| - c.extra_setting = "bill mode"
|
| -
|
| - includes(iterable(str)) - Any config items named in the includes list will
|
| - be run against the config blob before the decorated function can modify
|
| - it. If an inclusion is already applied to the config blob, it's skipped
|
| - without applying/raising BadConf. Example:
|
| - @config_ctx(includes=('bob', 'cool'))
|
| - def charlie(c):
|
| - c.config_group.item_b = 25
|
| - The result of this config_ctx (assuming default values for the schema)
|
| - would be:
|
| - {'config_group': { 'item_a': 100, 'item_b': 25 },
|
| - 'extra_setting': 'gnarly!'}
|
| -
|
| - deps(iterable(str)) - One or more groups which must be satisfied before
|
| - this config_ctx can be applied to a config_blob. If you invoke
|
| - a config_ctx on a blob without having all of its deps satisfied,
|
| - you'll get a BadConf exception.
|
| -
|
| - is_root(bool) - If set to True on an item, this item will become the
|
| - 'basis' item for all other configurations in this group. That means that
|
| - it will be implicitly included in all other config_items. There may only
|
| - ever be one root item.
|
| -
|
| - config_vars(dict) - A dictionary mapping of { CONFIG_VAR: <value> }. This
|
| - sets the input contidions for the CONFIG_SCHEMA.
|
| -
|
| - Returns a new decorated version of this function (see inner()).
|
| - """
|
| - def decorator(f):
|
| - name = f.__name__
|
| - @functools.wraps(f)
|
| - def inner(config=None, final=True, optional=False, **kwargs):
|
| - """This is the function which is returned from the config_ctx
|
| - decorator.
|
| -
|
| - It applies all of the logic mentioned in the config_ctx docstring
|
| - above, and alters the function signature slightly.
|
| -
|
| - Args:
|
| - config - The config blob that we intend to manipulate. This is passed
|
| - through to the function after checking deps and including includes.
|
| - After the function manipulates it, it is automatically returned.
|
| -
|
| - final(bool) - Set to True by default, this will record the application
|
| - of this config_ctx to `config', which will prevent the config_ctx
|
| - from being applied to `config' again. It also is used to see if the
|
| - config blob satisfies deps for subsequent config_ctx applications
|
| - (i.e. in order for a config_ctx to satisfy a dependency, it must
|
| - be applied with final=True).
|
| -
|
| - This is useful to apply default values while allowing the config to
|
| - later override those values.
|
| -
|
| - However, it's best if each config_ctx is final, because then you
|
| - can implement the config items with less error checking, since you
|
| - know that the item may only be applied once. For example, if your
|
| - item appends something to a list, but is called with final=False,
|
| - you'll have to make sure that you don't append the item twice, etc.
|
| -
|
| - **kwargs - Passed through to the decorated function without harm.
|
| -
|
| - Returns config and ignores the return value of the decorated function.
|
| - """
|
| - if config is None:
|
| - config = self.CONFIG_SCHEMA()
|
| - assert isinstance(config, ConfigGroup)
|
| - inclusions = config._inclusions # pylint: disable=W0212
|
| -
|
| - # inner.IS_ROOT will be True or False at the time of invocation.
|
| - if (self.ROOT_CONFIG_ITEM and not inner.IS_ROOT and
|
| - self.ROOT_CONFIG_ITEM.__name__ not in inclusions):
|
| - self.ROOT_CONFIG_ITEM(config)
|
| -
|
| - if name in inclusions:
|
| - if optional:
|
| - return config
|
| - raise BadConf('config_ctx "%s" is already in this config "%s"' %
|
| - (name, config.as_jsonish(include_hidden=True)))
|
| - if final:
|
| - inclusions.add(name)
|
| -
|
| - for include in includes or []:
|
| - if include in inclusions:
|
| - continue
|
| - try:
|
| - self.CONFIG_ITEMS[include](config)
|
| - except BadConf as e:
|
| - raise BadConf('config "%s" includes "%s", but [%s]' %
|
| - (name, include, e))
|
| -
|
| - # deps are a list of group names. All groups must be represented
|
| - # in config already.
|
| - for dep_group in deps or []:
|
| - if not inclusions & self.MUTEX_GROUPS[dep_group]:
|
| - raise BadConf('dep group "%s" is unfulfilled for "%s"' %
|
| - (dep_group, name))
|
| -
|
| - if group:
|
| - overlap = inclusions & self.MUTEX_GROUPS[group]
|
| - overlap.discard(name)
|
| - if overlap:
|
| - raise BadConf('"%s" is a member of group "%s", but %s already ran' %
|
| - (name, group, tuple(overlap)))
|
| -
|
| - ret = f(config, **kwargs)
|
| - assert ret is None, 'Got return value (%s) from "%s"?' % (ret, name)
|
| -
|
| - return config
|
| - inner.WRAPPED = f
|
| - inner.INCLUDES = includes or []
|
| -
|
| - def default_config_vars():
|
| - ret = {}
|
| - for include in includes or []:
|
| - item = self.CONFIG_ITEMS[include]
|
| - ret.update(item.DEFAULT_CONFIG_VARS())
|
| - if config_vars:
|
| - ret.update(config_vars)
|
| - return ret
|
| - inner.DEFAULT_CONFIG_VARS = default_config_vars
|
| -
|
| - assert name not in self.CONFIG_ITEMS, (
|
| - '%s is already in CONFIG_ITEMS' % name)
|
| - self.CONFIG_ITEMS[name] = inner
|
| - if group:
|
| - self.MUTEX_GROUPS.setdefault(group, set()).add(name)
|
| - inner.IS_ROOT = is_root
|
| - if is_root:
|
| - assert not self.ROOT_CONFIG_ITEM, (
|
| - 'may only have one root config_ctx!')
|
| - self.ROOT_CONFIG_ITEM = inner
|
| - inner.IS_ROOT = True
|
| - return inner
|
| - return decorator
|
| -
|
| -
|
| -def config_item_context(CONFIG_SCHEMA):
|
| - """Create a configuration context.
|
| -
|
| - Args:
|
| - CONFIG_SCHEMA: This is a function which can take a minimum of zero arguments
|
| - and returns an instance of BaseConfig. This BaseConfig
|
| - defines the schema for all configuration objects manipulated
|
| - in this context.
|
| -
|
| - Returns a config_ctx decorator for this context.
|
| - """
|
| - return ConfigContext(CONFIG_SCHEMA)
|
| -
|
| -
|
| -class AutoHide(object):
|
| - pass
|
| -AutoHide = AutoHide()
|
| -
|
| -
|
| -class ConfigBase(object):
|
| - """This is the root interface for all config schema types."""
|
| -
|
| - def __init__(self, hidden=AutoHide):
|
| - """
|
| - Args:
|
| - hidden -
|
| - True: This object will be excluded from printing when the config blob
|
| - is rendered with ConfigGroup.as_jsonish(). You still have full
|
| - read/write access to this blob otherwise though.
|
| - False: This will be printed as part of ConfigGroup.as_jsonish()
|
| - AutoHide: This will be printed as part of ConfigGroup.as_jsonish() only
|
| - if self._is_default() is false.
|
| - """
|
| - # work around subclasses which override __setattr__
|
| - object.__setattr__(self, '_hidden_mode', hidden)
|
| - object.__setattr__(self, '_inclusions', set())
|
| -
|
| - def get_val(self):
|
| - """Gets the native value of this config object."""
|
| - return self
|
| -
|
| - def set_val(self, val):
|
| - """Resets the value of this config object using data in val."""
|
| - raise NotImplementedError
|
| -
|
| - def reset(self):
|
| - """Resets the value of this config object to it's initial state."""
|
| - raise NotImplementedError
|
| -
|
| - def as_jsonish(self, include_hidden=False):
|
| - """Returns the value of this config object as simple types."""
|
| - raise NotImplementedError
|
| -
|
| - def complete(self):
|
| - """Returns True iff this configuraton blob is fully viable."""
|
| - raise NotImplementedError
|
| -
|
| - def _is_default(self):
|
| - """Returns True iff this configuraton blob is the default value."""
|
| - raise NotImplementedError
|
| -
|
| - @property
|
| - def _hidden(self):
|
| - """Returns True iff this configuraton blob is hidden."""
|
| - if self._hidden_mode is AutoHide:
|
| - return self._is_default()
|
| - return self._hidden_mode
|
| -
|
| -
|
| -class ConfigGroup(ConfigBase):
|
| - """Allows you to provide hierarchy to a configuration schema.
|
| -
|
| - Example usage:
|
| - config_blob = ConfigGroup(
|
| - some_item = SimpleConfig(str),
|
| - group = ConfigGroup(
|
| - numbahs = SetConfig(int),
|
| - ),
|
| - )
|
| - config_blob.some_item = "hello"
|
| - config_blob.group.numbahs.update(range(10))
|
| - """
|
| -
|
| - def __init__(self, hidden=AutoHide, **type_map):
|
| - """Expects type_map to be {python_name -> ConfigBase} instance."""
|
| - super(ConfigGroup, self).__init__(hidden)
|
| - assert type_map, 'A ConfigGroup with no type_map is meaningless.'
|
| -
|
| - object.__setattr__(self, '_type_map', type_map)
|
| - for name, typeval in self._type_map.iteritems():
|
| - typeAssert(typeval, ConfigBase)
|
| - object.__setattr__(self, name, typeval)
|
| -
|
| - def __getattribute__(self, name):
|
| - obj = object.__getattribute__(self, name)
|
| - if isinstance(obj, ConfigBase):
|
| - return obj.get_val()
|
| - else:
|
| - return obj
|
| -
|
| - def __setattr__(self, name, val):
|
| - obj = object.__getattribute__(self, name)
|
| - typeAssert(obj, ConfigBase)
|
| - obj.set_val(val)
|
| -
|
| - def __delattr__(self, name):
|
| - obj = object.__getattribute__(self, name)
|
| - typeAssert(obj, ConfigBase)
|
| - obj.reset()
|
| -
|
| - def set_val(self, val):
|
| - if isinstance(val, ConfigBase):
|
| - val = val.as_jsonish(include_hidden=True)
|
| - if isinstance(val, infra_types.FrozenDict):
|
| - val = infra_types.thaw(val)
|
| - typeAssert(val, dict)
|
| -
|
| - val = dict(val) # because we pop later.
|
| - for name, config_obj in self._type_map.iteritems():
|
| - if name in val:
|
| - try:
|
| - config_obj.set_val(val.pop(name))
|
| - except Exception as e:
|
| - raise Exception('While assigning key %r: %s' % (name, e))
|
| -
|
| - if val:
|
| - raise TypeError("Got extra keys while setting ConfigGroup: %s" % val)
|
| -
|
| - def as_jsonish(self, include_hidden=False):
|
| - return dict(
|
| - (n, v.as_jsonish(include_hidden)) for n, v in self._type_map.iteritems()
|
| - if include_hidden or not v._hidden) # pylint: disable=W0212
|
| -
|
| - def reset(self):
|
| - for v in self._type_map.values():
|
| - v.reset()
|
| -
|
| - def complete(self):
|
| - return all(v.complete() for v in self._type_map.values())
|
| -
|
| - def _is_default(self):
|
| - # pylint: disable=W0212
|
| - return all(v._is_default() for v in self._type_map.values())
|
| -
|
| -
|
| -class ConfigList(ConfigBase, collections.MutableSequence):
|
| - """Allows you to provide an ordered repetition to a configuration schema.
|
| -
|
| - Example usage:
|
| - config_blob = ConfigGroup(
|
| - some_items = ConfigList(
|
| - lambda: ConfigGroup(
|
| - herp = SimpleConfig(int),
|
| - derp = SimpleConfig(str)
|
| - )
|
| - )
|
| - )
|
| - config_blob.some_items.append({'herp': 1})
|
| - config_blob.some_items[0].derp = 'bob'
|
| - """
|
| -
|
| - def __init__(self, item_schema, hidden=AutoHide):
|
| - """
|
| - Args:
|
| - item_schema: The schema of each object. Should be a function which returns
|
| - an instance of ConfigGroup.
|
| - """
|
| - super(ConfigList, self).__init__(hidden=hidden)
|
| - typeAssert(item_schema, types.FunctionType)
|
| - typeAssert(item_schema(), ConfigGroup)
|
| - self.item_schema = item_schema
|
| - self.data = []
|
| -
|
| - def __getitem__(self, index):
|
| - return self.data.__getitem__(index)
|
| -
|
| - def __setitem__(self, index, value):
|
| - datum = self.item_schema()
|
| - datum.set_val(value)
|
| - return self.data.__setitem__(index, datum)
|
| -
|
| - def __delitem__(self, index):
|
| - return self.data.__delitem__(index)
|
| -
|
| - def __len__(self):
|
| - return len(self.data)
|
| -
|
| - def insert(self, index, value):
|
| - datum = self.item_schema()
|
| - datum.set_val(value)
|
| - return self.data.insert(index, datum)
|
| -
|
| - def add(self):
|
| - self.append({})
|
| - return self[-1]
|
| -
|
| - def reset(self):
|
| - self.data = []
|
| -
|
| - def complete(self):
|
| - return all(i.complete() for i in self.data)
|
| -
|
| - def set_val(self, data):
|
| - if isinstance(data, ConfigList):
|
| - data = data.as_jsonish(include_hidden=True)
|
| -
|
| - typeAssert(data, list)
|
| - self.reset()
|
| - for item in data:
|
| - self.append(item)
|
| -
|
| - def as_jsonish(self, include_hidden=False):
|
| - return [i.as_jsonish(include_hidden) for i in self.data
|
| - if include_hidden or not i._hidden] # pylint: disable=W0212
|
| -
|
| - def _is_default(self):
|
| - # pylint: disable=W0212
|
| - return all(v._is_default() for v in self.data)
|
| -
|
| -
|
| -class Dict(ConfigBase, collections.MutableMapping):
|
| - """Provides a semi-homogenous dict()-like configuration object."""
|
| -
|
| - def __init__(self, item_fn=lambda i: i, jsonish_fn=dict, value_type=None,
|
| - hidden=AutoHide):
|
| - """
|
| - Args:
|
| - item_fn - A function which renders (k, v) pairs to input items for
|
| - jsonish_fn. Defaults to the identity function.
|
| - jsonish_fn - A function which renders a list of outputs of item_fn to a
|
| - JSON-compatiple python datatype. Defaults to dict().
|
| - value_type - A type object used for constraining/validating the values
|
| - assigned to this dictionary.
|
| - hidden - See ConfigBase.
|
| - """
|
| - super(Dict, self).__init__(hidden)
|
| - self.value_type = value_type
|
| - self.item_fn = item_fn
|
| - self.jsonish_fn = jsonish_fn
|
| - self.data = {}
|
| -
|
| - def __getitem__(self, k):
|
| - return self.data.__getitem__(k)
|
| -
|
| - def __setitem__(self, k, v):
|
| - if self.value_type:
|
| - typeAssert(v, self.value_type)
|
| - return self.data.__setitem__(k, v)
|
| -
|
| - def __delitem__(self, k):
|
| - return self.data.__delitem__(k)
|
| -
|
| - def __iter__(self):
|
| - return iter(self.data)
|
| -
|
| - def __len__(self):
|
| - return len(self.data)
|
| -
|
| - def set_val(self, val):
|
| - if isinstance(val, Dict):
|
| - val = val.data
|
| - if isinstance(val, infra_types.FrozenDict):
|
| - val = dict(val)
|
| -
|
| - typeAssert(val, dict)
|
| - for v in val.itervalues():
|
| - typeAssert(v, self.value_type)
|
| - self.data = val
|
| -
|
| - def as_jsonish(self, _include_hidden=None):
|
| - return self.jsonish_fn(map(
|
| - self.item_fn, sorted(self.data.iteritems(), key=lambda x: x[0])))
|
| -
|
| - def reset(self):
|
| - self.data.clear()
|
| -
|
| - def complete(self):
|
| - return True
|
| -
|
| - def _is_default(self):
|
| - return not self.data
|
| -
|
| -
|
| -class List(ConfigBase, collections.MutableSequence):
|
| - """Provides a semi-homogenous list()-like configuration object."""
|
| -
|
| - def __init__(self, inner_type, jsonish_fn=list, hidden=AutoHide):
|
| - """
|
| - Args:
|
| - inner_type - The type of data contained in this set, e.g. str, int, ...
|
| - Can also be a tuple of types to allow more than one type.
|
| - jsonish_fn - A function used to reduce the list() to a JSON-compatible
|
| - python datatype. Defaults to list().
|
| - hidden - See ConfigBase.
|
| - """
|
| - super(List, self).__init__(hidden)
|
| - self.inner_type = inner_type
|
| - self.jsonish_fn = jsonish_fn
|
| - self.data = []
|
| -
|
| - def __getitem__(self, index):
|
| - return self.data[index]
|
| -
|
| - def __setitem__(self, index, value):
|
| - typeAssert(value, self.inner_type)
|
| - self.data[index] = value
|
| -
|
| - def __delitem__(self, index):
|
| - del self.data
|
| -
|
| - def __len__(self):
|
| - return len(self.data)
|
| -
|
| - def __radd__(self, other):
|
| - if not isinstance(other, list):
|
| - other = list(other)
|
| - return other + self.data
|
| -
|
| - def insert(self, index, value):
|
| - typeAssert(value, self.inner_type)
|
| - self.data.insert(index, value)
|
| -
|
| - def set_val(self, val):
|
| - for v in val:
|
| - typeAssert(v, self.inner_type)
|
| - self.data = list(val)
|
| -
|
| - def as_jsonish(self, _include_hidden=None):
|
| - return self.jsonish_fn(self.data)
|
| -
|
| - def reset(self):
|
| - self.data = []
|
| -
|
| - def complete(self):
|
| - return True
|
| -
|
| - def _is_default(self):
|
| - return not self.data
|
| -
|
| -
|
| -class Set(ConfigBase, collections.MutableSet):
|
| - """Provides a semi-homogenous set()-like configuration object."""
|
| -
|
| - def __init__(self, inner_type, jsonish_fn=list, hidden=AutoHide):
|
| - """
|
| - Args:
|
| - inner_type - The type of data contained in this set, e.g. str, int, ...
|
| - Can also be a tuple of types to allow more than one type.
|
| - jsonish_fn - A function used to reduce the set() to a JSON-compatible
|
| - python datatype. Defaults to list().
|
| - hidden - See ConfigBase.
|
| - """
|
| - super(Set, self).__init__(hidden)
|
| - self.inner_type = inner_type
|
| - self.jsonish_fn = jsonish_fn
|
| - self.data = set()
|
| -
|
| - def __contains__(self, val):
|
| - return val in self.data
|
| -
|
| - def __iter__(self):
|
| - return iter(self.data)
|
| -
|
| - def __len__(self):
|
| - return len(self.data)
|
| -
|
| - def add(self, value):
|
| - typeAssert(value, self.inner_type)
|
| - self.data.add(value)
|
| -
|
| - def update(self, values):
|
| - for value in values:
|
| - if value not in self:
|
| - self.add(value)
|
| -
|
| - def discard(self, value):
|
| - self.data.discard(value)
|
| -
|
| - def set_val(self, val):
|
| - for v in val:
|
| - typeAssert(v, self.inner_type)
|
| - self.data = set(val)
|
| -
|
| - def as_jsonish(self, _include_hidden=None):
|
| - return self.jsonish_fn(sorted(self.data))
|
| -
|
| - def reset(self):
|
| - self.data = set()
|
| -
|
| - def complete(self):
|
| - return True
|
| -
|
| - def _is_default(self):
|
| - return not self.data
|
| -
|
| -
|
| -class Single(ConfigBase):
|
| - """Provides a configuration object which holds a single 'simple' type."""
|
| -
|
| - def __init__(self, inner_type, jsonish_fn=lambda x: x, empty_val=None,
|
| - required=True, hidden=AutoHide):
|
| - """
|
| - Args:
|
| - inner_type - The type of data contained in this object, e.g. str, int, ...
|
| - Can also be a tuple of types to allow more than one type.
|
| - jsonish_fn - A function used to reduce the data to a JSON-compatible
|
| - python datatype. Default is the identity function.
|
| - empty_val - The value to use when initializing this object or when calling
|
| - reset().
|
| - required(bool) - True iff this config item is required to have a
|
| - non-empty_val in order for it to be considered complete().
|
| - hidden - See ConfigBase.
|
| - """
|
| - super(Single, self).__init__(hidden)
|
| - self.inner_type = inner_type
|
| - self.jsonish_fn = jsonish_fn
|
| - self.empty_val = empty_val
|
| - self.data = empty_val
|
| - self.required = required
|
| -
|
| - def get_val(self):
|
| - return self.data
|
| -
|
| - def set_val(self, val):
|
| - if isinstance(val, Single):
|
| - val = val.data
|
| - if val is not self.empty_val:
|
| - typeAssert(val, self.inner_type)
|
| - self.data = val
|
| -
|
| - def as_jsonish(self, _include_hidden=None):
|
| - return self.jsonish_fn(self.data)
|
| -
|
| - def reset(self):
|
| - self.data = self.empty_val
|
| -
|
| - def complete(self):
|
| - return not self.required or self.data is not self.empty_val
|
| -
|
| - def _is_default(self):
|
| - return self.data is self.empty_val
|
| -
|
| -
|
| -class Static(ConfigBase):
|
| - """Holds a single, hidden, immutible data object.
|
| -
|
| - This is very useful for holding the 'input' configuration values.
|
| - """
|
| -
|
| - def __init__(self, value, hidden=AutoHide):
|
| - super(Static, self).__init__(hidden=hidden)
|
| - # Attempt to hash the value, which will ensure that it's immutable all the
|
| - # way down :).
|
| - hash(value)
|
| - self.data = value
|
| -
|
| - def get_val(self):
|
| - return self.data
|
| -
|
| - def set_val(self, val):
|
| - raise TypeError("Cannot assign to a Static config member")
|
| -
|
| - def as_jsonish(self, _include_hidden=None):
|
| - return self.data
|
| -
|
| - def reset(self):
|
| - assert False
|
| -
|
| - def complete(self):
|
| - return True
|
| -
|
| - def _is_default(self):
|
| - return True
|
|
|