Exemplo n.º 1
0
    def create_entry_from_record(self, record):
        """
        Helper function to create a log entry from a record created as by the
        python logging lobrary

        :param record: The record created by the logging module
        :type record: :class:`logging.record`
        :return: An object implementing the log entry interface
        :rtype: :class:`aiida.orm.log.Log`
        """
        from datetime import datetime

        objpk = record.__dict__.get('objpk', None)
        objname = record.__dict__.get('objname', None)

        # Do not store if objpk and objname are not set
        if objpk is None or objname is None:
            return None

        return self.create_entry(time=timezone.make_aware(
            datetime.fromtimestamp(record.created)),
                                 loggername=record.name,
                                 levelname=record.levelname,
                                 objname=objname,
                                 objpk=objpk,
                                 message=record.getMessage(),
                                 metadata=record.__dict__)
Exemplo n.º 2
0
    def test_datetime_attribute(self):
        from aiida.utils.timezone import (get_current_timezone, is_naive,
                                          make_aware, now)

        a = Node()

        date = now()

        a._set_attr('some_date', date)
        a.store()

        retrieved = a.get_attr('some_date')

        if is_naive(date):
            date_to_compare = make_aware(date, get_current_timezone())
        else:
            date_to_compare = date

        # Do not compare microseconds (they are not stored in the case of MySQL)
        date_to_compare = date_to_compare.replace(microsecond=0)
        retrieved = retrieved.replace(microsecond=0)

        self.assertEquals(date_to_compare, retrieved)
Exemplo n.º 3
0
 def test_timezone_now(self):
     DELTA = datetime.timedelta(minutes=1)
     ref = timezone.now()
     from_tz = timezone.make_aware(datetime.datetime.fromtimestamp(time.time()))
     self.assertLessEqual(from_tz, ref + DELTA)
     self.assertGreaterEqual(from_tz, ref - DELTA)
