Source code for run_aster.settings

# coding=utf-8
# --------------------------------------------------------------------
# Copyright (C) 1991 - 2026 - EDF - www.code-aster.org
# This file is part of code_aster.
#
# code_aster is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# code_aster is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with code_aster.  If not, see <http://www.gnu.org/licenses/>.
# --------------------------------------------------------------------

"""
:py:mod:`settings` --- Objects to deal with settings
----------------------------------------------------

:py:class:`Store` is a general storage object that holds various kinds
of settings as typed parameters.

The base object is the :py:class:`AbstractParameter` object from which are
derivated objects to store values of type *str*, *int*, *float*, *bool* and
list of *str*.
"""

import os
from string import Template

from .logger import logger

DEPRECATED = "__DEPRECATED__"


[docs]class AbstractParameter: """An abstract parameter that must be subclassed to hold a typed value."""
[docs] def __init__(self, name): self._name = name self._value = None
@property def name(self): """str: Parameter name.""" return self._name @property def value(self): """misc: Value of the parameter.""" return self._value
[docs] def convert(self, value): """Convert a value for the parameter type.""" try: return self._convert(value) except (TypeError, ValueError) as exc: logger.error("Parameter %r: %s", self.name, exc, exception=exc)
def _convert(self, value): raise NotImplementedError("must be subclassed!")
[docs] def set(self, value): """Convert and set the value. Arguments: value (misc): New value. """ self._value = self.convert(value)
[docs] @classmethod def factory(cls, store_typed_params, name): """Create a Parameter of the right type. Arguments: store_typed_params (dict): Dict of parameters supported by the :py:class:`Store` giving the excpected type. name (str): Parameter name. """ typ = store_typed_params.get(name) if typ is None: logger.warning("unknown parameter: %r", name) return None if typ == DEPRECATED: return None klass = cls._typed_subclasses(typ) if not klass: raise TypeError(typ) return klass(name)
[docs] @staticmethod def _typed_subclasses(typ): """Return the subclass for the expected type or *None* if not found.""" return { "str": ParameterStr, "varstr": ParameterVarStr, "bool": ParameterBool, "int": ParameterInt, "float": ParameterFloat, "list[str]": ParameterListStr, "varlist[str]": ParameterVarListStr, "dict[str]": ParameterDictStr, }.get(typ)
[docs]class ParameterStr(AbstractParameter): """A parameter defined in a Export object of type string. It may use environment variable "${VAR}", substitution is only done once when the value is assigned. """ @staticmethod def _convert(value): if isinstance(value, (list, tuple)): value = " ".join([str(i) for i in value]) if not value: return value value = str(value) if "$" in value: try: value = Template(value).substitute(os.environ) except (KeyError, ValueError): pass return value
[docs]class VarMixin: """Mixin class for a parameter that may be overridden by environment."""
[docs] def set(self, value): """Convert and set the value. Arguments: value (misc): New value. """ self._value = self.convert(os.environ.get(self._name, value))
[docs]class ParameterVarStr(VarMixin, ParameterStr): """A parameter defined in a Export object of type string that may be overridden by an environment variable."""
[docs]class ParameterBool(AbstractParameter): """A parameter defined in a Export object of type boolean.""" @staticmethod def _convert(value): if isinstance(value, (list, tuple)): value = " ".join([str(i) for i in value]) if value == "": value = True elif value == "False": value = False return bool(value)
[docs]class ParameterInt(AbstractParameter): """A parameter defined in a Export object of type integer.""" @staticmethod def _convert(value): if isinstance(value, (list, tuple)): value = " ".join([str(i) for i in value]) if value == "": value = 0 return int(float(value))
[docs]class ParameterFloat(AbstractParameter): """A parameter defined in a Export object of type float.""" @staticmethod def _convert(value): if isinstance(value, (list, tuple)): value = " ".join([str(i) for i in value]) if value == "": value = 0.0 return float(value)
[docs]class ParameterListStr(AbstractParameter): """A parameter defined in a Export object of type list of strings.""" @staticmethod def _convert(value): if not isinstance(value, (list, tuple)): value = [value] value = [str(i) for i in value] return value
[docs]class ParameterVarListStr(VarMixin, ParameterListStr): """A parameter defined in a Export object of type list of strings that may be overridden by an environment variable."""
[docs]class ParameterDictStr(AbstractParameter): """A parameter defined in a Export object of type dict of strings.""" @staticmethod def _convert(value): if not isinstance(value, dict): raise TypeError(f"dict expected, not {value}") for key, string in value.items(): if not isinstance(key, str): raise TypeError(f"str expected, not {string}") value[key] = ParameterStr._convert(string) return value
[docs] def set(self, value): """Convert and update the dict. Arguments: value (dict): New value. """ if self._value is None: self._value = {} self._value.update(self.convert(value))
[docs]class Store: """A base object to store some settings. This class must be subclassed and a ``_new_param`` class method must be added to make `set()` method usable. """
[docs] def __init__(self): self._params = {}
[docs] def __len__(self): """Return the storage size. Returns: int: Number of stored parameters. """ return len(self._params)
[docs] def add(self, param): """Add a parameter. Arguments: param (*Parameter*): Parameter object. """ self._params[param.name] = param
[docs] def has_param(self, name): """Tell if `name` is a known parameter. Arguments: name (str): Parameter name. Returns: bool: *True* it the parameter is defined, *False* otherwise. """ return name in self._params
[docs] def get_param(self, name): """Return a parameter. Arguments: name (str): Parameter name. Returns: misc: Parameter or *None* if the parameter does not exist. """ return self._params.get(name)
[docs] def get(self, name, default=None): """Return a parameter value. Arguments: name (str): Parameter name. default (misc, optional): Default value if the parameter does not exist. Returns: misc: Parameter value. """ param = self.get_param(name) return param.value if param and param.value is not None else default
[docs] def set(self, name, value): """Automatically add a parameter of the expected type. Arguments: name (str): Parameter name. value (misc): Parameter value. """ param = self._params.setdefault(name, self._new_param(name)) if not param: del self._params[name] return param.set(value)
[docs] @staticmethod def _new_param(name): """Create a Parameter of the right type.""" return None