def tools(self): """Return the calculation tools that are registered for the process type associated with this calculation. If the entry point name stored in the `process_type` of the CalcJobNode has an accompanying entry point in the `aiida.tools.calculations` entry point category, it will attempt to load the entry point and instantiate it passing the node to the constructor. If the entry point does not exist, cannot be resolved or loaded, a warning will be logged and the base CalculationTools class will be instantiated and returned. :return: CalculationTools instance """ from aiida.plugins.entry_point import is_valid_entry_point_string, get_entry_point_from_string, load_entry_point from aiida.tools.calculations import CalculationTools if self._tools is None: entry_point_string = self.process_type if is_valid_entry_point_string(entry_point_string): entry_point = get_entry_point_from_string(entry_point_string) try: tools_class = load_entry_point('aiida.tools.calculations', entry_point.name) self._tools = tools_class(self) except exceptions.EntryPointError as exception: self._tools = CalculationTools(self) self.logger.warning( f'could not load the calculation tools entry point {entry_point.name}: {exception}' ) return self._tools
def get_node_namespace(): """Return the full namespace of all available nodes in the current database. :return: complete node `Namespace` """ from aiida import orm from aiida.plugins.entry_point import is_valid_entry_point_string, parse_entry_point_string builder = orm.QueryBuilder().append(orm.Node, project=['node_type', 'process_type']).distinct() unique_types = {(node_type, process_type if process_type else '') for node_type, process_type in builder.all()} # First we create a flat list of all "leaf" node types. namespaces = [] for node_type, process_type in unique_types: label = None namespace = None if process_type: # Process nodes parts = node_type.rsplit('.', 2) if is_valid_entry_point_string(process_type): _, entry_point_name = parse_entry_point_string(process_type) label = entry_point_name.rpartition('.')[-1] namespace = '.'.join(parts[:-2] + [entry_point_name]) else: label = process_type.rsplit('.', 1)[-1] namespace = '.'.join(parts[:-2] + [DEFAULT_NAMESPACE_LABEL, label]) else: # Data nodes parts = node_type.rsplit('.', 2) try: label = parts[-2] namespace = '.'.join(parts[:-2]) except IndexError: continue full_type = construct_full_type(node_type, process_type) namespaces.append((namespace, label, full_type)) node_namespace = Namespace('node') for namespace, label, full_type in sorted(namespaces, key=lambda x: x[0], reverse=False): node_namespace.create_namespace(namespace, label=label, full_type=full_type) return node_namespace
def _get_config(config_file): """Return the caching configuration. :param config_file: the absolute path to the caching configuration file :return: the configuration dictionary """ from aiida.manage.configuration import get_profile from aiida.plugins.entry_point import is_valid_entry_point_string, load_entry_point_from_string profile = get_profile() if profile is None: exceptions.ConfigurationError('no profile has been loaded') try: with open(config_file, 'r', encoding='utf8') as handle: config = yaml.safe_load(handle)[profile.name] except (OSError, IOError, KeyError): # No config file, or no config for this profile return DEFAULT_CONFIG # Validate configuration for key in config: if key not in DEFAULT_CONFIG: raise ValueError( "Configuration error: Invalid key '{}' in cache_config.yml". format(key)) # Add defaults where key is either completely missing or specifies no values in which case it will be `None` for key, default_config in DEFAULT_CONFIG.items(): if key not in config or config[key] is None: config[key] = default_config # Validate the entry point identifiers for key in [ConfigKeys.ENABLED.value, ConfigKeys.DISABLED.value]: # If the key is defined in the file but contains no values, it will be `None` if config[key] is None: continue for identifier in config[key]: if not is_valid_entry_point_string(identifier): raise exceptions.ConfigurationError( "entry point '{}' in 'cache_config.yml' is not a valid entry point string." .format(identifier)) try: load_entry_point_from_string(identifier) except exceptions.EntryPointError as exception: raise exceptions.ConfigurationError( "entry point '{}' in 'cache_config.yml' can not be loaded: {}." .format(identifier, exception)) return config
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')
def get_node_namespace(user_pk=None, count_nodes=False): """Return the full namespace of all available nodes in the current database. :return: complete node `Namespace` """ # pylint: disable=too-many-branches from aiida import orm from aiida.plugins.entry_point import is_valid_entry_point_string, parse_entry_point_string filters = {} if user_pk is not None: filters['user_id'] = user_pk builder = orm.QueryBuilder().append(orm.Node, filters=filters, project=['node_type', 'process_type']).distinct() # All None instances of process_type are turned into '' unique_types = {(node_type, process_type if process_type else '') for node_type, process_type in builder.all()} # First we create a flat list of all "leaf" node types. namespaces = [] for node_type, process_type in unique_types: label = None counter = None namespace = None if process_type: # Only process nodes parts = node_type.rsplit('.', 2) if is_valid_entry_point_string(process_type): _, entry_point_name = parse_entry_point_string(process_type) label = entry_point_name.rpartition('.')[-1] namespace = '.'.join(parts[:-2] + [entry_point_name]) else: label = process_type.rsplit('.', 1)[-1] namespace = '.'.join(parts[:-2] + [DEFAULT_NAMESPACE_LABEL, process_type]) else: # Data nodes and process nodes without process type (='' or =None) parts = node_type.rsplit('.', 2) try: label = parts[-2] namespace = '.'.join(parts[:-2]) except IndexError: continue if count_nodes: builder = orm.QueryBuilder() concat_filters = [{'node_type': {'==': node_type}}] if node_type.startswith('process.'): if process_type: concat_filters.append({'process_type': {'==': process_type}}) else: concat_filters.append({'process_type': {'or': [{'==': ''}, {'==': None}]}}) if user_pk: concat_filters.append({'user_id': {'==': user_pk}}) if len(concat_filters) == 1: builder.append(orm.Node, filters=concat_filters[0]) else: builder.append(orm.Node, filters={'and': concat_filters}) counter = builder.count() full_type = construct_full_type(node_type, process_type) namespaces.append((namespace, label, full_type, counter)) node_namespace = Namespace('node') for namespace, label, full_type, counter in sorted(namespaces, key=lambda x: x[0], reverse=False): node_namespace.create_namespace(namespace, label=label, full_type=full_type, counter=counter) return node_namespace