Skip to content

Commit e5affc8

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 f6b6e18 commit e5affc8

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

gitlab/base.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# You should have received a copy of the GNU Lesser General Public License
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

18+
import copy
1819
import importlib
1920
import pprint
2021
import textwrap
@@ -243,10 +244,11 @@ def encoded_id(self) -> Optional[Union[int, str]]:
243244

244245
@property
245246
def attributes(self) -> Dict[str, Any]:
246-
d = self.__dict__["_updated_attrs"].copy()
247-
d.update(self.__dict__["_attrs"])
248-
d.update(self.__dict__["_parent_attrs"])
249-
return d
247+
data = {}
248+
data.update(copy.deepcopy(self._parent_attrs))
249+
data.update(copy.deepcopy(self._attrs))
250+
data.update(copy.deepcopy(self._updated_attrs))
251+
return data
250252

251253

252254
class RESTObjectList:

tests/unit/test_base.py

+26
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ def fake_manager(fake_gitlab):
4646
return FakeManager(fake_gitlab)
4747

4848

49+
@pytest.fixture
50+
def fake_object(fake_manager):
51+
return FakeObject(fake_manager, {"attr1": [1, 2, 3]})
52+
53+
4954
class TestRESTManager:
5055
def test_computed_path_simple(self):
5156
class MGR(base.RESTManager):
@@ -306,3 +311,24 @@ def test_repr(self, fake_manager):
306311

307312
FakeObject._id_attr = None
308313
assert repr(obj) == "<FakeObject>"
314+
315+
def test_attributes_get(self, fake_object):
316+
assert fake_object.attr1 == [1, 2, 3]
317+
result = fake_object.attributes
318+
assert result == {"attr1": [1, 2, 3]}
319+
320+
def test_attributes_shows_updates(self, fake_object):
321+
# Updated attribute value is reflected in `attributes`
322+
fake_object.attr1 = "hello"
323+
assert fake_object.attributes == {"attr1": "hello"}
324+
assert fake_object.attr1 == "hello"
325+
# New attribute is in `attributes`
326+
fake_object.new_attrib = "spam"
327+
assert fake_object.attributes == {"attr1": "hello", "new_attrib": "spam"}
328+
329+
def test_attributes_is_copy(self, fake_object):
330+
# Modifying the dictionary does not cause modifications to the object
331+
result = fake_object.attributes
332+
result["attr1"].append(10)
333+
assert result == {"attr1": [1, 2, 3, 10]}
334+
assert fake_object.attributes == {"attr1": [1, 2, 3]}

0 commit comments

Comments
 (0)