Skip to content

Commit

Permalink
Removed get_aiida_class
Browse files Browse the repository at this point in the history
Replaced all instances with either `get_backend_entity` or `get_orm_entity`
(as appropriate).

Also changed backend group to be independent of the ORM.  Because the
iterator was getting the ORM class and returning that, which required it
to access up to the ORM level.  Now it just returns backend entities
which are in turn converted to ORM entities by the `orm.Group`.  This also
means you can't call `len(group.nodes)` because this is not allowed for
iterators but the same can be achieved with `len(list(group.nodes))`
  • Loading branch information
muhrin committed Dec 7, 2018
1 parent 801619f commit f2643b3
Show file tree
Hide file tree
Showing 41 changed files with 617 additions and 787 deletions.
4 changes: 2 additions & 2 deletions aiida/backends/djsite/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def get_workflow_list(pk_list=tuple(), user=None, all_states=False, n_days_ago=N
workflows started up to this number of days ago
"""
from aiida.backends.djsite.db.models import DbWorkflow
from aiida.orm.implementation.django import convert

if pk_list:
filters = Q(pk__in=pk_list)
Expand All @@ -44,5 +45,4 @@ def get_workflow_list(pk_list=tuple(), user=None, all_states=False, n_days_ago=N
filters &= Q(ctime__gte=time)

wf_list = DbWorkflow.objects.filter(filters).order_by('ctime') # pylint: disable=no-member

return list(wf_list)
return [convert.get_backend_entity(wf, None) for wf in wf_list]
66 changes: 10 additions & 56 deletions aiida/backends/djsite/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@
AbstractBaseUser, BaseUserManager, PermissionsMixin)
from django.utils.encoding import python_2_unicode_compatible
from django.core.exceptions import ObjectDoesNotExist
from django.db.models.query import QuerySet, ModelIterable
from django.db.models.query import QuerySet

from aiida.utils import timezone
from aiida.common.utils import get_new_uuid
from aiida.common.exceptions import (
ConfigurationError, DbContentError, MissingPluginError)

from aiida.common.exceptions import (ConfigurationError, DbContentError)
from aiida.backends.djsite.settings.settings import AUTH_USER_MODEL
import aiida.backends.djsite.db.migrations as migrations
from aiida.backends.utils import AIIDA_ATTRIBUTE_SEP
Expand All @@ -44,24 +42,26 @@

class AiidaQuerySet(QuerySet):
def iterator(self):
from aiida.orm.implementation.django import convert
for obj in super(AiidaQuerySet, self).iterator():
yield obj.get_aiida_class()
yield convert.get_backend_entity(obj, None)

def __iter__(self):
"""Iterate for list comprehensions.
Note: used to rely on the iterator in django 1.8 but does no longer in django 1.11.
"""

return (x.get_aiida_class() for x in super(AiidaQuerySet, self).__iter__())
from aiida.orm.implementation.django import convert
return (convert.get_backend_entity(model, None) for model in super(AiidaQuerySet, self).__iter__())

def __getitem__(self, key):
"""Get item for [] operator
Note: used to rely on the iterator in django 1.8 but does no longer in django 1.11.
"""
from aiida.orm.implementation.django import convert
res = super(AiidaQuerySet, self).__getitem__(key)
return res.get_aiida_class()
return convert.get_backend_entity(res, None)


class AiidaObjectManager(m.Manager):
Expand Down Expand Up @@ -118,11 +118,6 @@ class DbUser(AbstractBaseUser, PermissionsMixin):

objects = DbUserManager()

def get_aiida_class(self):
from aiida.orm.implementation.django.users import DjangoUser
from aiida.manage import get_manager
return DjangoUser.from_dbmodel(self, get_manager().get_backend())


@python_2_unicode_compatible
class DbNode(m.Model):
Expand Down Expand Up @@ -184,25 +179,6 @@ class DbNode(m.Model):
# Return aiida Node instances or their subclasses instead of DbNode instances
aiidaobjects = AiidaObjectManager()

def get_aiida_class(self):
"""
Return the corresponding aiida instance of class aiida.orm.Node or a
appropriate subclass.
"""
from aiida.common import AIIDA_LOGGER
from aiida.orm.node import Node
from aiida.plugins.loader import get_plugin_type_from_type_string, load_plugin

try:
plugin_type = get_plugin_type_from_type_string(self.type)
except DbContentError:
raise DbContentError("The type name of node with pk= {} is "
"not valid: '{}'".format(self.pk, self.type))

PluginClass = load_plugin(plugin_type, safe=True)

return PluginClass(dbnode=self)

def get_simple_name(self, invalid_result=None):
"""
Return a string with the last part of the type name.
Expand Down Expand Up @@ -1313,11 +1289,6 @@ def __str__(self):
else:
return '<DbGroup [user-defined] "{}">'.format(self.name)

def get_aiida_class(self):
from aiida.orm.implementation.django.groups import DjangoGroup
from aiida.manage import get_manager
return DjangoGroup.from_dbmodel(self, get_manager().get_backend())


@python_2_unicode_compatible
class DbComputer(m.Model):
Expand Down Expand Up @@ -1397,11 +1368,6 @@ def get_dbcomputer(cls, computer):
"Pass either a computer name, a DbComputer django instance, a Computer pk or a Computer object")
return dbcomputer

