Source code for qmflows._settings

"""Settings use to describe the input of a Quantum chemistry package."""

__all__ = ['Settings']

from functools import wraps
from typing import Callable, NoReturn, Any, TypeVar, Mapping

from scm import plams

_Self = TypeVar("_Self", bound="Settings")


[docs]class Settings(plams.core.settings.Settings, ): """A subclass of :class:`plams.Settings<scm.plams.core.settings.Settings>`. The difference with respect to plams' Settings are: - :code:`settings['a.b']` is equivalent to :code:`settings['a']['b'] = settings.a.b` """
[docs] def __getitem__(self, name: str) -> Any: """Implement :meth:`self[name]<object.__getitem__>`.""" return dict.__getitem__(self, name)
[docs] def __setitem__(self, name: str, value: Any) -> None: """Implement :meth:`self[name] = value<object.__setitem__>`. Like its counterpart in :class:`dict` but passed dictionaries are converted into instances of :class:`type(self)<Settings>`. """ if isinstance(value, dict): cls = type(self) value = cls(value) dict.__setitem__(self, name, value)
[docs] def __delitem__(self, name: str) -> Any: """Implement :meth:`del self[name]<object.__delitem__>`.""" dict.__delitem__(self, name)
[docs] def copy(self: _Self) -> _Self: """Create a deep(-ish) copy of this instance. All nested settings instances embedded within *self* are copied recursively; all other objects set without copying. """ cls = type(self) ret = cls() for name in self: if isinstance(self[name], plams.core.settings.Settings): ret[name] = self[name].copy() else: ret[name] = self[name] return ret
[docs] def __deepcopy__(self: _Self, _: object) -> _Self: """Implement :func:`copy.deepcopy(self)<copy.deepcopy>`. Serves as an alias for :meth:`Settings.copy`. """ return self.copy()
[docs] def overlay(self: _Self, other: Mapping[str, Any]) -> _Self: """Return new instance of :class:`~qmflows.Settings` that is a copy of this instance updated with *other*.""" # noqa: E501 ret = self.copy() ret.update(other) return ret
def _unsuported_operation(meth: Callable[..., Any]) -> Callable[..., NoReturn]: """Decorate a method such that it raises a :exc:`TypeError`.""" @wraps(meth) def new_meth(self, *args, **kwargs) -> NoReturn: raise TypeError(f"{self.__class__.__name__!r} does not " "support item assignment or deletion") return new_meth def _super_method(meth: Callable[..., '_Settings']) -> Callable[..., '_Settings']: """Decorate a method such that it's body is executed by the super-class.""" @wraps(meth) def new_meth(self, *args, **kwargs) -> '_Settings': cls = type(self) func = getattr(super(), meth.__name__) ret = func(*args, **kwargs) return cls(ret) return new_meth class _Settings(Settings): """Immutable-ish counterpart of :class:`Settings`.""" def __init__(self, *args, **kwargs): """Initialize an instance.""" cls = type(self) set_item = super().__setitem__ dict.__init__(self, *args, **kwargs) for k, v in self.items(): if isinstance(v, dict): set_item(k, cls(v)) elif isinstance(v, list): set_item(k, [cls(i) if isinstance(i, dict) else i for i in v]) def __missing__(self, name: str) -> NoReturn: """Raise a :exc:`KeyError`.""" raise KeyError(name) __setitem__ = _unsuported_operation(Settings.__setitem__) __delitem__ = _unsuported_operation(Settings.__delitem__) clear = _unsuported_operation(Settings.clear) popitem = _unsuported_operation(Settings.popitem) setdefault = _unsuported_operation(Settings.setdefault) update = _unsuported_operation(Settings.update) overlay = _super_method(Settings.overlay) merge = _super_method(Settings.merge) copy = _super_method(Settings.copy) flatten = _super_method(Settings.flatten) __init__.__doc__ = Settings.__init__.__doc__