Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List: register the class with the to_aiida_type serializer #5142

Merged
merged 2 commits into from
Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions aiida/orm/nodes/data/dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ def __getitem__(self, key):
def __setitem__(self, key, value):
self.set_attribute(key, value)

def __eq__(self, other):
if isinstance(other, dict):
return self.get_dict() == other

return self is other

def set_dict(self, dictionary):
""" Replace the current dictionary with another one.

Expand Down
6 changes: 6 additions & 0 deletions aiida/orm/nodes/data/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""`Data` sub class to represent a list."""
from collections.abc import MutableSequence

from .base import to_aiida_type
from .data import Data

__all__ = ('List',)
Expand Down Expand Up @@ -139,3 +140,8 @@ def _using_list_reference(self):
:rtype: bool
"""
return not self.is_stored


@to_aiida_type.register(list)
def _(value):
return List(list=value)
115 changes: 74 additions & 41 deletions tests/orm/data/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,58 +7,91 @@
# For further information on the license, see the LICENSE.txt file #
# For further information please visit http://www.aiida.net #
###########################################################################
"""Tests for the `Dict` class."""
# pylint: disable=redefined-outer-name
"""Tests for :class:`aiida.orm.nodes.data.dict.Dict` class."""
import pytest

from aiida.backends.testbase import AiidaTestCase
from aiida.orm import Dict


class TestDict(AiidaTestCase):
"""Test for the `Dict` class."""
@pytest.fixture
def dictionary():
return {'value': 1, 'nested': {'dict': 'ionary'}}

@classmethod
def setUpClass(cls, *args, **kwargs):
super().setUpClass(*args, **kwargs)
cls.dictionary = {'value': 1, 'nested': {'dict': 'ionary'}}
cls.node = Dict(dict=cls.dictionary)

def test_keys(self):
"""Test the `keys` method."""
self.assertEqual(sorted(self.node.keys()), sorted(self.dictionary.keys()))
@pytest.mark.usefixtures('clear_database_before_test')
def test_keys(dictionary):
"""Test the ``keys`` method."""
node = Dict(dict=dictionary)
assert sorted(node.keys()) == sorted(dictionary.keys())

def test_get_dict(self):
"""Test the `get_dict` method."""
self.assertEqual(self.node.get_dict(), self.dictionary)

def test_dict_property(self):
"""Test the `dict` property."""
self.assertEqual(self.node.dict.value, self.dictionary['value'])
self.assertEqual(self.node.dict.nested, self.dictionary['nested'])
@pytest.mark.usefixtures('clear_database_before_test')
def test_get_dict(dictionary):
"""Test the ``get_dict`` method."""
node = Dict(dict=dictionary)
assert node.get_dict() == dictionary

def test_get_item(self):
"""Test the `__getitem__` method."""
self.assertEqual(self.node['value'], self.dictionary['value'])
self.assertEqual(self.node['nested'], self.dictionary['nested'])

def test_set_item(self):
"""Test the methods for setting the item.
@pytest.mark.usefixtures('clear_database_before_test')
def test_dict_property(dictionary):
"""Test the ``dict`` property."""
node = Dict(dict=dictionary)
assert node.dict.value == dictionary['value']
assert node.dict.nested == dictionary['nested']

* `__setitem__` directly on the node
* `__setattr__` through the `AttributeManager` returned by the `dict` property
"""
self.node['value'] = 2
self.assertEqual(self.node['value'], 2)
self.node.dict.value = 3
self.assertEqual(self.node['value'], 3)

def test_correct_raises(self):
"""Test that the methods for accessing the item raise the correct error.
@pytest.mark.usefixtures('clear_database_before_test')
def test_get_item(dictionary):
"""Test the ``__getitem__`` method."""
node = Dict(dict=dictionary)
assert node['value'] == dictionary['value']
assert node['nested'] == dictionary['nested']

* `dictnode['inexistent']` should raise KeyError
* `dictnode.dict.inexistent` should raise AttributeError
"""
with self.assertRaises(KeyError):
_ = self.node['inexistent_key']

with self.assertRaises(AttributeError):
_ = self.node.dict.inexistent_key
@pytest.mark.usefixtures('clear_database_before_test')
def test_set_item(dictionary):
"""Test the methods for setting the item.