def get_aiida_class(self):
from aiida.orm.implementation.django.computer import DjangoComputer
from aiida.manage import get_manager
return DjangoComputer.from_dbmodel(self, get_manager().get_backend())

def _get_val_from_metadata(self, key):
import aiida.utils.json as json

Expand Down Expand Up @@ -1450,11 +1416,6 @@ def __str__(self):
else:
return "DB authorization info for {} on {} [DISABLED]".format(self.aiidauser.email, self.dbcomputer.name)

def get_aiida_class(self):
from aiida.orm.implementation.django.authinfo import DjangoAuthInfo
from aiida.manage import get_manager
return DjangoAuthInfo.from_dbmodel(self, get_manager().get_backend())


@python_2_unicode_compatible
class DbComment(m.Model):
Expand Down Expand Up @@ -1519,14 +1480,6 @@ class DbWorkflow(m.Model):
# Return aiida Node instances or their subclasses instead of DbNode instances
aiidaobjects = AiidaObjectManager()

def get_aiida_class(self):
"""
Return the corresponding aiida instance of class aiida.workflow
"""
from aiida.orm.workflow import Workflow

return Workflow.get_subclass_from_dbnode(self)

def set_state(self, _state):
self.state = _state
self.save()
Expand Down Expand Up @@ -1694,14 +1647,15 @@ def set_value(self, arg):
six.reraise(ValueError, "Cannot set the parameter {}".format(self.name), sys.exc_info()[2])

def get_value(self):
from aiida.orm.convert import get_orm_entity
import aiida.utils.json as json

from aiida.common.datastructures import wf_data_value_types

