diff --git a/nomad/metainfo/metainfo.py b/nomad/metainfo/metainfo.py index b97efdd396e1d74a5027be95804fb3eee2312103..553cb252df566edfbb12e863530317f456047a5f 100644 --- a/nomad/metainfo/metainfo.py +++ b/nomad/metainfo/metainfo.py @@ -622,11 +622,42 @@ class MObject(metaclass=MObjectMeta): # These placeholder are replaced, once the necessary classes are defined. This process # is referred to as 'bootstrapping'. +_definition_change_counter = 0 + + +def cached(f): + """ A decorator that allows to cache the results of metainfo definition methods. + + The cache will be invalidated whenever a new definition is added. Once all definitions + are loaded, the cache becomes stable and complex derived results become available + instantaneous. + """ + cache = dict(change=-1, value=None) + + def wrapper(*args, **kwargs): + if cache['change'] == _definition_change_counter: + return cache['value'] + + value = f(*args, **kwargs) + cache['change'] == _definition_change_counter + cache['value'] == value + + return value + + return wrapper + + class Definition(MObject): + name: 'Quantity' = None description: 'Quantity' = None links: 'Quantity' = None + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + global _definition_change_counter + _definition_change_counter += 1 + class Quantity(Definition): """Used to define quantities that store a certain piece of (meta-)data. @@ -731,8 +762,8 @@ class Section(Definition): super().__init__(**kwargs) Section.__all_instances.append(self) - # TODO cache - @property + @property # type: ignore + @cached def attributes(self) -> Dict[str, Union['Section', Quantity]]: """ All attribute (sub section and quantity) definitions. """ @@ -740,8 +771,8 @@ class Section(Definition): attributes.update(**self.sub_sections) return attributes - # TODO cache - @property + @property # type: ignore + @cached def quantities(self) -> Dict[str, Quantity]: """ All quantity definition in the given section definition. """ @@ -749,8 +780,8 @@ class Section(Definition): quantity.name: quantity for quantity in self.m_data.get('Quantity', [])} - # TODO cache - @property + @property # type: ignore + @cached def sub_sections(self) -> Dict[str, 'Section']: """ All sub section definitions for this section definition. """