Exemplo n.º 4
0
def _deserialize_attribute(mainitem,
                           subitems,
                           sep,
                           original_class=None,
                           original_pk=None,
                           lesserrors=False):
    """
    Deserialize a single attribute.

    :param mainitem: the main item (either the attribute itself for base
      types (None, string, ...) or the main item for lists and dicts.
      Must contain the 'key' key and also the following keys:
      datatype, tval, fval, ival, bval, dval.
      NOTE that a type check is not performed! tval is expected to be a string,
      dval a date, etc.
    :param subitems: must be a dictionary of dictionaries. In the top-level dictionary,
      the key must be the key of the attribute, stripped of all prefixes
      (i.e., if the mainitem has key 'a.b' and we pass subitems
        'a.b.0', 'a.b.1', 'a.b.1.c', their keys must be '0', '1', '1.c').
        It must be None if the value is not iterable (int, str,
        float, ...).
        It is an empty dictionary if there are no subitems.
    :param sep: a string, the separator between subfields (to separate the
      name of a dictionary from the keys it contains, for instance)
    :param original_class: if these elements come from a specific subclass
      of DbMultipleValueAttributeBaseClass, pass here the class (note: the class,
      not the instance!). This is used only in case the wrong number of elements
      is found in the raw data, to print a more meaningful message (if the class
      has a dbnode associated to it)
    :param original_pk: if the elements come from a specific subclass
      of DbMultipleValueAttributeBaseClass that has a dbnode associated to it,
      pass here the PK integer. This is used only in case the wrong number
      of elements is found in the raw data, to print a more meaningful message
    :param lesserrors: If set to True, in some cases where the content of the
      DB is not consistent but data is still recoverable,
      it will just log the message rather than raising
      an exception (e.g. if the number of elements of a dictionary is different
      from the number declared in the ival field).

    :return: the deserialized value
    :raise DeserializationError: if an error occurs
    """

    #    from aiida.common import aiidalogger

    if mainitem['datatype'] == 'none':
        if subitems:
            raise DeserializationException("'{}' is of a base type, "
                                           "but has subitems!".format(
                                               mainitem.key))
        return None
    elif mainitem['datatype'] == 'bool':
        if subitems:
            raise DeserializationException("'{}' is of a base type, "
                                           "but has subitems!".format(
                                               mainitem.key))
        return mainitem['bval']
    elif mainitem['datatype'] == 'int':
        if subitems:
            raise DeserializationException("'{}' is of a base type, "
                                           "but has subitems!".format(
                                               mainitem.key))
        return mainitem['ival']
    elif mainitem['datatype'] == 'float':
        if subitems:
            raise DeserializationException("'{}' is of a base type, "
                                           "but has subitems!".format(
                                               mainitem.key))
        return mainitem['fval']
    elif mainitem['datatype'] == 'txt':
        if subitems:
            raise DeserializationException("'{}' is of a base type, "
                                           "but has subitems!".format(
                                               mainitem.key))
        return mainitem['tval']
    elif mainitem['datatype'] == 'date':
        if subitems:
            raise DeserializationException("'{}' is of a base type, "
                                           "but has subitems!".format(
                                               mainitem.key))
        if is_naive(mainitem['dval']):
            return make_aware(mainitem['dval'], get_current_timezone())
        else:
            return mainitem['dval']
        return mainitem['dval']
    elif mainitem['datatype'] == 'list':
        # subitems contains all subitems, here I store only those of
        # deepness 1, i.e. if I have subitems '0', '1' and '1.c' I
        # store only '0' and '1'
        firstlevelsubdict = {
            k: v
            for k, v in subitems.iteritems() if sep not in k
        }

        # For checking, I verify the expected values
        expected_set = set(["{:d}".format(i) for i in range(mainitem['ival'])])
        received_set = set(firstlevelsubdict.keys())
        # If there are more entries than expected, but all expected
        # ones are there, I just issue an error but I do not stop.

        if not expected_set.issubset(received_set):
            if (original_class is not None
                    and original_class._subspecifier_field_name is not None):
                subspecifier_string = "{}={} and ".format(
                    original_class._subspecifier_field_name, original_pk)
            else:
                subspecifier_string = ""
            if original_class is None:
                sourcestr = "the data passed"
            else:
                sourcestr = original_class.__name__

            raise DeserializationException(
                "Wrong list elements stored in {} for "
                "{}key='{}' ({} vs {})".format(sourcestr, subspecifier_string,
                                               mainitem['key'], expected_set,
                                               received_set))
        if expected_set != received_set:
            if (original_class is not None
                    and original_class._subspecifier_field_name is not None):
                subspecifier_string = "{}={} and ".format(
                    original_class._subspecifier_field_name, original_pk)
            else:
                subspecifier_string = ""
            if original_class is None:
                sourcestr = "the data passed"
            else:
                sourcestr = original_class.__name__

            msg = ("Wrong list elements stored in {} for "
                   "{}key='{}' ({} vs {})".format(sourcestr,
                                                  subspecifier_string,
                                                  mainitem['key'],
                                                  expected_set, received_set))
            if lesserrors:
                print msg
                #~ aiidalogger.error(msg)
            else:
                raise DeserializationException(msg)

        # I get the values in memory as a dictionary
        tempdict = {}
        for firstsubk, firstsubv in firstlevelsubdict.iteritems():
            # I call recursively the same function to get subitems
            newsubitems = {
                k[len(firstsubk) + len(sep):]: v
                for k, v in subitems.iteritems()
                if k.startswith(firstsubk + sep)
            }
            tempdict[firstsubk] = _deserialize_attribute(
                mainitem=firstsubv,
                subitems=newsubitems,
                sep=sep,
                original_class=original_class,
                original_pk=original_pk)

        # And then I put them in a list
        retlist = [tempdict["{:d}".format(i)] for i in range(mainitem['ival'])]
        return retlist
    elif mainitem['datatype'] == 'dict':
        # subitems contains all subitems, here I store only those of
        # deepness 1, i.e. if I have subitems '0', '1' and '1.c' I
        # store only '0' and '1'
        firstlevelsubdict = {
            k: v
            for k, v in subitems.iteritems() if sep not in k
        }

        if len(firstlevelsubdict) != mainitem['ival']:
            if (original_class is not None
                    and original_class._subspecifier_field_name is not None):
                subspecifier_string = "{}={} and ".format(
                    original_class._subspecifier_field_name, original_pk)
            else:
                subspecifier_string = ""
            if original_class is None:
                sourcestr = "the data passed"
            else:
                sourcestr = original_class.__name__

            msg = ("Wrong dict length stored in {} for "
                   "{}key='{}' ({} vs {})".format(sourcestr,
                                                  subspecifier_string,
                                                  mainitem['key'],
                                                  len(firstlevelsubdict),
                                                  mainitem['ival']))
            if lesserrors:
                print msg
                #~ aiidalogger.error(msg)
            else:
                raise DeserializationException(msg)

        # I get the values in memory as a dictionary
        tempdict = {}
        for firstsubk, firstsubv in firstlevelsubdict.iteritems():
            # I call recursively the same function to get subitems
            newsubitems = {
                k[len(firstsubk) + len(sep):]: v
                for k, v in subitems.iteritems()
                if k.startswith(firstsubk + sep)
            }
            tempdict[firstsubk] = _deserialize_attribute(
                mainitem=firstsubv,
                subitems=newsubitems,
                sep=sep,
                original_class=original_class,
                original_pk=original_pk)

        return tempdict
    elif mainitem['datatype'] == 'json':
        try:
            return json.loads(mainitem['tval'])
        except ValueError:
            raise DeserializationException(
                "Error in the content of the json field")
    else:
        raise DeserializationException(
            "The type field '{}' is not recognized".format(
                mainitem['datatype']))
