diff --git a/src/easyscience/Objects/variable/__init__.py b/src/easyscience/Objects/variable/__init__.py index 37b9571..e2b6663 100644 --- a/src/easyscience/Objects/variable/__init__.py +++ b/src/easyscience/Objects/variable/__init__.py @@ -1,9 +1,11 @@ +from .descriptor_any_type import DescriptorAnyType from .descriptor_bool import DescriptorBool from .descriptor_number import DescriptorNumber from .descriptor_str import DescriptorStr from .parameter import Parameter __all__ = [ + DescriptorAnyType, DescriptorBool, DescriptorNumber, DescriptorStr, diff --git a/src/easyscience/Objects/variable/descriptor_any_type.py b/src/easyscience/Objects/variable/descriptor_any_type.py new file mode 100644 index 0000000..0d117ce --- /dev/null +++ b/src/easyscience/Objects/variable/descriptor_any_type.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +import numbers +from typing import Any +from typing import Dict +from typing import List +from typing import Optional +from typing import Union + +import numpy as np + +from easyscience.global_object.undo_redo import property_stack_deco + +from .descriptor_base import DescriptorBase + + +class DescriptorAnyType(DescriptorBase): + """ + A `Descriptor` for any type that does not fit the other Descriptors. Should be avoided when possible. + It was created to hold the symmetry operations used in the SpaceGroup class of EasyCrystallography. + """ + + def __init__( + self, + name: str, + value: Any, + unique_name: Optional[str] = None, + description: Optional[str] = None, + url: Optional[str] = None, + display_name: Optional[str] = None, + parent: Optional[Any] = None, + ): + """Constructor for the DescriptorAnyType class + + param name: Name of the descriptor + param value: Value of the descriptor + param description: Description of the descriptor + param url: URL of the descriptor + param display_name: Display name of the descriptor + param parent: Parent of the descriptor + .. note:: Undo/Redo functionality is implemented for the attributes `variance`, `error`, `unit` and `value`. + """ + + self._value=value + + super().__init__( + name=name, + unique_name=unique_name, + description=description, + url=url, + display_name=display_name, + parent=parent, + ) + + @property + def value(self) -> numbers.Number: + """ + Get the value. + + :return: Value of self. + """ + return self._value + + @value.setter + @property_stack_deco + def value(self, value: Union[list, np.ndarray]) -> None: + """ + Set the value of self. + + :param value: New value for the DescriptorAnyType. + """ + self._value = value + + def __copy__(self) -> DescriptorAnyType: + return super().__copy__() + + def __repr__(self) -> str: + """ + Return a string representation of the DescriptorAnyType, showing its name and value. + """ + + if hasattr(self._value, '__repr__'): + value_repr = repr(self._value) + else: + value_repr = type(self._value) + + return f"<{self.__class__.__name__} '{self._name}': {value_repr}>" + + def as_dict(self, skip: Optional[List[str]] = None) -> Dict[str, Any]: + raw_dict = super().as_dict(skip=skip) + raw_dict['value'] = self._value + return raw_dict + diff --git a/tests/unit_tests/Objects/variable/test_descriptor_any_type.py b/tests/unit_tests/Objects/variable/test_descriptor_any_type.py new file mode 100644 index 0000000..5b8a131 --- /dev/null +++ b/tests/unit_tests/Objects/variable/test_descriptor_any_type.py @@ -0,0 +1,92 @@ +import pytest +import numpy as np + +from easyscience.Objects.variable.descriptor_any_type import DescriptorAnyType +from easyscience import global_object + +class TestDescriptorAnyType: + @pytest.fixture + def descriptor(self): + descriptor = DescriptorAnyType( + name="name", + value="string", + description="description", + url="url", + display_name="display_name", + parent=None, + ) + return descriptor + + @pytest.fixture + def clear(self): + global_object.map._clear() + + def test_init(self, descriptor: DescriptorAnyType): + # When Then Expect + assert descriptor._value == "string" + + # From super + assert descriptor._name == "name" + assert descriptor._description == "description" + assert descriptor._url == "url" + assert descriptor._display_name == "display_name" + + def test_value(self, descriptor: DescriptorAnyType): + # When Then Expect + assert descriptor.value == "string" + + + @pytest.mark.parametrize("value", [True, "new_string", 1.0, np.array([1, 2, 3]),{"key": "value"}]) + def test_set_value(self, descriptor: DescriptorAnyType,value): + # When Then + descriptor.value = value + + # Expect + if isinstance(value, np.ndarray): + assert np.array_equal(descriptor._value, value) + else: + assert descriptor._value == value + + @pytest.mark.parametrize( + "value, expected", + [ + (True, "True"), + ("new_string", "'new_string'"), + (1.0, "1.0"), + (np.array([1, 2, 3]), "array([1, 2, 3])"), + ({"key": "value"}, "{'key': 'value'}") + ] + ) + def test_repr(self, descriptor: DescriptorAnyType, value, expected): + # Set the descriptor value + descriptor.value = value + + # When Then + repr_str = str(descriptor) + + print(repr_str) + + # Expect + assert repr_str == f"" + + def test_copy(self, descriptor: DescriptorAnyType): + # When Then + descriptor_copy = descriptor.__copy__() + + # Expect + assert type(descriptor_copy) == DescriptorAnyType + assert descriptor_copy._value == descriptor._value + + def test_as_data_dict(self, clear, descriptor: DescriptorAnyType): + # When Then + descriptor_dict = descriptor.as_data_dict() + + # Expect + assert descriptor_dict == { + "name": "name", + "value": "string", + "description": "description", + "url": "url", + "display_name": "display_name", + "unique_name": "DescriptorAnyType_0" + } \ No newline at end of file