Beispiel #1
0
    def test_replacement_1(self):
        from aiida.backends.djsite.db.models import DbExtra

        n1 = Node().store()
        n2 = Node().store()

        DbExtra.set_value_for_node(n1._dbnode, "pippo", [1, 2, 'a'])
        DbExtra.set_value_for_node(n1._dbnode, "pippobis", [5, 6, 'c'])
        DbExtra.set_value_for_node(n2._dbnode, "pippo2", [3, 4, 'b'])

        self.assertEquals(n1.get_extras(), {'pippo': [1, 2, 'a'],
                                            'pippobis': [5, 6, 'c'],
                                            '_aiida_hash': n1.get_hash()
                                            })
        self.assertEquals(n2.get_extras(), {'pippo2': [3, 4, 'b'],
                                            '_aiida_hash': n2.get_hash()
                                            })

        new_attrs = {"newval1": "v", "newval2": [1, {"c": "d", "e": 2}]}

        DbExtra.reset_values_for_node(n1._dbnode, attributes=new_attrs)
        self.assertEquals(n1.get_extras(), new_attrs)
        self.assertEquals(n2.get_extras(), {'pippo2': [3, 4, 'b'], '_aiida_hash': n2.get_hash()})

        DbExtra.del_value_for_node(n1._dbnode, key='newval2')
        del new_attrs['newval2']
        self.assertEquals(n1.get_extras(), new_attrs)
        # Also check that other nodes were not damaged
        self.assertEquals(n2.get_extras(), {'pippo2': [3, 4, 'b'], '_aiida_hash': n2.get_hash()})
Beispiel #2
0
 def _del_db_extra(self, key):
     from aiida.backends.djsite.db.models import DbExtra
     if not DbExtra.has_key(self.dbnode, key):
         raise AttributeError("DbExtra {} does not exist".format(
             key))
     return DbExtra.del_value_for_node(self.dbnode, key)
     self._increment_version_number_db()
Beispiel #3
0
    def _set_db_extra(self, key, value, exclusive=False):
        from aiida.backends.djsite.db.models import DbExtra

        DbExtra.set_value_for_node(self.dbnode,
                                   key,
                                   value,
                                   stop_if_existing=exclusive)
        self._increment_version_number_db()
Beispiel #4
0
 def del_extra(self, key):
     from aiida.backends.djsite.db.models import DbExtra
     if self._to_be_stored:
         raise ModificationNotAllowed(
             "The extras of a node can be set and deleted "
             "only after storing the node")
     if not DbExtra.has_key(self.dbnode, key):
         raise AttributeError("DbExtra {} does not exist".format(key))
     return DbExtra.del_value_for_node(self.dbnode, key)
     self._increment_version_number_db()
Beispiel #5
0
    def set_extra_exclusive(self, key, value):
        from aiida.backends.djsite.db.models import DbExtra
        DbExtra.validate_key(key)

        if self._to_be_stored:
            raise ModificationNotAllowed(
                "The extras of a node can be set only after "
                "storing the node")
        DbExtra.set_value_for_node(self.dbnode,
                                   key,
                                   value,
                                   stop_if_existing=True)
        self._increment_version_number_db()
Beispiel #6
0
 def extras(self):
     from aiida.backends.djsite.db.models import DbExtra
     if self._to_be_stored:
         return
     else:
         extraslist = DbExtra.list_all_node_elements(self.dbnode)
     for e in extraslist:
         yield e.key
Beispiel #7
0
 def iterextras(self):
     from aiida.backends.djsite.db.models import DbExtra
     if self._to_be_stored:
         # If it is not stored yet, there are no extras that can be
         # added (in particular, we do not even have an ID to use!)
         # Return without value, meaning that this is an empty generator
         return
     else:
         extraslist = DbExtra.list_all_node_elements(self.dbnode)
         for e in extraslist:
             yield (e.key, e.getvalue())
Beispiel #8
0
    def get_extra(self, key, *args):
        from aiida.backends.djsite.db.models import DbExtra
        if len(args) > 1:
            raise ValueError("After the key name you can pass at most one"
                             "value, that is the default value to be used "
                             "if no extra is found.")

        try:
            if self._to_be_stored:
                raise AttributeError("DbExtra '{}' does not exist yet, the "
                                     "node is not stored".format(key))
            else:
                return DbExtra.get_value_for_node(dbnode=self.dbnode, key=key)
        except AttributeError as e:
            try:
                return args[0]
            except IndexError:
                raise e
