Source code for qudi.core.configoption

# -*- coding: utf-8 -*-
"""
ConfigOption object to be used in qudi modules. The value of each ConfigOption can
(if it has a default value) or must be specified by the user in the config file.
Usually these values should be constant for the duration of a qudi session.

.. Copyright (c) 2021, the qudi developers. See the AUTHORS.md file at the top-level directory of this
.. distribution and on <https://github.com/Ulm-IQO/qudi-core/>
..
.. This file is part of qudi.
..
.. Qudi is free software: you can redistribute it and/or modify it under the terms of
.. the GNU Lesser General Public License as published by the Free Software Foundation,
.. either version 3 of the License, or (at your option) any later version.
..
.. Qudi 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 Lesser General Public License for more details.
..
.. You should have received a copy of the GNU Lesser General Public License along with qudi.
.. If not, see <https://www.gnu.org/licenses/>.
"""

__all__ = ["ConfigOption", "MissingOption"]

import copy
import inspect
from enum import Enum
from typing import Any, Optional, Callable


[docs] class MissingOption(Enum): """Representation for missing ConfigOption""" error = -3 warn = -2 info = -1 nothing = 0
[docs] class ConfigOption: """This class represents a configuration entry in the config file that is loaded before module initalisation. """ def __init__( self, name: Optional[str] = None, default: Optional[Any] = None, *, missing: Optional[str] = "nothing", constructor: Optional[Callable] = None, checker: Optional[Callable] = None, converter: Optional[Callable] = None, ): """Create a ConfigOption object. Parameters ---------- name : Optional[str], optional Identifier of the option in the configuration file. default : Optional[Any], optional Default value for the case that the option is not set in the config file. missing : Optional[str], optional Action to take when the option is not set. 'nothing' does nothing, 'warn' logs a warning, 'error' logs an error and prevents the module from loading. constructor : Optional[Callable], optional Constructor function for complex config option behavior. checker : Optional[Callable], optional Static function that checks if value is okay. converter : Optional[Callable], optional Static function that forces type interpretation. """ self.missing = MissingOption[missing] self.name = name self.default = default self.checker = checker self.converter = converter self.constructor_function = None if constructor is not None: self.constructor(constructor) def __set_name__(self, owner, name): if self.name is None: self.name = name def __copy__(self): return self.copy() def __deepcopy__(self, memodict={}): return self.copy() @property def optional(self) -> bool: return self.missing != MissingOption.error
[docs] def copy(self, **kwargs): """Create a new instance of ConfigOption with copied values and update. Parameters ---------- **kwargs Extra arguments or overrides for the constructor of this class. """ newargs = { "name": self.name, "default": copy.deepcopy(self.default), "missing": self.missing.name, "constructor": self.constructor_function, "checker": self.checker, "converter": self.converter, } newargs.update(kwargs) return ConfigOption(**newargs)
[docs] def check(self, value: Any) -> bool: """If checker function set, check value. Assume everything is ok otherwise.""" if callable(self.checker): return self.checker(value) return True
[docs] def convert(self, value: Any) -> Any: """If converter function set, convert value (pass-through otherwise).""" if callable(self.converter): return self.converter(value) return value
[docs] def constructor(self, func: Callable) -> Callable: """Decorator for declaring a constructor function for this ConfigOption. Parameters ---------- func : Callable Constructor function for this ConfigOption. Returns ------- Callable Returns the original function so it can be used as a decorator. """ self.constructor_function = self._assert_func_signature(func) return func
@staticmethod def _assert_func_signature(func: Callable) -> Callable: assert callable(func), "ConfigOption constructor must be callable" params = tuple(inspect.signature(func).parameters) assert 0 < len(params) < 3, ( "ConfigOption constructor must be function with " "1 (static) or 2 (bound method) parameters." ) if len(params) == 1: def wrapper(instance, value): return func(value) return wrapper return func