Source code for ase2sprkkr.bindings.tests.configuration

""" This module contains just a base class for both configuration values - :class:`Options<ase2sprkkr.common.options.Option>`
and configuration containers - :class:`Sections<ase2sprkkr.common.configuration_containers.Section>`.
"""

from typing import Union
from .warnings import DataValidityWarning, DataValidityError
import warnings


[docs] class Configuration: """ The common base class for all configurations values and containers. I.e. for :class:`Options<ase2sprkkr.common.options.Option>` and :class:`Sections<ase2sprkkr.common.configuration_containers.Section>`. """
[docs] def __init__(self, definition, container=None): """ Create the object. Just sets the two properties from the parameters. Parameters ---------- definition: ase2sprkkr.common.configuration_definitions.BaseDefinition Definition of this configuration object. container: ase2sprkkr.common.configuration_containers.ConfigurationContainer The container, that owns this configuration object. """ self._definition = definition """ The "definition" of the option or section. The definition determines the name(s), value type(s) etc... contained in the configuration object. Instance of :class:`ase2sprkkr.common.configuration_definitions.BaseDefinition` """ self._container = container """ The parent container. I.e. the container that holds this object (e.g. for a value it is the section that owns the value) Instance of :class:`ase2sprkkr.common.configuration_containers.ConfigurationContainer` """
[docs] def _get_path(self, include_root=False): """ Return the dot-delimited path to the item in the configuration tree. E.g. the ``ENERGY`` option in the ``CONTROL`` section has the path ``CONTROL.ENERGY`` """ name = self.name if self._container and (include_root or self._container._container): return f'{self._container._get_path()}.{name}' return name
[docs] def _get_root_container(self): """ Return the root object of the configuration tree. I.E. the object, that represents the whole configuration or problem-definition file """ return self._container._get_root_container() if self._container else self
@property def name(self): """ Return the name of the option/section. The name is defined by the definition of the object. Returns ------- name: str The name of the object. """ return self._definition.name
[docs] def _as_dict(self, get): raise NotImplementedError()
[docs] @staticmethod def as_dict_getter(only_changed:Union[bool,str]='basic', generated=False, copy=False): def get(self): d = self._definition if d.is_generated and not generated: return None if only_changed == 'explicit': if self._definition.is_generated and not generated: return None v = self._unpack_value(self._value) elif only_changed and (only_changed!='basic' or d.is_expert) and not d.is_always_added: v,c = self.value_and_changed() if not c: return None else: v = self(all_values=True) if v is not None: if copy: v = self._definition.copy_value(v, all_values=True) return v return get
[docs] def as_dict(self, only_changed:Union[bool,str]='basic', generated=False, copy=False, getter=None): """ Return the value of self, in the case of container as a dictionary. To be redefined in the descendants. Parameters ---------- only_changed Return only changed values, or all of them? If True, return only the values, that differ from the defaults. If False, return all the values. The default value ``basic`` means, return all non-expert values and all the changed expert values. ``explicit`` means just the values, that were explicitly set (even if they are the same as the default value) """ if not getter: getter = self.as_dict_getter(only_changed, generated, copy) return self._as_dict(getter)
to_dict = as_dict
[docs] def show(self): """ Print the configuration, as it will be saved into the configuration/problem definition file. """ print(self.to_string())
@property def info(self): return self._definition.info() @property def doc(self): try: return self._definition.description() except AttributeError as e: raise Exception("Cannot retrieve documentation") from e
[docs] def help(self, verbose=False, show_hidden=False): if verbose is True: verbose='all' elif verbose is False: verbose=True print(self._definition.description(verbose, show_hidden)) global _help_warning_printed if not _help_warning_printed: import __main__ as main if verbose is True and not hasattr(main, '__file__'): # I'm in repl print('\n You can use <Configuration>.help(True) for a more detailed description of the possible configuration options. Enjoy ASE2SPRKKR!\n') _help_warning_printed = True
def __repr__(self): d = self._definition out = d.configuration_type_name out = out + ' ' + d.name.upper() return out
[docs] def check_for_errors(self, validate='save', print=True): with warnings.catch_warnings(record = True) as lst: warnings.simplefilter("always", DataValidityWarning) self._validate(validate) if lst and print: for warning in lst: warnings.showwarning( message=warning.message, category=warning.category, filename=warning.filename, lineno=warning.lineno )
[docs] def validate(self, why='save'): if why=='warning': return self._validate(why) with warnings.catch_warnings(): warnings.simplefilter("error", DataValidityError) self._validate(why)
[docs] def save_to_file(self, file, *, validate:Union[str, bool]='save'): """ Save the configuration to a file in a given format. This routine do some basic stuff and then call _save_to_file routine, that contains the implementation specific for the type of the configuration container/value. Parameters ---------- file: str or file File to read the data from validate Validate the data in the container first and raise an exception, if there is an error (e.g. the the data are not complete). The string value can be used to select the type of validation ``save`` means the full check (same as the default value ``True``), use ``set`` to allow some missing values. """ if validate == 'warning': self.check_for_errors('save') else: self.validate(validate) if not hasattr(file, 'write'): with open(file, "w") as file: out=self._save_to_file(file) file.flush() else: out=self._save_to_file(file) file.flush() return out
[docs] def to_string(self, *, validate:Union[str, bool]='warning'): """ Return the configuration (problem definition) in a string. Parameters ---------- Validate. How to validate before retrieving. See the method validate. Default 'warning' means the same as 'save', but only throw a warning. Returns ------- configuration:str The configuration, as it should be saved in a configuration/problem definition file. """ from io import StringIO s = StringIO() self.save_to_file(s, validate=validate) return s.getvalue()
[docs] def _find_member(self, name, lower_case:bool=False, is_option=None): item = self._find_members(name, lower_case, is_option) try: return next(item) except StopIteration: return None
_help_warning_printed=False