def _infer_full_type(self, full_type): """Infer the full type based on the current namespace path and the given full type of the leaf.""" from aiida.common.utils import strip_prefix if full_type or self._path is None: return full_type full_type = strip_prefix(self._path, 'node.') if full_type.startswith('process.'): for basepath, full_type_template in self.process_full_type_mapping.items(): if full_type.startswith(basepath): plugin_name = strip_prefix(full_type, basepath) if plugin_name.startswith(DEFAULT_NAMESPACE_LABEL): temp_type_template = self.process_full_type_mapping_unplugged[basepath] plugin_name = strip_prefix(plugin_name, DEFAULT_NAMESPACE_LABEL + '.') full_type = temp_type_template.format(plugin_name=plugin_name) else: full_type = full_type_template.format(plugin_name=plugin_name) return full_type full_type += f'.{LIKE_OPERATOR_CHARACTER}{FULL_TYPE_CONCATENATOR}' if full_type.startswith('process.'): full_type += LIKE_OPERATOR_CHARACTER return full_type
def _infer_full_type(self, full_type): """Infer the full type based on the current namespace path and the given full type of the leaf.""" from aiida.common.utils import strip_prefix if full_type or self._path is None: return full_type full_type = strip_prefix(self._path, 'node.') if full_type.startswith('process.'): for basepath, full_type_template in self.process_full_type_mapping.items( ): if full_type.startswith(basepath): plugin_name = strip_prefix(full_type, basepath) full_type = full_type_template.format( plugin_name=plugin_name) return full_type full_type += '.{}{}'.format(LIKE_OPERATOR_CHARACTER, FULL_TYPE_CONCATENATOR) if full_type.startswith('process.'): full_type += LIKE_OPERATOR_CHARACTER return full_type
def load_node_class(type_string): """ Return the `Node` sub class that corresponds to the given type string. :param type_string: the `type` string of the node :return: a sub class of `Node` """ from aiida.orm import Data, Node from aiida.plugins.entry_point import load_entry_point if type_string == '': return Node if type_string == 'data.Data.': return Data if not type_string.endswith('.'): raise exceptions.DbContentError('The type string `{}` is invalid'.format(type_string)) try: base_path = type_string.rsplit('.', 2)[0] except ValueError: raise exceptions.EntryPointError # This exception needs to be there to make migrations work that rely on the old type string starting with `node.` # Since now the type strings no longer have that prefix, we simply strip it and continue with the normal logic. if base_path.startswith('node.'): base_path = strip_prefix(base_path, 'node.') # Data nodes are the only ones with sub classes that are still external, so if the plugin is not available # we fall back on the base node type if base_path.startswith('data.'): entry_point_name = strip_prefix(base_path, 'data.') try: return load_entry_point('aiida.data', entry_point_name) except exceptions.MissingEntryPointError: return Data if base_path.startswith('process'): entry_point_name = strip_prefix(base_path, 'nodes.') return load_entry_point('aiida.node', entry_point_name) # At this point we really have an anomalous type string. At some point, storing nodes with unresolvable type strings # was allowed, for example by creating a sub class in a shell and then storing an instance. Attempting to load the # node then would fail miserably. This is now no longer allowed, but we need a fallback for existing cases, which # should be rare. We fallback on `Data` and not `Node` because bare node instances are also not storable and so the # logic of the ORM is not well defined for a loaded instance of the base `Node` class. warnings.warn('unknown type string `{}`, falling back onto `Data` class'.format(type_string)) # pylint: disable=no-member return Data
def get_type_string_from_class(class_module, class_name): """ Given the module and name of a class, determine the orm_class_type string, which codifies the orm class that is to be used. The returned string will always have a terminating period, which is required to query for the string in the database :param class_module: module of the class :param class_name: name of the class """ from aiida.plugins.entry_point import get_entry_point_from_class, ENTRY_POINT_GROUP_TO_MODULE_PATH_MAP group, entry_point = get_entry_point_from_class(class_module, class_name) # If we can reverse engineer an entry point group and name, we're dealing with an external class if group and entry_point: module_base_path = ENTRY_POINT_GROUP_TO_MODULE_PATH_MAP[group] type_string = '{}.{}.{}.'.format(module_base_path, entry_point.name, class_name) # Otherwise we are dealing with an internal class else: type_string = '{}.{}.'.format(class_module, class_name) prefixes = ('aiida.orm.nodes.',) # Sequentially and **in order** strip the prefixes if present for prefix in prefixes: type_string = strip_prefix(type_string, prefix) # This needs to be here as long as `aiida.orm.nodes.data` does not live in `aiida.orm.nodes.data` because all the # `Data` instances will have a type string that starts with `data.` instead of `nodes.`, so in order to match any # `Node` we have to look for any type string essentially. if type_string == 'node.Node.': type_string = '' return type_string
def load_node_class(type_string): """ Return the `Node` sub class that corresponds to the given type string. :param type_string: the `type` string of the node :return: a sub class of `Node` """ from aiida.orm import Data, Node from aiida.plugins.entry_point import load_entry_point if type_string == '': return Node if type_string == 'data.Data.': return Data if not type_string.endswith('.'): raise exceptions.DbContentError( 'The type string `{}` is invalid'.format(type_string)) try: base_path = type_string.rsplit('.', 2)[0] except ValueError: raise exceptions.EntryPointError # This exception needs to be there to make migrations work that rely on the old type string starting with `node.` # Since now the type strings no longer have that prefix, we simply strip it and continue with the normal logic. if base_path.startswith('node.'): base_path = strip_prefix(base_path, 'node.') # Data nodes are the only ones with sub classes that are still external, so if the plugin is not available # we fall back on the base node type if base_path.startswith('data.'): entry_point_name = strip_prefix(base_path, 'data.') try: return load_entry_point('aiida.data', entry_point_name) except exceptions.MissingEntryPointError: return Data if base_path.startswith('process'): entry_point_name = strip_prefix(base_path, 'nodes.') return load_entry_point('aiida.node', entry_point_name) raise exceptions.EntryPointError( 'unknown type string {}'.format(type_string))
def load_entry_point_from_full_type(full_type): """Return the loaded entry point for the given `full_type` unique node identifier. :param full_type: the `full_type` unique node identifier :raises ValueError: if the `full_type` is invalid :raises TypeError: if the `full_type` is not a string type :raises `~aiida.common.exceptions.EntryPointError`: if the corresponding entry point cannot be loaded """ from aiida.common import EntryPointError from aiida.common.utils import strip_prefix from aiida.plugins.entry_point import is_valid_entry_point_string, load_entry_point, load_entry_point_from_string data_prefix = 'data.' validate_full_type(full_type) node_type, process_type = full_type.split(FULL_TYPE_CONCATENATOR) if is_valid_entry_point_string(process_type): try: return load_entry_point_from_string(process_type) except EntryPointError: raise EntryPointError( f'could not load entry point `{process_type}`') elif node_type.startswith(data_prefix): base_name = strip_prefix(node_type, data_prefix) entry_point_name = base_name.rsplit('.', 2)[0] try: return load_entry_point('aiida.data', entry_point_name) except EntryPointError: raise EntryPointError( f'could not load entry point `{process_type}`') # Here we are dealing with a `ProcessNode` with a `process_type` that is not an entry point string. # Which means it is most likely a full module path (the fallback option) and we cannot necessarily load the # class from this. We could try with `importlib` but not sure that we should raise EntryPointError( 'entry point of the given full type cannot be loaded')