LOG = _get_basic_logger(__name__)
-from .tools import _PackageConfig
+from .tools import PackageConfig as _PackageConfig
package_config = _PackageConfig(package_name=__name__, logger=LOG)
"""
-class _Setting (object):
+class Setting (object):
"A named setting with arbitrart text values."
def __init__(self, name, help='', default=None):
self.name = name
return value
-class _ChoiceSetting (_Setting):
+class ChoiceSetting (Setting):
"""A named setting with a limited number of possible values.
`choices` should be a list of `(config_file_value, Python value)`
pairs. For example
- >>> s = _ChoiceSetting(name='bool',
- ... choices=[('yes', True), ('no', False)])
+ >>> s = ChoiceSetting(name='bool',
+ ... choices=[('yes', True), ('no', False)])
>>> s.convert_from_text('yes')
True
>>> s.convert_to_text(True)
if 'default' not in kwargs:
if None not in [keyval[1] for keyval in choices]:
kwargs['default'] = choices[0][1]
- super(_ChoiceSetting, self).__init__(**kwargs)
+ super(ChoiceSetting, self).__init__(**kwargs)
if choices == None:
choices = []
self.choices = choices
def help(self):
ret = '%s Choices: %s' % (
- super(_ChoiceSetting, self).help(),
+ super(ChoiceSetting, self).help(),
', '.join([key for key,value in self.choices]))
return ret.strip()
raise ValueError(value)
-class _BooleanSetting (_ChoiceSetting):
+class BooleanSetting (ChoiceSetting):
"""A named settubg that can be either true or false.
- >>> s = _BooleanSetting(name='bool')
+ >>> s = BooleanSetting(name='bool')
>>> s.convert_from_text('yes')
True
assert 'choices' not in kwargs
if 'default' not in kwargs:
kwargs['default'] = False
- super(_BooleanSetting, self).__init__(
+ super(BooleanSetting, self).__init__(
choices=[('yes', True), ('no', False)], **kwargs)
-class _NumericSetting (_Setting):
+class NumericSetting (Setting):
"""A named setting with numeric values.
Don't use this setting class. Use a more specific subclass, such
- as `_IntegerSetting`.
+ as `IntegerSetting`.
- >>> s = _NumericSetting(name='float')
+ >>> s = NumericSetting(name='float')
>>> s.default
0
>>> s.convert_to_text(13)
def __init__(self, **kwargs):
if 'default' not in kwargs:
kwargs['default'] = self._default_value
- super(_NumericSetting, self).__init__(**kwargs)
+ super(NumericSetting, self).__init__(**kwargs)
def convert_to_text(self, value):
return str(value)
raise NotImplementedError()
-class _IntegerSetting (_NumericSetting):
+class IntegerSetting (NumericSetting):
"""A named setting with integer values.
- >>> s = _IntegerSetting(name='int')
+ >>> s = IntegerSetting(name='int')
>>> s.default
1
>>> s.convert_from_text('8')
return int(value)
-class _FloatSetting (_NumericSetting):
+class FloatSetting (NumericSetting):
"""A named setting with floating point values.
- >>> s = _FloatSetting(name='float')
+ >>> s = FloatSetting(name='float')
>>> s.default
1.0
>>> s.convert_from_text('8')
return float(value)
-class _FloatListSetting (_Setting):
+class FloatListSetting (Setting):
"""A named setting with a list of floating point values.
- >>> s = _FloatListSetting(name='floatlist')
+ >>> s = FloatListSetting(name='floatlist')
>>> s.default
[]
>>> s.convert_to_text([1, 2.3])
def __init__(self, **kwargs):
if 'default' not in kwargs:
kwargs['default'] = []
- super(_FloatListSetting, self).__init__(**kwargs)
+ super(FloatListSetting, self).__init__(**kwargs)
def _convert_from_text(self, value):
if value is None:
return ', '.join([str(x) for x in value])
-class _Config (dict):
- "A class with a list `._keys` of `_Setting`\s."
+class Config (dict):
+ "A class with a list `._keys` of `Setting`\s."
settings = []
def __init__(self):
def dump(self, help=False):
"""Return all settings and their values as a string
- >>> class _MyConfig (_Config):
+ >>> class MyConfig (Config):
... settings = [
- ... _ChoiceSetting(
+ ... ChoiceSetting(
... name='number',
... help='I have a number behind my back...',
... default=1,
... choices=[('one', 1), ('two', 2),
... ]),
- ... _BooleanSetting(
+ ... BooleanSetting(
... name='odd',
... help='The number behind my back is odd.',
... default=True),
- ... _IntegerSetting(
+ ... IntegerSetting(
... name='guesses',
... help='Number of guesses before epic failure.',
... default=2),
... ]
- >>> c = _MyConfig()
+ >>> c = MyConfig()
>>> print c.dump()
number: one
odd: yes
return '\n'.join(lines)
-class _BackedConfig (_Config):
- "A `_Config` instance with some kind of storage interface"
+class BackedConfig (Config):
+ "A `Config` instance with some kind of storage interface"
def load(self):
raise NotImplementedError()
return lines
-class _HDF5Config (_config._BackedConfig):
+class _HDF5Config (_config.BackedConfig):
"""Mixin to back a `_Config` class with an HDF5 file.
TODO: Special handling for Choice (enums), FloatList (arrays), etc.?
... if obj.endswith('Config')
... and not obj.startswith('_')])
HDF5_TestConfig
+TestConfig
YAML_TestConfig
}
-class _TestConfig (_config._Config):
+class TestConfig (_config.Config):
"Test all the setting types for the h5config module"
settings = [
- _config._ChoiceSetting(
+ _config.ChoiceSetting(
name='species',
help='Type of parrot.',
default=0,
choices=[('Norwegian Blue', 0), ('Macaw', 1)]),
- _config._BooleanSetting(
+ _config.BooleanSetting(
name='alive',
help='The parrot is alive.',
default=False),
- _config._IntegerSetting(
+ _config.IntegerSetting(
name='daisies',
help="Number of daisies pushed up by the parrot.",
default=13),
- _config._FloatSetting(
+ _config.FloatSetting(
name='age',
help='Parrot age in years',
default=1.3),
- _config._FloatListSetting(
+ _config.FloatListSetting(
name='bids',
help='Prices offered for parrot.',
default=[5.4, 3.2, 1]),
classes = []
for name,obj in sorted(globals().items()):
try:
- if issubclass(obj, _TestConfig):
+ if issubclass(obj, TestConfig):
classes.append(obj)
except TypeError:
pass
_os.remove(filename)
def _non_defaults(test_instance):
- for setting in _TestConfig.settings:
+ for setting in TestConfig.settings:
value = test_instance[setting.name]
if value != setting.default:
yield (setting.name, value)
"""Tools for setting up a package using config files.
-The benefit of subclassing `_PackageConfig` over using something like
+The benefit of subclassing `PackageConfig` over using something like
`configparser` is that you can easily store default `h5config` values
in the configuration file. Consider the following example:
from . import util as _util
-class _PackageConfig (_config._Config):
+class PackageConfig (_config.Config):
"""Configure package operation
This basic implementation just creates and manages a package-wide
"""
_backed_subclasses = ()
settings = [
- _config._ChoiceSetting(
+ _config.ChoiceSetting(
name='log-level',
help='Module logging level.',
default=_logging.WARN,
('info', _logging.INFO),
('debug', _logging.DEBUG),
]),
- _config._BooleanSetting(
+ _config.BooleanSetting(
name='syslog',
help='Log to syslog (otherwise log to stderr).',
default=False),
]
def __init__(self, package_name, namespace=None, logger=None, **kwargs):
- super(_PackageConfig, self).__init__(**kwargs)
+ super(PackageConfig, self).__init__(**kwargs)
self._package_name = package_name
if not namespace:
namespace = _sys.modules[package_name]
return [user_basepath, system_basepath, distributed_basepath]
def load_system(self):
- "Return the best `_PackageConfig` match after scanning the filesystem"
+ "Return the best `PackageConfig` match after scanning the filesystem"
self._logger.info('looking for package config file')
basepaths = self._base_paths()
for basepath in basepaths:
self._replace_self(replacement)
-_PackageConfig._clear_class = _PackageConfig
+PackageConfig._clear_class = PackageConfig
_util.build_backend_classes(_sys.modules[__name__])
-_PackageConfig._backed_subclasses = [
+PackageConfig._backed_subclasses = [
('.h5', HDF5_PackageConfig),
('.yaml', YAML_PackageConfig)
]
import os.path as _os_path
from . import LOG as _LOG
-from .config import _Config, _BackedConfig
+from . import config as _config
from .hdf5 import _HDF5Config
from .yaml import _YAMLConfig
def build_backend_classes(namespace, objects=None):
- """Define HDF5- and YAML-backed subclasses of the basic _Config types
+ """Define HDF5- and YAML-backed subclasses of the basic `Config` types
At the end of your class-defining module, you should build the
particular backends. You'll need to pass in a namespace to attach
the new classes to. I generally use `sys.modules[__name__]` to
attach the classes to the current module. By default
- `build_backend_classes` will search for base `_Config` classes in
+ `build_backend_classes` will search for base `Config` classes in
the namespace you pass it. If that doesn't work for you, you can
explicitly pass it an iterable of `name, object)` tuples.
"""
objects = [(name,getattr(namespace, name, None))
for name in dir(namespace)]
for name,obj in objects:
- if (obj != _Config and
+ if (obj != _config.Config and
type(obj) == type and
- issubclass(obj, _Config) and
- not issubclass(obj, _BackedConfig)):
+ issubclass(obj, _config.Config) and
+ not issubclass(obj, _config.BackedConfig)):
for prefix,base in [('HDF5', _HDF5Config), ('YAML', _YAMLConfig)]:
_LOG.debug(
'creating {} backend for {} in the {} namespace'.format(
prefix, name, namespace))
- name_ = '%s%s' % (prefix, name)
+ name_ = '%s_%s' % (prefix, name)
bases = (base, obj)
dict_ = {}
class_ = type(name_, bases, dict_)
_YAMLDumper.add_representer(bool, _YAMLDumper.represent_bool)
-class _YAMLConfig (_config._BackedConfig):
- """Mixin to back a `_Config` class with a YAML file.
+class _YAMLConfig (_config.BackedConfig):
+ """Mixin to back a `Config` class with a YAML file.
TODO: Special handling for Choice (enums), FloatList (arrays), etc.?
settings = dict([(s.name, s) for s in self.settings])
for key,value in data.iteritems():
setting = settings[key]
- if isinstance(setting, _config._BooleanSetting):
+ if isinstance(setting, _config.BooleanSetting):
v = value
else:
v = setting.convert_from_text(value)
for key,value in self.iteritems():
if key in settings:
setting = settings[key]
- if isinstance(setting, _config._BooleanSetting):
+ if isinstance(setting, _config.BooleanSetting):
v = value
else:
v = setting.convert_to_text(value)