Exemplo n.º 5
0
    def _add_filter(self, key, filtername, value, negate, dbtable, querieslist,
                    attrdict, relnode, relnodeclass):
        """
        Internal method to apply a filter either on Extras or Attributes,
        to avoid to repeat the same code in a DRY spirit.
        """
        valid_filters = {
            '': '',
            None: '',
            '=': '__exact',
            'exact': '__exact',
            'iexact': '__iexact',
            'contains': '__contains',
            'icontains': '__icontains',
            'startswith': '__startswith',
            'istartswith': '__istartswith',
            'endswith': '__endswith',
            'iendsswith': '__iendswith',
            '<': '__lt',
            'lt': '__lt',
            'lte': '__lte',
            'le': '__lte',
            '<=': '__lte',
            '>': '__gt',
            'gt': '__gt',
            'gte': '__gte',
            'ge': '__gte',
            '>=': '__gte',
        }

        querylist = []
        querydict = {}
        querydict['key'] = key

        try:
            internalfilter = valid_filters[filtername]
        except KeyError:
            raise ValueError(
                "Filter '{}' is not a supported filter".format(filtername))

        if value is None:
            querydict['datatype'] = 'none'
        elif isinstance(value, bool):
            querydict['datatype'] = 'bool'
            if negate:
                querylist.append(~Q(
                    **{'bval{}'.format(internalfilter): value}))
            else:
                querydict['bval{}'.format(internalfilter)] = value
        elif isinstance(value, (int, long)):
            querydict['datatype'] = 'int'
            querydict['ival{}'.format(internalfilter)] = value
        elif isinstance(value, float):
            querydict['datatype'] = 'float'
            querydict['fval{}'.format(internalfilter)] = value
        elif isinstance(value, basestring):
            querydict['datatype'] = 'txt'
            if negate:
                querylist.append(~Q(
                    **{'tval{}'.format(internalfilter): value}))
            else:
                querydict['tval{}'.format(internalfilter)] = value
        elif isinstance(value, datetime.datetime):
            # current timezone is taken from the settings file of django
            if is_naive(value):
                value_aware = make_aware(value, get_current_timezone())
            else:
                value_aware = value
            querydict['datatype'] = 'date'
            querydict['dval{}'.format(internalfilter)] = value_aware
        # elif isinstance(value, list):
        #
        #    new_entry.datatype = 'list'
        #    new_entry.ival = length
        #elif isinstance(value, dict):
        #    new_entry.datatype = 'dict'
        #    new_entry.ival = len(value)
        else:
            raise TypeError("Only basic datatypes are supported in queries!")

        reldata = {}
        if relnode is not None:
            if (relnodeclass is not None
                    and not isinstance(relnodeclass, Node)
                    and not issubclass(relnodeclass, Node)):
                raise TypeError("relnodeclass must be an AiiDA node")
            if relnodeclass is None:
                reldata['nodeclass'] = None
            else:
                reldata['nodeclass'] = relnodeclass._query_type_string
            if relnode == 'res':
                reldata['relation'] = "__output"
                reldata['linkname'] = "output_parameters"
            elif relnode.startswith('out.'):
                reldata['relation'] = "__output"
                reldata['linkname'] = relnode[4:]
            elif relnode.startswith('inp.'):
                reldata['relation'] = "__input"
                reldata['linkname'] = relnode[4:]
            else:
                raise NotImplementedError(
                    "Implemented only for 'out.' and 'inp.' for the time being!"
                )
        else:
            if relnodeclass is not None:
                raise ValueError(
                    "cannot pass relnodeclass if no relnode is specified")
        # We are changing the query, clear the cache
        self._queryobject = None
        querieslist.append((dbtable.objects.filter(*querylist,
                                                   **querydict), reldata))
        if reldata:
            pass
        else:
            attrdict[key] = reldata