From e513eb7994d300bae18c81eff38575c62c0ec1c4 Mon Sep 17 00:00:00 2001
From: Markus Scheidgen <markus.scheidgen@gmail.com>
Date: Fri, 27 Sep 2019 20:48:13 +0200
Subject: [PATCH] Added cache to metainfo definition methods.

---
 nomad/metainfo/metainfo.py | 43 ++++++++++++++++++++++++++++++++------
 1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/nomad/metainfo/metainfo.py b/nomad/metainfo/metainfo.py
index b97efdd396..553cb252df 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. """
 
-- 
GitLab