Skip to content

Commit 3b95671

Browse files
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.
1 parent c188cb0 commit 3b95671

File tree

3 files changed

+16
-35
lines changed

3 files changed

+16
-35
lines changed

docs/api-usage.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,9 @@ the dictionary will have no impact on the GitLab Object. This can also be used
219219
to create a JSON representation of the object. There are two ways to retrieve a
220220
dictionary representation of the Gitlab Object.
221221

222-
* `asdict()` method. Returns a dictionary with updated attributes having precedence.
223-
* `attributes` property. Returns a dictionary with original attributes having
224-
precedence and then updated attributes. Also returns any relevant parent object
225-
attributes.
222+
* `asdict()` method. Returns a dictionary representation of the Gitlab object.
223+
* `attributes` property. Returns a dictionary representation of the Gitlab object.
224+
Also returns any relevant parent object attributes.
226225

227226
.. note::
228227

gitlab/base.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ def __setattr__(self, name: str, value: Any) -> None:
144144
self.__dict__["_updated_attrs"][name] = value
145145

146146
def asdict(self) -> Dict[str, Any]:
147-
data = copy.deepcopy(self._attrs)
147+
data = {}
148+
data.update(copy.deepcopy(self._attrs))
148149
data.update(copy.deepcopy(self._updated_attrs))
149150
return data
150151

@@ -245,10 +246,10 @@ def encoded_id(self) -> Optional[Union[int, str]]:
245246

246247
@property
247248
def attributes(self) -> Dict[str, Any]:
248-
d = self.__dict__["_updated_attrs"].copy()
249-
d.update(self.__dict__["_attrs"])
250-
d.update(self.__dict__["_parent_attrs"])
251-
return d
249+
data = {}
250+
data.update(copy.deepcopy(self._parent_attrs))
251+
data.update(copy.deepcopy(self.asdict()))
252+
return data
252253

253254

254255
class RESTObjectList:

tests/unit/test_base.py

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -341,36 +341,17 @@ def test_attributes(self, fake_manager):
341341
result = fake_object.attributes
342342
assert result == {"attr1": [1, 2, 3]}
343343

344-
# Updated attribute value is not reflected in `attributes`
344+
# Updated attribute value is reflected in `attributes`
345345
fake_object.attr1 = "hello"
346-
assert fake_object.attributes == {"attr1": [1, 2, 3]}
346+
assert fake_object.attributes == {"attr1": "hello"}
347347
assert fake_object.attr1 == "hello"
348348
# New attribute is in `attributes`
349349
fake_object.new_attrib = "spam"
350-
assert fake_object.attributes == {"attr1": [1, 2, 3], "new_attrib": "spam"}
350+
assert fake_object.attributes == {"attr1": "hello", "new_attrib": "spam"}
351351

352-
# Modifying the dictionary can cause modification to the object :(
352+
# Modifying the dictionary does not cause modifications to the object
353+
fake_object = FakeObject(fake_manager, {"attr1": [1, 2, 3]})
353354
result = fake_object.attributes
354355
result["attr1"].append(10)
355-
assert result == {"attr1": [1, 2, 3, 10], "new_attrib": "spam"}
356-
assert fake_object.attributes == {"attr1": [1, 2, 3, 10], "new_attrib": "spam"}
357-
assert fake_object.attr1 == "hello"
358-
359-
360-
def test_asdict_vs_attributes(self, fake_manager):
361-
fake_object = FakeObject(fake_manager, {"attr1": "foo"})
362-
assert fake_object.attr1 == "foo"
363-
result = fake_object.asdict()
364-
assert result == {"attr1": "foo"}
365-
366-
# New attribute added, return same result
367-
assert fake_object.attributes == fake_object.asdict()
368-
fake_object.attr2 = "eggs"
369-
assert fake_object.attributes == fake_object.asdict()
370-
# Update attribute, return different result
371-
fake_object.attr1 = "hello"
372-
assert fake_object.attributes != fake_object.asdict()
373-
# asdict() returns the updated value
374-
assert fake_object.asdict() == {"attr1": "hello", "attr2": "eggs"}
375-
# `attributes` returns original value
376-
assert fake_object.attributes == {"attr1": "foo", "attr2": "eggs"}
356+
assert result == {"attr1": [1, 2, 3, 10]}
357+
assert fake_object.attributes == {"attr1": [1, 2, 3]}

0 commit comments

Comments
 (0)