if self.value_type == wf_data_value_types.JSON:
return json.loads(self.json_value)
elif self.value_type == wf_data_value_types.AIIDA:
return self.aiida_obj.get_aiida_class()
return get_orm_entity(self.aiida_obj)
elif self.value_type == wf_data_value_types.NONE:
return None
else:
Expand Down
4 changes: 2 additions & 2 deletions aiida/backends/sqlalchemy/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def get_workflow_list(pk_list=tuple(), user=None, all_states=False, n_days_ago=N
"""
from aiida.backends.sqlalchemy.models.workflow import DbWorkflow
from aiida.common.datastructures import wf_states
from aiida.orm.implementation.sqlalchemy import convert

if pk_list:
query = DbWorkflow.query.filter(DbWorkflow.id.in_(pk_list))
Expand All @@ -41,5 +42,4 @@ def get_workflow_list(pk_list=tuple(), user=None, all_states=False, n_days_ago=N
time = timezone.now() - datetime.timedelta(days=n_days_ago)
query = query.filter(DbWorkflow.ctime >= time)

wf_list = list(query.distinct().order_by('ctime'))
return wf_list
return [convert.get_backend_entity(wf, None) for wf in query.distinct().order_by('ctime')]
3 changes: 2 additions & 1 deletion aiida/backends/sqlalchemy/migrations/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
from aiida.backends.sqlalchemy.models.computer import DbComputer
from aiida.backends.sqlalchemy.models.group import DbGroup
from aiida.backends.sqlalchemy.models.log import DbLog
from aiida.backends.sqlalchemy.models.node import DbComputer, DbContentError, DbLink, DbNode
from aiida.backends.sqlalchemy.models.node import DbComputer, DbLink, DbNode
from aiida.backends.sqlalchemy.models.settings import DbSetting
from aiida.backends.sqlalchemy.models.user import DbUser
from aiida.backends.sqlalchemy.models.workflow import (
DbWorkflow, DbWorkflowData, DbWorkflowStep)
from aiida.common.exceptions import DbContentError
from aiida.backends.sqlalchemy.models.base import Base
target_metadata = Base.metadata

Expand Down
7 changes: 1 addition & 6 deletions aiida/backends/sqlalchemy/models/authinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from sqlalchemy.types import Integer, Boolean
from sqlalchemy.dialects.postgresql import JSONB

from aiida.backends.sqlalchemy.models.base import Base
from .base import Base


class DbAuthInfo(Base):
Expand Down Expand Up @@ -52,8 +52,3 @@ def __str__(self):
return "DB authorization info for {} on {}".format(self.aiidauser.email, self.dbcomputer.name)
else:
return "DB authorization info for {} on {} [DISABLED]".format(self.aiidauser.email, self.dbcomputer.name)

def get_aiida_class(self):
from aiida.orm.implementation.sqlalchemy.authinfo import SqlaAuthInfo
from aiida.manage import get_manager
return SqlaAuthInfo.from_dbmodel(dbmodel=self, backend=get_manager().get_backend())
10 changes: 6 additions & 4 deletions aiida/backends/sqlalchemy/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,15 @@ def __init__(self, *args, **kwargs):
super(_AiidaQuery, self).__init__(*args, **kwargs)

def __iter__(self):
from aiida.orm.implementation.sqlalchemy import convert

iterator = super(_AiidaQuery, self).__iter__()
for r in iterator:
for result in iterator:
# Allow the use of with_entities
if issubclass(type(r), Model):
yield r.get_aiida_class()
if issubclass(type(result), Model):
yield convert.get_backend_entity(result, None)
else:
yield r
yield result


from aiida.backends.sqlalchemy import get_scoped_session
Expand Down
5 changes: 0 additions & 5 deletions aiida/backends/sqlalchemy/models/computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,6 @@ def get_dbcomputer(cls, computer):
"Pass either a computer name, a DbComputer SQLAlchemy instance, a Computer id or a Computer object")
return dbcomputer

def get_aiida_class(self):
from aiida.orm.implementation.sqlalchemy.backend import SqlaBackend
backend = SqlaBackend()
return backend.computers.from_dbmodel(self)

@property
def pk(self):
return self.id
Expand Down
11 changes: 3 additions & 8 deletions aiida/backends/sqlalchemy/models/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, backref
from sqlalchemy.schema import Column, Table, UniqueConstraint, Index
from sqlalchemy.types import Integer, String, Boolean, DateTime, Text
from sqlalchemy.types import Integer, String, DateTime, Text

from sqlalchemy.dialects.postgresql import UUID

from aiida.utils import timezone
from aiida.backends.sqlalchemy.models.base import Base
from aiida.backends.sqlalchemy.models.utils import uuid_func
from .base import Base
from .utils import uuid_func

table_groups_nodes = Table(
'db_dbgroup_dbnodes',
Expand Down Expand Up @@ -67,8 +67,3 @@ def __str__(self):
return '<DbGroup [type: {}] "{}">'.format(self.type, self.name)

return '<DbGroup [user-defined] "{}">'.format(self.name)

def get_aiida_class(self):
from aiida.orm.implementation.sqlalchemy.backend import SqlaBackend
backend = SqlaBackend()
return backend.groups.from_dbmodel(self)
32 changes: 3 additions & 29 deletions aiida/backends/sqlalchemy/models/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,27 @@
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import
from sqlalchemy import ForeignKey, select, func, join, case
from sqlalchemy import ForeignKey, select
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.schema import Column, UniqueConstraint, Index
from sqlalchemy.schema import Column
from sqlalchemy.types import Integer, String, Boolean, DateTime, Text
# Specific to PGSQL. If needed to be agnostic
# http://docs.sqlalchemy.org/en/rel_0_9/core/custom_types.html?highlight=guid#backend-agnostic-guid-type
# Or maybe rely on sqlalchemy-utils UUID type
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy_utils.types.choice import ChoiceType

from aiida.utils import timezone
from aiida.backends.sqlalchemy.models.base import Base, _QueryProperty, _AiidaQuery
from aiida.backends.sqlalchemy.models.base import Base
from aiida.backends.sqlalchemy.models.utils import uuid_func
from aiida.backends.sqlalchemy.utils import flag_modified

from aiida.common.exceptions import DbContentError
from aiida.common.datastructures import calc_states, _sorted_datastates, sort_states

from aiida.backends.sqlalchemy.models.user import DbUser
from aiida.backends.sqlalchemy.models.computer import DbComputer


class DbNode(Base):
__tablename__ = "db_dbnode"

aiida_query = _QueryProperty(_AiidaQuery)

id = Column(Integer, primary_key=True)
uuid = Column(UUID(as_uuid=True), default=uuid_func, unique=True)
type = Column(String(255), index=True)
Expand Down Expand Up @@ -114,25 +107,6 @@ def outputs(self):
def inputs(self):
return self.inputs_q.all()

# XXX repetition between django/sqlalchemy here.
def get_aiida_class(self):
"""
Return the corresponding aiida instance of class aiida.orm.Node or a
appropriate subclass.
"""
from aiida.orm.node import Node
from aiida.plugins.loader import get_plugin_type_from_type_string, load_plugin

try:
plugin_type = get_plugin_type_from_type_string(self.type)
except DbContentError:
raise DbContentError("The type name of node with pk= {} is "
"not valid: '{}'".format(self.pk, self.type))

PluginClass = load_plugin(plugin_type, safe=True)

return PluginClass(dbnode=self)

def get_simple_name(self, invalid_result=None):
"""
Return a string with the last part of the type name.
Expand Down
5 changes: 0 additions & 5 deletions aiida/backends/sqlalchemy/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,3 @@ def __init__(self, email, first_name="", last_name="", institution="", **kwargs)

def __str__(self):
return self.email

def get_aiida_class(self):
from aiida.orm.implementation.sqlalchemy.users import SqlaUser
from aiida.manage import get_manager
return SqlaUser.from_dbmodel(self, get_manager().get_backend())

0 comments on commit f2643b3

Please sign in to comment.