def set_attribute(self, key, value): """Set an attribute to the given value. :param key: name of the attribute :param value: value of the attribute :raise aiida.common.exceptions.ModificationNotAllowed: if the node is already sealed or if the node is already stored and the attribute is not updatable. """ if self.is_sealed: raise exceptions.ModificationNotAllowed('attributes of a sealed node are immutable') if self.is_stored and key not in self._updatable_attributes: # pylint: disable=unsupported-membership-test raise exceptions.ModificationNotAllowed('`{}` is not an updatable attribute'.format(key)) self.backend_entity.set_attribute(key, value)
def delete_attribute(self, key): """Delete an attribute. :param key: name of the attribute :raises AttributeError: if the attribute does not exist :raise aiida.common.exceptions.ModificationNotAllowed: if the node is already sealed or if the node is already stored and the attribute is not updatable. """ if self.is_sealed: raise exceptions.ModificationNotAllowed('attributes of a sealed node are immutable') if self.is_stored and key not in self._updatable_attributes: # pylint: disable=unsupported-membership-test raise exceptions.ModificationNotAllowed('`{}` is not an updatable attribute'.format(key)) self.backend_entity.delete_attribute(key)
def restore(self): """Move the contents from the repository folder back into the sandbox folder.""" if not self._is_stored: raise exceptions.ModificationNotAllowed('repository is not yet stored') self._temp_folder.replace_with_folder(self._repo_folder.abspath, move=True, overwrite=True) self._is_stored = False
def store(self): """Store the contents of the sandbox folder into the repository folder.""" if self._is_stored: raise exceptions.ModificationNotAllowed('repository is already stored') self._repo_folder.replace_with_folder(self._get_temp_folder().abspath, move=True, overwrite=True) self._is_stored = True
def clear_attributes(self): """Delete all attributes.""" if self.is_stored: raise exceptions.ModificationNotAllowed( 'the attributes of a stored entity are immutable') self.backend_entity.clear_attributes()
def add_nodes(self, nodes): """Add a node or a set of nodes to the family. .. note: Each family instance can only contain a single pseudo potential for each element. :param nodes: a single or list of ``Node`` instances of type that is in ``PseudoPotentialFamily._pseudo_types``. :raises ModificationNotAllowed: if the family is not stored. :raises TypeError: if nodes are not an instance or list of instance of any of the classes listed by ``PseudoPotentialFamily._pseudo_types``. :raises ValueError: if any of the nodes are not stored or their elements already exist in this family. """ if not self.is_stored: raise exceptions.ModificationNotAllowed('cannot add nodes to an unstored group') if not isinstance(nodes, (list, tuple)): nodes = [nodes] if any(not isinstance(node, self._pseudo_types) for node in nodes): raise TypeError(f'only nodes of types `{self._pseudo_types}` can be added: {nodes}') pseudos = {} # Check for duplicates before adding any pseudo to the internal cache for pseudo in nodes: if pseudo.element in self.elements: raise ValueError(f'element `{pseudo.element}` already present in this family') pseudos[pseudo.element] = pseudo self.pseudos.update(pseudos) self.update_pseudo_type() super().add_nodes(nodes)
def validate_mutability(self): """Raise if the repository is immutable. :raises aiida.common.ModificationNotAllowed: if repository is marked as immutable because the corresponding node is stored """ if self._is_stored: raise exceptions.ModificationNotAllowed('cannot modify the repository after the node has been stored')
def store(self): """Can only store if both the node and user are stored as well.""" if self._dbmodel.dbnode.id is None or self._dbmodel.user.id is None: self._dbmodel.dbnode = None raise exceptions.ModificationNotAllowed( 'The corresponding node and/or user are not stored') super().store()
def add_incoming(self, source, link_type, link_label): """Add a link of the given type from a given node to ourself. :param source: the node from which the link is coming :param link_type: the link type :param link_label: the link label :return: True if the proposed link is allowed, False otherwise :raise aiida.common.ModificationNotAllowed: if either source or target node is not stored """ type_check(source, DjangoNode) if not self.is_stored: raise exceptions.ModificationNotAllowed('node has to be stored when adding an incoming link') if not source.is_stored: raise exceptions.ModificationNotAllowed('source node has to be stored when adding a link from it') self._add_link(source, link_type, link_label)
def store(self): """Can only store if both the node and user are stored as well.""" from aiida.backends.djsite.db.models import suppress_auto_now if self._dbmodel.dbnode.id is None or self._dbmodel.user.id is None: raise exceptions.ModificationNotAllowed('The corresponding node and/or user are not stored') with suppress_auto_now([(models.DbComment, ['mtime'])]) if self.mtime else contextlib.nullcontext(): super().store()
def out(self, link_label, node): """Register a node as an output with the given link label. :param link_label: the name of the link label :param node: the node to register as an output :raises aiida.common.ModificationNotAllowed: if an output node was already registered with the same link label """ if link_label in self._outputs: raise exceptions.ModificationNotAllowed('the output {} already exists'.format(link_label)) self._outputs[link_label] = node
def store(self): """Can only store if both the node and user are stored as well.""" from aiida.backends.djsite.db.models import suppress_auto_now if self._dbmodel.dbnode.id is None or self._dbmodel.user.id is None: raise exceptions.ModificationNotAllowed('The corresponding node and/or user are not stored') # `contextlib.suppress` provides empty context and can be replaced with `contextlib.nullcontext` after we drop # support for python 3.6 with suppress_auto_now([(models.DbComment, ['mtime'])]) if self.mtime else contextlib.suppress(): super().store()
def delete_attribute(self, key): """Delete an attribute. :param key: name of the attribute :raises AttributeError: if the attribute does not exist :raise aiida.common.ModificationNotAllowed: if the entity is stored """ if self.is_stored: raise exceptions.ModificationNotAllowed( 'the attributes of a stored entity are immutable') self.backend_entity.delete_attribute(key)
def delete_attribute_many(self, keys): """Delete multiple attributes. :param keys: names of the attributes to delete :raises AttributeError: if at least one of the attribute does not exist :raise aiida.common.ModificationNotAllowed: if the entity is stored """ if self.is_stored: raise exceptions.ModificationNotAllowed( 'the attributes of a stored entity are immutable') self.backend_entity.delete_attribute_many(keys)
def set_attribute(self, key, value): """Set an attribute to the given value. :param key: name of the attribute :param value: value of the attribute :raise aiida.common.ValidationError: if the key is invalid, i.e. contains periods :raise aiida.common.ModificationNotAllowed: if the entity is stored """ if self.is_stored: raise exceptions.ModificationNotAllowed( 'the attributes of a stored entity are immutable') self.backend_entity.set_attribute(key, value)
def set_attribute_many(self, attributes): """Set multiple attributes. .. note:: This will override any existing attributes that are present in the new dictionary. :param attributes: a dictionary with the attributes to set :raise aiida.common.ValidationError: if any of the keys are invalid, i.e. contain periods :raise aiida.common.ModificationNotAllowed: if the entity is stored """ if self.is_stored: raise exceptions.ModificationNotAllowed( 'the attributes of a stored entity are immutable') self.backend_entity.set_attribute_many(attributes)
def reset_attributes(self, attributes): """Reset the attributes. .. note:: This will completely clear any existing attributes and replace them with the new dictionary. :param attributes: a dictionary with the attributes to set :raise aiida.common.ValidationError: if any of the keys are invalid, i.e. contain periods :raise aiida.common.ModificationNotAllowed: if the entity is stored """ if self.is_stored: raise exceptions.ModificationNotAllowed( 'the attributes of a stored entity are immutable') self.backend_entity.reset_attributes(attributes)
def validate_outgoing(self, target, link_type, link_label): """Validate adding a link of the given type from ourself to a given node. Adding an outgoing link from a sealed node is forbidden. :param target: the node to which the link is going :param link_type: the link type :param link_label: the link label :raise aiida.common.ModificationNotAllowed: if the source node (self) is sealed """ if self.is_sealed: raise exceptions.ModificationNotAllowed('Cannot add a link from a sealed node') super().validate_outgoing(target, link_type=link_type, link_label=link_label)
def validate_incoming(self, source, link_type, link_label): """Validate adding a link of the given type from a given node to ourself. Adding an incoming link to a sealed node is forbidden. :param source: the node from which the link is coming :param link_type: the link type :param link_label: the link label :raise aiida.common.ModificationNotAllowed: if the target node (self) is sealed """ if self.is_sealed: raise exceptions.ModificationNotAllowed('Cannot add a link to a sealed node') super().validate_incoming(source, link_type=link_type, link_label=link_label)
def remove_nodes(self, nodes): """Remove a node or a set of nodes to the group. :note: all the nodes *and* the group itself have to be stored. :param nodes: a single `Node` or a list of `Nodes` :type nodes: :class:`aiida.orm.Node` or list """ from .nodes import Node if not self.is_stored: raise exceptions.ModificationNotAllowed('cannot add nodes to an unstored group') # Cannot use `collections.Iterable` here, because that would also match iterable `Node` sub classes like `List` if not isinstance(nodes, (list, tuple)): nodes = [nodes] for node in nodes: type_check(node, Node) self._backend_entity.remove_nodes([node.backend_entity for node in nodes])
def add_nodes(self, nodes): """Add a node or a set of nodes to the basis set. .. note: Each basis set instance can only contain a single basis for each element. :param nodes: a single or list of ``Node`` instances of type that is in ``BasisSet._basis_types``. :raises ModificationNotAllowed: if the basis set is not stored. :raises TypeError: if nodes are not an instance or list of instance of any of the classes listed by ``BasisSet._basis_types``. :raises ValueError: if any of the nodes are not stored or their elements already exist in this basis set. """ if not self.is_stored: raise exceptions.ModificationNotAllowed( 'cannot add nodes to an unstored group') if not isinstance(nodes, (list, tuple)): nodes = [nodes] if any(not isinstance(node, self._basis_types) for node in nodes): raise TypeError( f'only nodes of types `{self._basis_types}` can be added: {nodes}' ) bases = {} # Check for duplicates before adding any basis to the internal cache for basis in nodes: if basis.element in self.elements: raise ValueError( f'element `{basis.element}` already present in this basis set' ) bases[basis.element] = basis self.bases.update(bases) self.update_basis_type() super().add_nodes(nodes)