diff --git a/bob/extension/config.py b/bob/extension/config.py index 05962451d66b006669356d9617d77e61e73c9029..2faeaa3d3c3ddb5da5fcd29ac6ef69d5143ab474 100644 --- a/bob/extension/config.py +++ b/bob/extension/config.py @@ -5,7 +5,6 @@ import os import imp -import six import collections import logging @@ -53,7 +52,7 @@ def _load_context(path, context): return dict((k,v) for k,v in retval.__dict__.items() if not k.startswith('_')) -def load(path, context=None): +def load(paths, context=None): '''Loads a set of configuration files, in sequence This method will load one or more configuration files. Everytime a @@ -63,10 +62,10 @@ def load(path, context=None): Parameters: - path (:py:class:`str`, :py:class:`list`): The full path of the Python file - to load the module contents from. If an iterable is passed, then it is - iterated and each configuration file is loaded by creating/modifying the - context generated after each file readout. + paths (:py:class:`list`): A list or iterable containing paths (relative or + absolute) of configuration files that need to be loaded in sequence. + Each configuration file is loaded by creating/modifying the context + generated after each file readout. context (:py:class:`dict`, Optional): If passed, start the readout of the first configuration file with the given context. Otherwise, create a new @@ -80,24 +79,16 @@ def load(path, context=None): ''' - if isinstance(path, six.string_types): - - if context is None: - context = dict(defaults={}) - else: - if 'defaults' not in context: - context['defaults'] = {} - - return _load_context(os.path.realpath(os.path.expanduser(path)), context) - - elif isinstance(path, collections.Iterable): - - for k in path: context = load(k, context) - return context - + if context is None: + context = dict(defaults={}) else: + if 'defaults' not in context: + context['defaults'] = {} + + for k in paths: + context = _load_context(os.path.realpath(os.path.expanduser(k)), context) - raise TypeError('path must be either a string or iterable over strings') + return context def loadrc(context=None): @@ -138,4 +129,4 @@ def loadrc(context=None): logger.debug("No RC file found", path) return {} - return load(path, context) + return load([path], context) diff --git a/bob/extension/test_config.py b/bob/extension/test_config.py new file mode 100644 index 0000000000000000000000000000000000000000..0732f527c3668abcfd482d1411e4f42cc6c98f8a --- /dev/null +++ b/bob/extension/test_config.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : + +'''Tests for the config module and functionality''' + + +import os +import pkg_resources +path = pkg_resources.resource_filename('bob.extension', 'data') + +from .config import load, loadrc, ENVNAME + + +def test_basic(): + + c = load([os.path.join(path, 'basic-config.py')]) + assert c == {'a': 1, 'b': 3, 'defaults': {}} + + +def test_defaults(): + + c = load([os.path.join(path, 'defaults-config.py')]) + assert c == {'defaults': {'bob.db.atnt': {'directory': '/directory/to/root/of/atnt-database', 'extension': '.ppm'} } } + + +def test_chain_loading(): + + file1 = os.path.join(path, 'defaults-config.py') + file2 = os.path.join(path, 'load-config.py') + c = load([file1, file2]) + assert c == {'defaults': {'bob.db.atnt': {'directory': '/directory/to/root/of/atnt-database', 'extension': '.hdf5'} } } + + +def test_rc_env(): + + os.environ[ENVNAME] = os.path.join(path, 'basic-config.py') + c = loadrc() #should load from environment variable + assert c == {'a': 1, 'b': 3, 'defaults': {}} diff --git a/doc/config.rst b/doc/config.rst index f36eb4d0d61671fcb877134126822b2de4b16f9f..d05a7d1bc40bcf73ed60e6e1bd304cc8e8e394c9 100644 --- a/doc/config.rst +++ b/doc/config.rst @@ -13,7 +13,7 @@ programs while configuring, import modules, create classes and more. The configuration system is centered around a single function called :py:func:`bob.extension.config.load`. You call it to load the configuration -objects from a given configuration file, like this: +objects from one or more configuration files, like this: .. testsetup:: * @@ -26,7 +26,7 @@ objects from a given configuration file, like this: >>> from bob.extension.config import load >>> #the variable `path` points to <path-to-bob.extension's root>/data - >>> configuration = load(os.path.join(path, 'basic-config.py')) + >>> configuration = load([os.path.join(path, 'basic-config.py')]) If the function :py:func:`bob.extension.config.load` succeeds, it returns a @@ -100,7 +100,7 @@ When loaded, this configuration file produces the result: .. doctest:: defaults-config >>> #the variable `path` points to <path-to-bob.extension's root>/data - >>> configuration = load(os.path.join(path, 'defaults-config.py')) + >>> configuration = load([os.path.join(path, 'defaults-config.py')]) >>> print(json.dumps(configuration, indent=2, sort_keys=True)) # doctest: +NORMALIZE_WHITESPACE { "defaults": { @@ -126,9 +126,9 @@ Chain Loading ------------- It is possible to implement chain configuration loading and overriding by -either calling :py:func:`bob.extension.config.load` many times or by passing -iterables with filenames to that function. Suppose we have two configuration -files which must be loaded in sequence: +passing iterables with more than one filename to +:py:func:`bob.extension.config.load`. Suppose we have two configuration files +which must be loaded in sequence: .. literalinclude:: ../bob/extension/data/defaults-config.py :caption: "defaults-config.py" (first to be loaded) diff --git a/setup.py b/setup.py index 5722d3694bd29479162b427c720f35ea5ad774fa..4f96474a18e9ecb07c0f40ae1b9a2a21ff860855 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ from setuptools import setup, find_packages # Define package version version = open("version.txt").read().rstrip() -requires = ['setuptools', 'six'] +requires = ['setuptools'] import sys if sys.version_info[0] == 2 and sys.version_info[1] <= 6: requires.append('importlib')