* ``__setitem__`` directly on the node
* ``__setattr__`` through the ``AttributeManager`` returned by the ``dict`` property
"""
node = Dict(dict=dictionary)

node['value'] = 2
assert node['value'] == 2

node.dict.value = 3
assert node['value'] == 3


@pytest.mark.usefixtures('clear_database_before_test')
def test_correct_raises(dictionary):
"""Test that the methods for accessing the item raise the correct error.

* ``node['inexistent']`` should raise ``KeyError``
* ``node.dict.inexistent`` should raise ``AttributeError``
"""
node = Dict(dict=dictionary)

with pytest.raises(KeyError):
_ = node['inexistent_key']

with pytest.raises(AttributeError):
_ = node.dict.inexistent_key


@pytest.mark.usefixtures('clear_database_before_test')
def test_eq(dictionary):
"""Test the ``__eq__`` method.

A node should compare equal to itself and to the plain dictionary that represents its value. However, it should not
compare equal to another node that has the same content. This is a hot issue and is being discussed in the following
ticket: https://github.com/aiidateam/aiida-core/issues/1917
"""
node = Dict(dict=dictionary)
clone = Dict(dict=dictionary)

assert node is node # pylint: disable=comparison-with-itself
assert node == dictionary
assert node != clone
87 changes: 24 additions & 63 deletions tests/orm/data/test_to_aiida_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,66 +7,27 @@
# For further information on the license, see the LICENSE.txt file #
# For further information please visit http://www.aiida.net #
###########################################################################
"""
This module contains tests for the to_aiida_type serializer
"""
from aiida.orm import to_aiida_type
from aiida.orm import Dict, Int, Float, Bool, Str

from aiida.backends.testbase import AiidaTestCase


class TestToAiiDAType(AiidaTestCase):
"""
Test the to_aiida_type serialize that converts
python objects to AiiDA nodes
"""

def test_dict(self):
"""Test converting dict to Dict"""

data = {'foo': 'bar', 'bla': {'bar': 'foo'}}

# pylint: disable=assignment-from-no-return
aiida_dict = to_aiida_type(data)
self.assertIsInstance(aiida_dict, Dict)
self.assertEqual(aiida_dict.get_dict(), data)

def test_int(self):
"""Test integer"""

# pylint: disable=assignment-from-no-return
aiida_int = to_aiida_type(1234567)
self.assertEqual(aiida_int, 1234567)
self.assertIsInstance(aiida_int, Int)

def test_flot(self):
"""Test converting float to Float"""

float_value = 3.14159265358
# pylint: disable=assignment-from-no-return
aiida_float = to_aiida_type(float_value)
self.assertEqual(aiida_float, float_value)
self.assertIsInstance(aiida_float, Float)

def test_bool(self):
"""Test converting bool to Bool"""

import numpy as np
# pylint: disable=assignment-from-no-return
aiida_bool = to_aiida_type(True)
self.assertIsInstance(aiida_bool, Bool)
self.assertEqual(aiida_bool, True)

# pylint: disable=assignment-from-no-return
aiida_bool = to_aiida_type(np.bool_(True))
self.assertIsInstance(aiida_bool, Bool)
self.assertEqual(np.bool_(True), True)

def test_str(self):
"""Test converting string to Str"""
string = 'hello world'
# pylint: disable=assignment-from-no-return
aiida_string = to_aiida_type(string)
self.assertIsInstance(aiida_string, Str)
self.assertEqual(aiida_string, string)
"""Test the :meth:`aiida.orm.data.base.to_aiida_type` serializer."""
import pytest

from aiida import orm


#yapf: disable
@pytest.mark.usefixtures('clear_database_before_test')
@pytest.mark.parametrize(
'expected_type, value', (
(orm.Bool, True),
(orm.Dict, {'foo': 'bar'}),
(orm.Float, 5.0),
(orm.Int, 5),
(orm.List, [0, 1, 2]),
(orm.Str, 'test-string'),
)
)
# yapf: enable
def test_to_aiida_type(expected_type, value):
"""Test the ``to_aiida_type`` dispatch."""
converted = orm.to_aiida_type(value)
assert isinstance(converted, expected_type)
assert converted == value