Skip to content

Commit

Permalink
Merge branch 'develop' into remove-get_backend_manager
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisjsewell authored Oct 20, 2021
2 parents 89f83f5 + fc0b458 commit 7fd8ccb
Show file tree
Hide file tree
Showing 18 changed files with 494 additions and 484 deletions.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ repos:
aiida/orm/implementation/sqlalchemy/backend.py|
aiida/orm/implementation/querybuilder.py|
aiida/orm/implementation/sqlalchemy/querybuilder/.*py|
aiida/orm/entities.py|
aiida/orm/nodes/data/jsonable.py|
aiida/orm/nodes/node.py|
aiida/orm/nodes/process/.*py|
Expand Down
36 changes: 0 additions & 36 deletions aiida/common/datastructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,39 +165,3 @@ class CodeRunMode(IntEnum):

SERIAL = 0
PARALLEL = 1


class LazyStore:
"""
A container that provides a mapping to objects based on a key, if the object is not
found in the container when it is retrieved it will created using a provided factory
method
"""

def __init__(self):
self._store = {}

def get(self, key, factory):
"""
Get a value in the store based on the key, if it doesn't exist it will be created
using the factory method and returned
:param key: the key of the object to get
:param factory: the factory used to create the object if necessary
:return: the object
"""
try:
return self._store[key]
except KeyError:
obj = factory()
self._store[key] = obj
return obj

def pop(self, key):
"""
Pop an object from the store based on the given key
:param key: the object key
:return: the object that was popped
"""
return self._store.pop(key)
7 changes: 4 additions & 3 deletions aiida/common/lang.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import functools
import inspect
import keyword
from typing import Any, Callable, Generic, TypeVar
from typing import Any, Callable, Generic, Type, TypeVar


def isidentifier(identifier):
Expand Down Expand Up @@ -77,6 +77,7 @@ def wrapped_fn(self, *args, **kwargs): # pylint: disable=missing-docstring
override = override_decorator(check=False) # pylint: disable=invalid-name

ReturnType = TypeVar('ReturnType')
SelfType = TypeVar('SelfType')


class classproperty(Generic[ReturnType]): # pylint: disable=invalid-name
Expand All @@ -88,8 +89,8 @@ class classproperty(Generic[ReturnType]): # pylint: disable=invalid-name
instance as its first argument).
"""

def __init__(self, getter: Callable[[Any], ReturnType]) -> None:
def __init__(self, getter: Callable[[Type[SelfType]], ReturnType]) -> None:
self.getter = getter

def __get__(self, instance: Any, owner: Any) -> ReturnType:
def __get__(self, instance: Any, owner: Type[SelfType]) -> ReturnType:
return self.getter(owner)
5 changes: 4 additions & 1 deletion aiida/engine/processes/workchains/restart.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,10 @@ def results(self) -> Optional['ExitCode']:
output = exposed_outputs[name]
except KeyError:
if port.required:
self.report(f"required output '{name}' was not an output of {self.ctx.process_name}<{node.pk}>")
self.report(
f'required output \'{name}\' was not an output of {self.ctx.process_name}<{node.pk}> '
f'(or an incorrect class/output is being exposed).'
)
else:
self.out(name, output)

Expand Down
33 changes: 22 additions & 11 deletions aiida/orm/authinfos.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
# For further information please visit http://www.aiida.net #
###########################################################################
"""Module for the `AuthInfo` ORM class."""
from typing import Type

from aiida.common import exceptions
from aiida.common.lang import classproperty
from aiida.manage.manager import get_manager
from aiida.plugins import TransportFactory

Expand All @@ -18,31 +20,40 @@
__all__ = ('AuthInfo',)


class AuthInfoCollection(entities.Collection['AuthInfo']):
"""The collection of `AuthInfo` entries."""

@staticmethod
def _entity_base_cls() -> Type['AuthInfo']:
return AuthInfo

def delete(self, pk: int) -> None:
"""Delete an entry from the collection.
:param pk: the pk of the entry to delete
"""
self._backend.authinfos.delete(pk)


class AuthInfo(entities.Entity):
"""ORM class that models the authorization information that allows a `User` to connect to a `Computer`."""

class Collection(entities.Collection):
"""The collection of `AuthInfo` entries."""
Collection = AuthInfoCollection

def delete(self, pk):
"""Delete an entry from the collection.
:param pk: the pk of the entry to delete
"""
self._backend.authinfos.delete(pk)
@classproperty
def objects(cls) -> AuthInfoCollection: # pylint: disable=no-self-argument
return AuthInfoCollection.get_cached(cls, get_manager().get_backend())

PROPERTY_WORKDIR = 'workdir'

def __init__(self, computer, user, backend=None):
def __init__(self, computer, user, backend=None) -> None:
"""Create an `AuthInfo` instance for the given computer and user.
:param computer: a `Computer` instance
:type computer: :class:`aiida.orm.Computer`
:param user: a `User` instance
:type user: :class:`aiida.orm.User`
:rtype: :class:`aiida.orm.authinfos.AuthInfo`
"""
backend = backend or get_manager().get_backend()
model = backend.authinfos.create(computer=computer.backend_entity, user=user.backend_entity)
Expand Down
71 changes: 41 additions & 30 deletions aiida/orm/comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,65 @@
# For further information please visit http://www.aiida.net #
###########################################################################
"""Comment objects and functions"""
from typing import List, Type

from aiida.common.lang import classproperty
from aiida.manage.manager import get_manager

from . import entities, users

__all__ = ('Comment',)


class Comment(entities.Entity):
"""Base class to map a DbComment that represents a comment attached to a certain Node."""
class CommentCollection(entities.Collection['Comment']):
"""The collection of Comment entries."""

@staticmethod
def _entity_base_cls() -> Type['Comment']:
return Comment

def delete(self, pk: int) -> None:
"""
Remove a Comment from the collection with the given id
:param pk: the id of the comment to delete
:raises TypeError: if ``comment_id`` is not an `int`
:raises `~aiida.common.exceptions.NotExistent`: if Comment with ID ``comment_id`` is not found
"""
self._backend.comments.delete(pk)

class Collection(entities.Collection):
"""The collection of Comment entries."""
def delete_all(self) -> None:
"""
Delete all Comments from the Collection
def delete(self, comment_id):
"""
Remove a Comment from the collection with the given id
:raises `~aiida.common.exceptions.IntegrityError`: if all Comments could not be deleted
"""
self._backend.comments.delete_all()

