diff --git a/news/uuid.rst b/news/uuid.rst new file mode 100644 index 00000000..474793f4 --- /dev/null +++ b/news/uuid.rst @@ -0,0 +1,23 @@ +**Added:** + +* Gettable `id` property to `DiffractionObject` + +**Changed:** + +* <news item> + +**Deprecated:** + +* <news item> + +**Removed:** + +* <news item> + +**Fixed:** + +* <news item> + +**Security:** + +* <news item> diff --git a/src/diffpy/utils/diffraction_objects.py b/src/diffpy/utils/diffraction_objects.py index 59aac37b..abfd44b0 100644 --- a/src/diffpy/utils/diffraction_objects.py +++ b/src/diffpy/utils/diffraction_objects.py @@ -1,4 +1,5 @@ import datetime +import uuid import warnings from copy import deepcopy @@ -53,6 +54,7 @@ def __init__( if yarray is None: yarray = np.empty(0) + self._id = uuid.uuid4() self.input_data(xarray, yarray, xtype) def __eq__(self, other): @@ -205,6 +207,14 @@ def input_xtype(self): def input_xtype(self, _): raise AttributeError(_setter_wmsg("input_xtype")) + @property + def id(self): + return self._id + + @id.setter + def id(self, _): + raise AttributeError(_setter_wmsg("id")) + def set_angles_from_list(self, angles_list): self.angles = angles_list self.n_steps = len(angles_list) - 1.0 diff --git a/tests/test_diffraction_objects.py b/tests/test_diffraction_objects.py index 328bb512..50080550 100644 --- a/tests/test_diffraction_objects.py +++ b/tests/test_diffraction_objects.py @@ -1,5 +1,7 @@ import re +import uuid from pathlib import Path +from uuid import UUID import numpy as np import pytest @@ -335,8 +337,8 @@ def test_dump(tmp_path, mocker): @pytest.mark.parametrize("inputs, expected", tc_params) def test_constructor(inputs, expected): - actual_do = DiffractionObject(**inputs) - diff = DeepDiff(actual_do.__dict__, expected, ignore_order=True, significant_digits=13) + actual = DiffractionObject(**inputs).__dict__ + diff = DeepDiff(actual, expected, ignore_order=True, significant_digits=13, exclude_paths="root['_id']") assert diff == {} @@ -369,6 +371,29 @@ def test_all_array_setter(): actual_do.all_arrays = np.empty((4, 4)) +def test_id_getter(): + do = DiffractionObject() + assert hasattr(do, "id") + assert isinstance(do.id, UUID) + assert len(str(do.id)) == 36 + + +def test_id_getter_with_mock(mocker): + mocker.patch.object(DiffractionObject, "id", new_callable=lambda: UUID("d67b19c6-3016-439f-81f7-cf20a04bee87")) + do = DiffractionObject() + assert do.id == UUID("d67b19c6-3016-439f-81f7-cf20a04bee87") + + +def test_id_setter_error(): + do = DiffractionObject() + + with pytest.raises( + AttributeError, + match="Direct modification of attribute 'id' is not allowed. Please use 'input_data' to modify 'id'.", + ): + do.id = uuid.uuid4() + + def test_xarray_yarray_length_mismatch(): with pytest.raises( ValueError, @@ -384,7 +409,7 @@ def test_input_xtype_getter(): assert do.input_xtype == "tth" -def test_input_xtype_setter(): +def test_input_xtype_setter_error(): do = DiffractionObject(xtype="tth") # Attempt to directly modify the property