Source code for sciunit.models.base

"""Base class for SciUnit models."""

import inspect
from fnmatch import fnmatchcase
from typing import Union

from sciunit.base import SciUnit
from sciunit.capabilities import Capability


[docs]class Model(SciUnit): """Abstract base class for sciunit models."""
[docs] def __init__(self, name=None, **params): """Instantiate model.""" if name is None: name = self.__class__.__name__ self.name = name self.params = params super(Model, self).__init__() self.check_params()
name = None """The name of the model. Defaults to the class name.""" description = "" """A description of the model.""" params = None """The parameters to the model (a dictionary). These distinguish one model of a class from another.""" run_args = None """These are the run-time arguments for the model. Execution of run() should make use of these arguments.""" extra_capability_checks = None """Optional extra checks of capabilities on a per-instance basis.""" _backend = None """Optional model backend for executing some methods, e.g. simulations.""" state_hide = ["results", "temp_dir", "_temp_dir", "stdout"]
[docs] @classmethod def get_capabilities(cls) -> list: """List the model's capabilities.""" capabilities = [] for _cls in cls.mro(): if ( issubclass(_cls, Capability) and _cls is not Capability and not issubclass(_cls, Model) ): capabilities.append(_cls) return capabilities
@property def capabilities(self) -> list: return self.__class__.get_capabilities() @property def failed_extra_capabilities(self) -> list: """Check to see if instance passes its `extra_capability_checks`.""" failed = [] if self.extra_capability_checks is not None: for capability, f_name in self.extra_capability_checks.items(): f = getattr(self, f_name) instance_capable = f() if isinstance(self, capability) and not instance_capable: failed.append(capability) return failed
[docs] def describe(self) -> str: """Describe the model. Returns: str: The description of the model. """ result = "No description available" if self.description: result = "%s" % self.description else: if self.__doc__: s = [] s += [self.__doc__.strip().replace("\n", "").replace(" ", " ")] result = "\n".join(s) return result
[docs] def curr_method(self, back: int = 0) -> str: """Return the name of the current method (calling this one). Args: back (int, optional): [description]. Defaults to 0. Returns: str: The name of the current method that calls this one. """ return inspect.stack()[1 + back][3]
[docs] def check_params(self) -> None: """Check model parameters to see if they are reasonable. For example, this method could check self.params to see if a particular value was within an acceptable range. This should be implemented as needed by specific model classes. """
[docs] def is_match(self, match: Union[str, "Model"]) -> bool: """Return whether this model is the same as `match`. Matches if the model is the same as or has the same name as `match`. Args: match (Union[str, 'Model']): [description] Returns: bool: Whether this model is the same as `match`. """ result = False if self == match: result = True elif isinstance(match, str) and fnmatchcase(self.name, match): result = True # Found by instance or name return result
[docs] def __getattr__(self, attr): try: result = super(Model, self).__getattribute__(attr) except AttributeError: try: result = self._backend.__getattribute__(attr) except: raise AttributeError("Model %s has no attribute %s" % (self, attr)) return result
[docs] def __str__(self): """Return the model name.""" return "%s" % self.name
[docs] def __repr__(self): """Returns a representation of the model.""" return "%s (%s)" % (self.name, self.__class__.__name__)