From 3a61a70032d6ace3d27f1a701be048f3f2026b43 Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Fri, 7 Jul 2023 04:48:34 -0700 Subject: [PATCH] Lazily define `_plugin_type_string` and `_query_type_string of `Node` These class attributes require a look up whether the `Node` class has a registered entry point which can have a non-negligible cost. These attributes were defined in the `AbstractNodeMeta` class, which is the metaclass of the `Node` class, which would cause this code to be executed as soon as the class was imported. Here, the `AbstractNodeMeta` metaclass is removed. The `_plugin_type_string` and `_query_type_string` class attributes are changed to class properties. The actual value is stored in the private attribute analog which is defined lazily the first time the property is accessed. --- aiida/orm/nodes/node.py | 25 +++++++++++++++++++++---- aiida/orm/utils/node.py | 5 ----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/aiida/orm/nodes/node.py b/aiida/orm/nodes/node.py index b1ac17c631..b614b5723a 100644 --- a/aiida/orm/nodes/node.py +++ b/aiida/orm/nodes/node.py @@ -20,7 +20,11 @@ from aiida.common.links import LinkType from aiida.common.warnings import warn_deprecation from aiida.manage import get_manager -from aiida.orm.utils.node import AbstractNodeMeta +from aiida.orm.utils.node import ( # pylint: disable=unused-import + AbstractNodeMeta, + get_query_type_from_type_string, + get_type_string_from_class, +) from ..computers import Computer from ..entities import Collection as EntityCollection @@ -149,9 +153,22 @@ class Node(Entity['BackendNode', NodeCollection], metaclass=AbstractNodeMeta): _CLS_NODE_LINKS = NodeLinks _CLS_NODE_CACHING = NodeCaching - # added by metaclass - _plugin_type_string: ClassVar[str] - _query_type_string: ClassVar[str] + __plugin_type_string: ClassVar[str] + __query_type_string: ClassVar[str] + + @classproperty + def _plugin_type_string(cls) -> str: + """Return the plugin type string of this node class.""" + if not hasattr(cls, '__plugin_type_string'): + cls.__plugin_type_string = get_type_string_from_class(cls.__module__, cls.__name__) # type: ignore[misc] + return cls.__plugin_type_string + + @classproperty + def _query_type_string(cls) -> str: + """Return the query type string of this node class.""" + if not hasattr(cls, '__query_type_string'): + cls.__query_type_string = get_query_type_from_type_string(cls._plugin_type_string) # type: ignore[misc] + return cls.__query_type_string # This will be set by the metaclass call _logger: Optional[Logger] = None diff --git a/aiida/orm/utils/node.py b/aiida/orm/utils/node.py index 4734a27b9d..7c277133c7 100644 --- a/aiida/orm/utils/node.py +++ b/aiida/orm/utils/node.py @@ -160,9 +160,4 @@ class AbstractNodeMeta(ABCMeta): def __new__(mcs, name, bases, namespace, **kwargs): newcls = ABCMeta.__new__(mcs, name, bases, namespace, **kwargs) # pylint: disable=too-many-function-args newcls._logger = logging.getLogger(f"{namespace['__module__']}.{name}") - - # Set the plugin type string and query type string based on the plugin type string - newcls._plugin_type_string = get_type_string_from_class(namespace['__module__'], name) # pylint: disable=protected-access - newcls._query_type_string = get_query_type_from_type_string(newcls._plugin_type_string) # pylint: disable=protected-access - return newcls