示例#1
0
    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
示例#2
0
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
示例#3
0
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
示例#4
0
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')
示例#5
0
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