diff options
author | John L. Villalovos <john@sodarock.com> | 2022-07-20 08:38:31 -0700 |
---|---|---|
committer | John L. Villalovos <john@sodarock.com> | 2022-07-20 08:38:31 -0700 |
commit | e5affc8749797293c1373c6af96334f194875038 (patch) | |
tree | 91fbf3e2ade71e17da2083f4b3b9702e4fbc3cde | |
parent | f6b6e18f96f4cdf67c8c53ae79e6a8259dcce9ee (diff) | |
download | gitlab-e5affc8749797293c1373c6af96334f194875038.tar.gz |
fix: results returned by `attributes` property to show updates
Previously the `attributes` method would show the original values in a
Gitlab Object even if they had been updated. Correct this so that the
updated value will be returned.
Also use copy.deepcopy() to ensure that modifying the dictionary returned can
not also modify the object.
-rw-r--r-- | gitlab/base.py | 10 | ||||
-rw-r--r-- | tests/unit/test_base.py | 26 |
2 files changed, 32 insertions, 4 deletions
diff --git a/gitlab/base.py b/gitlab/base.py index 920617b..7de76e0 100644 --- a/gitlab/base.py +++ b/gitlab/base.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +import copy import importlib import pprint import textwrap @@ -243,10 +244,11 @@ class RESTObject: @property def attributes(self) -> Dict[str, Any]: - d = self.__dict__["_updated_attrs"].copy() - d.update(self.__dict__["_attrs"]) - d.update(self.__dict__["_parent_attrs"]) - return d + data = {} + data.update(copy.deepcopy(self._parent_attrs)) + data.update(copy.deepcopy(self._attrs)) + data.update(copy.deepcopy(self._updated_attrs)) + return data class RESTObjectList: diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index ea4ad9e..53e484e 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -46,6 +46,11 @@ def fake_manager(fake_gitlab): return FakeManager(fake_gitlab) +@pytest.fixture +def fake_object(fake_manager): + return FakeObject(fake_manager, {"attr1": [1, 2, 3]}) + + class TestRESTManager: def test_computed_path_simple(self): class MGR(base.RESTManager): @@ -306,3 +311,24 @@ class TestRESTObject: FakeObject._id_attr = None assert repr(obj) == "<FakeObject>" + + def test_attributes_get(self, fake_object): + assert fake_object.attr1 == [1, 2, 3] + result = fake_object.attributes + assert result == {"attr1": [1, 2, 3]} + + def test_attributes_shows_updates(self, fake_object): + # Updated attribute value is reflected in `attributes` + fake_object.attr1 = "hello" + assert fake_object.attributes == {"attr1": "hello"} + assert fake_object.attr1 == "hello" + # New attribute is in `attributes` + fake_object.new_attrib = "spam" + assert fake_object.attributes == {"attr1": "hello", "new_attrib": "spam"} + + def test_attributes_is_copy(self, fake_object): + # Modifying the dictionary does not cause modifications to the object + result = fake_object.attributes + result["attr1"].append(10) + assert result == {"attr1": [1, 2, 3, 10]} + assert fake_object.attributes == {"attr1": [1, 2, 3]} |