Beispiel #9
0
    def _get_aiida_res(self, key, res):
        """
        Some instance returned by ORM (django or SA) need to be converted
        to Aiida instances (eg nodes)

        :param res: the result returned by the query
        :param key: the key that this entry would be return with

        :returns: an aiida-compatible instance
        """

        if key.startswith('attributes.'):
            # If you want a specific attributes, that key was stored in res.
            # So I call the getvalue method to expand into a dictionary
            try:
                returnval = DbAttribute.objects.get(id=res).getvalue()
            except ObjectDoesNotExist:
                # If the object does not exist, return None. This is consistent
                # with SQLAlchemy inside the JSON
                returnval = None
        elif key.startswith('extras.'):
            # Same as attributes
            try:
                returnval = DbExtra.objects.get(id=res).getvalue()
            except ObjectDoesNotExist:
                returnval = None
        elif key == 'attributes':
            # If you asked for all attributes, the QB return the ID of the node
            # I use DbAttribute.get_all_values_for_nodepk
            # to get the dictionary
            return DbAttribute.get_all_values_for_nodepk(res)
        elif key == 'extras':
            # same as attributes
            return DbExtra.get_all_values_for_nodepk(res)
        elif key in ('_metadata', 'transport_params'):
            # Metadata and transport_params are stored as json strings in the DB:
            return json_loads(res)
        elif isinstance(res,
                        (self.Group, self.Node, self.Computer, self.User)):
            returnval = res.get_aiida_class()
        else:
            returnval = res
        return returnval
Beispiel #10
0
 def _db_iterextras(self):
     from aiida.backends.djsite.db.models import DbExtra
     extraslist = DbExtra.list_all_node_elements(self.dbnode)
     for e in extraslist:
         yield (e.key, e.getvalue())
Beispiel #11
0
 def _get_db_extra(self, key, *args):
     from aiida.backends.djsite.db.models import DbExtra
     return DbExtra.get_value_for_node(dbnode=self.dbnode, key=key)
Beispiel #12
0
    def _db_store(self, with_transaction=True):
        """
        Store a new node in the DB, also saving its repository directory
        and attributes.

        After being called attributes cannot be
        changed anymore! Instead, extras can be changed only AFTER calling
        this store() function.

        :note: After successful storage, those links that are in the cache, and
            for which also the parent node is already stored, will be
            automatically stored. The others will remain unstored.

        :parameter with_transaction: if False, no transaction is used. This
          is meant to be used ONLY if the outer calling function has already
          a transaction open!

        :param bool use_cache: Whether I attempt to find an equal node in the DB.
        """
        # TODO: This needs to be generalized, allowing for flexible methods
        # for storing data and its attributes.
        from django.db import transaction
        from aiida.common.utils import EmptyContextManager
        from aiida.common.exceptions import ValidationError
        from aiida.backends.djsite.db.models import DbAttribute
        import aiida.orm.autogroup

        if with_transaction:
            context_man = transaction.atomic()
        else:
            context_man = EmptyContextManager()

        # I save the corresponding django entry
        # I set the folder
        # NOTE: I first store the files, then only if this is successful,
        # I store the DB entry. In this way,
        # I assume that if a node exists in the DB, its folder is in place.
        # On the other hand, periodically the user might need to run some
        # bookkeeping utility to check for lone folders.
        self._repository_folder.replace_with_folder(
            self._get_temp_folder().abspath, move=True, overwrite=True)

        # I do the transaction only during storage on DB to avoid timeout
        # problems, especially with SQLite
        try:
            with context_man:
                # Save the row
                self._dbnode.save()
                # Save its attributes 'manually' without incrementing
                # the version for each add.
                DbAttribute.reset_values_for_node(self._dbnode,
                                                  attributes=self._attrs_cache,
                                                  with_transaction=False)
                # This should not be used anymore: I delete it to
                # possibly free memory
                del self._attrs_cache

                self._temp_folder = None
                self._to_be_stored = False

                # Here, I store those links that were in the cache and
                # that are between stored nodes.
                self._store_cached_input_links()

        # This is one of the few cases where it is ok to do a 'global'
        # except, also because I am re-raising the exception
        except:
            # I put back the files in the sandbox folder since the
            # transaction did not succeed
            self._get_temp_folder().replace_with_folder(
                self._repository_folder.abspath, move=True, overwrite=True)
            raise

        from aiida.backends.djsite.db.models import DbExtra
        # I store the hash without cleaning and without incrementing the nodeversion number
        DbExtra.set_value_for_node(self._dbnode, _HASH_EXTRA_KEY, self.get_hash())

        return self