:param comment_id: the id of the comment to delete
:type comment_id: int
def delete_many(self, filters) -> List[int]:
"""
Delete Comments from the Collection based on ``filters``
:raises TypeError: if ``comment_id`` is not an `int`
:raises `~aiida.common.exceptions.NotExistent`: if Comment with ID ``comment_id`` is not found
"""
self._backend.comments.delete(comment_id)
:param filters: similar to QueryBuilder filter
:type filters: dict
def delete_all(self):
"""
Delete all Comments from the Collection
:return: (former) ``PK`` s of deleted Comments
:raises `~aiida.common.exceptions.IntegrityError`: if all Comments could not be deleted
"""
self._backend.comments.delete_all()
:raises TypeError: if ``filters`` is not a `dict`
:raises `~aiida.common.exceptions.ValidationError`: if ``filters`` is empty
"""
return self._backend.comments.delete_many(filters)

def delete_many(self, filters):
"""
Delete Comments from the Collection based on ``filters``

:param filters: similar to QueryBuilder filter
:type filters: dict
class Comment(entities.Entity):
"""Base class to map a DbComment that represents a comment attached to a certain Node."""

:return: (former) ``PK`` s of deleted Comments
:rtype: list
Collection = CommentCollection

:raises TypeError: if ``filters`` is not a `dict`
:raises `~aiida.common.exceptions.ValidationError`: if ``filters`` is empty
"""
self._backend.comments.delete_many(filters)
@classproperty
def objects(cls) -> CommentCollection: # pylint: disable=no-self-argument
return CommentCollection.get_cached(cls, get_manager().get_backend())

def __init__(self, node, user, content=None, backend=None):
"""
Expand Down
69 changes: 40 additions & 29 deletions aiida/orm/computers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
"""Module for Computer entities"""
import logging
import os
from typing import List, Optional, Tuple, Type

from aiida.common import exceptions
from aiida.common.lang import classproperty
from aiida.manage.manager import get_manager
from aiida.orm.implementation import Backend
from aiida.plugins import SchedulerFactory, TransportFactory
Expand All @@ -21,6 +23,40 @@
__all__ = ('Computer',)


class ComputerCollection(entities.Collection['Computer']):
"""The collection of Computer entries."""

@staticmethod
def _entity_base_cls() -> Type['Computer']:
return Computer

def get_or_create(self, label: Optional[str] = None, **kwargs) -> Tuple['Computer', bool]:
"""
Try to retrieve a Computer from the DB with the given arguments;
create (and store) a new Computer if such a Computer was not present yet.
:param label: computer label
:return: (computer, created) where computer is the computer (new or existing,
in any case already stored) and created is a boolean saying
"""
if not label:
raise ValueError('Computer label must be provided')

try:
return False, self.get(label=label)
except exceptions.NotExistent:
return True, Computer(backend=self.backend, label=label, **kwargs)

def list_labels(self) -> List[str]:
"""Return a list with all the labels of the computers in the DB."""
return self._backend.computers.list_names()

def delete(self, pk: int) -> None:
"""Delete the computer with the given id"""
return self._backend.computers.delete(pk)


class Computer(entities.Entity):
"""
Computer entity.
Expand All @@ -34,36 +70,11 @@ class Computer(entities.Entity):
PROPERTY_WORKDIR = 'workdir'
PROPERTY_SHEBANG = 'shebang'

class Collection(entities.Collection):
"""The collection of Computer entries."""

def get_or_create(self, label=None, **kwargs):
"""
Try to retrieve a Computer from the DB with the given arguments;
create (and store) a new Computer if such a Computer was not present yet.
:param label: computer label
:type label: str
:return: (computer, created) where computer is the computer (new or existing,
in any case already stored) and created is a boolean saying
:rtype: (:class:`aiida.orm.Computer`, bool)
"""
if not label:
raise ValueError('Computer label must be provided')

try:
return False, self.get(label=label)
except exceptions.NotExistent:
return True, Computer(backend=self.backend, label=label, **kwargs)

def list_labels(self):
"""Return a list with all the labels of the computers in the DB."""
return self._backend.computers.list_names()
Collection = ComputerCollection

def delete(self, id): # pylint: disable=redefined-builtin,invalid-name
"""Delete the computer with the given id"""
return self._backend.computers.delete(id)
@classproperty
def objects(cls) -> ComputerCollection: # pylint: disable=no-self-argument
return ComputerCollection.get_cached(cls, get_manager().get_backend())

def __init__( # pylint: disable=too-many-arguments
self,
Expand Down
Loading

0 comments on commit 7fd8ccb

Please sign in to comment.