Source code for valjean.config

# Copyright French Alternative Energies and Atomic Energy Commission
# Contributors: valjean developers
# valjean-support@cea.fr
#
# This software is a computer program whose purpose is to analyze and
# post-process numerical simulation results.
#
# This software is governed by the CeCILL license under French law and abiding
# by the rules of distribution of free software. You can use, modify and/ or
# redistribute the software under the terms of the CeCILL license as circulated
# by CEA, CNRS and INRIA at the following URL: http://www.cecill.info.
#
# As a counterpart to the access to the source code and rights to copy, modify
# and redistribute granted by the license, users are provided only with a
# limited warranty and the software's author, the holder of the economic
# rights, and the successive licensors have only limited liability.
#
# In this respect, the user's attention is drawn to the risks associated with
# loading, using, modifying and/or developing or reproducing the software by
# the user in light of its specific status of free software, that may mean that
# it is complicated to manipulate, and that also therefore means that it is
# reserved for developers and experienced professionals having in-depth
# computer knowledge. Users are therefore encouraged to load and test the
# software's suitability as regards their requirements in conditions enabling
# the security of their systems and/or data to be ensured and, more generally,
# to use and operate it in the same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.

''':class:`Config` objects encapsulate a set of configuration options for a
:mod:`valjean` run. Here is how you create one:

    >>> from valjean.config import Config
    >>> config = Config()

By default, :class:`Config` objects come with a ``'path'`` configuration
section, which may be used to set default values for any configuration option.
A few options are set from the beginning:

    >>> for opt, val in sorted(config['path'].items()):
    ...     print(f'{opt} = {val}')
    log-root = /.../log
    output-root = /.../output
    report-root = /.../report

The :class:`Config` class behaves like a simple dictionary:

    >>> print(config.query('path', 'report-root'))
    /.../report

Module API
----------
'''

from collections.abc import MutableMapping
from pathlib import Path
import toml


[docs]class Config(MutableMapping): '''The base configuration class for :mod:`valjean`.'''
[docs] @classmethod def from_file(cls, path): '''Construct a configuration object from a TOML file. :param path: A path for the configuration file. :type path: pathlib.Path or str ''' file_content = toml.load(str(path)) return cls(file_content)
[docs] def __init__(self, dictionary=None): '''Construct a configuration object from a dictionary. The configuration will be initialized to contain a few default options. :param dict dictionary: The configuration object. :returns: The constructed Config object. ''' self.conf = dict(dictionary) if dictionary is not None else {} # sanity check if 'path' in self.conf and not isinstance(self.conf['path'], dict): raise ValueError('the "path" option is forbidden at the top level') # Set some default options if 'path' not in self: self['path'] = {} conf_path = self['path'] work_dir = Path.cwd() if 'log-root' not in conf_path: conf_path['log-root'] = f'{work_dir}/log' if 'output-root' not in conf_path: conf_path['output-root'] = f'{work_dir}/output' if 'report-root' not in conf_path: conf_path['report-root'] = f'{work_dir}/report'
def __getitem__(self, key): return self.conf[key] def __setitem__(self, key, value): self.conf[key] = value def __delitem__(self, key): del self.conf[key] def __iter__(self): yield from self.conf def __len__(self): return len(self.conf)
[docs] def __eq__(self, other): if not isinstance(other, Config): return False return self.conf == other.conf
[docs] def __ne__(self, other): return not self == other
[docs] def __str__(self): return toml.dumps(self.conf)
[docs] def __repr__(self): return f'Config({self.conf})'
[docs] def query(self, section, option): '''Return the value of `option` from `section`.''' return self.conf[section][option]
[docs] def set(self, section, option, value): '''Set the value of `option` in `section` to be `value`.''' self.conf[section][option] = value