Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit08ac071

Browse files
feat: addasdict() andto_json() methods to Gitlab Objects
Add an `asdict()` method that returns a dictionary representation copyof the Gitlab Object. This is a copy and changes made to it will haveno impact on the Gitlab Object.The `asdict()` method name was chosen as both the `dataclasses` and`attrs` libraries have an `asdict()` function which has the similarpurpose of creating a dictionary represenation of an object.Also add a `to_json()` method that returns a JSON stringrepresentation of the object.Closes:#1116
1 parente5affc8 commit08ac071

File tree

3 files changed

+129
-22
lines changed

3 files changed

+129
-22
lines changed

‎docs/api-usage.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,38 @@ the value on the object is accepted:
214214
issue.my_super_awesome_feature_flag="random_value"
215215
issue.save()
216216
217+
You can get a dictionary representation copy of the Gitlab Object. Modifications made to
218+
the dictionary will have no impact on the GitLab Object.
219+
220+
* `asdict()` method. Returns a dictionary representation of the Gitlab object.
221+
* `attributes` property. Returns a dictionary representation of the Gitlab
222+
object. Also returns any relevant parent object attributes.
223+
224+
..note::
225+
226+
`attributes` returns the parent object attributes that are defined in
227+
`object._from_parent_attrs`. What this can mean is that for example a `ProjectIssue`
228+
object will have a `project_id` key in the dictionary returned from `attributes` but
229+
`asdict()` will not.
230+
231+
232+
..code-block::python
233+
234+
project= gl.projects.get(1)
235+
project_dict= project.asdict()
236+
237+
# Or a dictionary representation also containing some of the parent attributes
238+
issue= project.issues.get(1)
239+
attribute_dict= issue.attributes
240+
241+
You can get a JSON string represenation of the Gitlab Object. For example:
242+
243+
..code-block::python
244+
245+
project= gl.projects.get(1)
246+
print(project.to_json())
247+
# Use arguments supported by `json.dump()`
248+
print(project.to_json(sort_keys=True,indent=4))
217249
218250
Base types
219251
==========

‎gitlab/base.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
importcopy
1919
importimportlib
20+
importjson
2021
importpprint
2122
importtextwrap
2223
fromtypesimportModuleType
@@ -143,15 +144,26 @@ def __getattr__(self, name: str) -> Any:
143144
def__setattr__(self,name:str,value:Any)->None:
144145
self.__dict__["_updated_attrs"][name]=value
145146

147+
defasdict(self,*,with_parent_attrs:bool=False)->Dict[str,Any]:
148+
data= {}
149+
ifwith_parent_attrs:
150+
data.update(copy.deepcopy(self._parent_attrs))
151+
data.update(copy.deepcopy(self._attrs))
152+
data.update(copy.deepcopy(self._updated_attrs))
153+
returndata
154+
155+
@property
156+
defattributes(self)->Dict[str,Any]:
157+
returnself.asdict(with_parent_attrs=True)
158+
159+
defto_json(self,*,with_parent_attrs:bool=False,**kwargs:Any)->str:
160+
returnjson.dumps(self.asdict(with_parent_attrs=with_parent_attrs),**kwargs)
161+
146162
def__str__(self)->str:
147-
data=self._attrs.copy()
148-
data.update(self._updated_attrs)
149-
returnf"{type(self)} =>{data}"
163+
returnf"{type(self)} =>{self.asdict()}"
150164

151165
defpformat(self)->str:
152-
data=self._attrs.copy()
153-
data.update(self._updated_attrs)
154-
returnf"{type(self)} =>\n{pprint.pformat(data)}"
166+
returnf"{type(self)} =>\n{pprint.pformat(self.asdict())}"
155167

156168
defpprint(self)->None:
157169
print(self.pformat())
@@ -242,14 +254,6 @@ def encoded_id(self) -> Optional[Union[int, str]]:
242254
obj_id=gitlab.utils.EncodedId(obj_id)
243255
returnobj_id
244256

245-
@property
246-
defattributes(self)->Dict[str,Any]:
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-
returndata
252-
253257

254258
classRESTObjectList:
255259
"""Generator object representing a list of RESTObject's.

‎tests/unit/test_base.py

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ class FakeManager(base.RESTManager):
3636
_path="/tests"
3737

3838

39+
classFakeParent:
40+
id=42
41+
42+
43+
classFakeManagerWithParent(base.RESTManager):
44+
_path="/tests/{test_id}/cases"
45+
_obj_cls=FakeObject
46+
_from_parent_attrs= {"test_id":"id"}
47+
48+
3949
@pytest.fixture
4050
deffake_gitlab():
4151
returnFakeGitlab()
@@ -46,9 +56,19 @@ def fake_manager(fake_gitlab):
4656
returnFakeManager(fake_gitlab)
4757

4858

59+
@pytest.fixture
60+
deffake_manager_with_parent(fake_gitlab):
61+
returnFakeManagerWithParent(fake_gitlab,parent=FakeParent)
62+
63+
4964
@pytest.fixture
5065
deffake_object(fake_manager):
51-
returnFakeObject(fake_manager, {"attr1": [1,2,3]})
66+
returnFakeObject(fake_manager, {"attr1":"foo","alist": [1,2,3]})
67+
68+
69+
@pytest.fixture
70+
deffake_object_with_parent(fake_manager_with_parent):
71+
returnFakeObject(fake_manager_with_parent, {"attr1":"foo","alist": [1,2,3]})
5272

5373

5474
classTestRESTManager:
@@ -313,22 +333,73 @@ def test_repr(self, fake_manager):
313333
assertrepr(obj)=="<FakeObject>"
314334

315335
deftest_attributes_get(self,fake_object):
316-
assertfake_object.attr1==[1,2,3]
336+
assertfake_object.attr1=="foo"
317337
result=fake_object.attributes
318-
assertresult== {"attr1": [1,2,3]}
338+
assertresult== {"attr1":"foo","alist":[1,2,3]}
319339

320340
deftest_attributes_shows_updates(self,fake_object):
321341
# Updated attribute value is reflected in `attributes`
322342
fake_object.attr1="hello"
323-
assertfake_object.attributes== {"attr1":"hello"}
343+
assertfake_object.attributes== {"attr1":"hello","alist": [1,2,3]}
324344
assertfake_object.attr1=="hello"
325345
# New attribute is in `attributes`
326346
fake_object.new_attrib="spam"
327-
assertfake_object.attributes== {"attr1":"hello","new_attrib":"spam"}
347+
assertfake_object.attributes== {
348+
"attr1":"hello",
349+
"new_attrib":"spam",
350+
"alist": [1,2,3],
351+
}
328352

329353
deftest_attributes_is_copy(self,fake_object):
330354
# Modifying the dictionary does not cause modifications to the object
331355
result=fake_object.attributes
332-
result["attr1"].append(10)
333-
assertresult== {"attr1": [1,2,3,10]}
334-
assertfake_object.attributes== {"attr1": [1,2,3]}
356+
result["alist"].append(10)
357+
assertresult== {"attr1":"foo","alist": [1,2,3,10]}
358+
assertfake_object.attributes== {"attr1":"foo","alist": [1,2,3]}
359+
360+
deftest_attributes_has_parent_attrs(self,fake_object_with_parent):
361+
assertfake_object_with_parent.attr1=="foo"
362+
result=fake_object_with_parent.attributes
363+
assertresult== {"attr1":"foo","alist": [1,2,3],"test_id":"42"}
364+
365+
deftest_asdict(self,fake_object):
366+
assertfake_object.attr1=="foo"
367+
result=fake_object.asdict()
368+
assertresult== {"attr1":"foo","alist": [1,2,3]}
369+
370+
deftest_asdict_no_parent_attrs(self,fake_object_with_parent):
371+
assertfake_object_with_parent.attr1=="foo"
372+
result=fake_object_with_parent.asdict()
373+
assertresult== {"attr1":"foo","alist": [1,2,3]}
374+
assert"test_id"notinfake_object_with_parent.asdict()
375+
assert"test_id"notinfake_object_with_parent.asdict(with_parent_attrs=False)
376+
assert"test_id"infake_object_with_parent.asdict(with_parent_attrs=True)
377+
378+
deftest_asdict_modify_dict_does_not_change_object(self,fake_object):
379+
result=fake_object.asdict()
380+
# Demonstrate modifying the dictionary does not modify the object
381+
result["attr1"]="testing"
382+
result["alist"].append(4)
383+
assertresult== {"attr1":"testing","alist": [1,2,3,4]}
384+
assertfake_object.attr1=="foo"
385+
assertfake_object.alist== [1,2,3]
386+
387+
deftest_asdict_modify_dict_does_not_change_object2(self,fake_object):
388+
# Modify attribute and then ensure modifying a list in the returned dict won't
389+
# modify the list in the object.
390+
fake_object.attr1= [9,7,8]
391+
assertfake_object.asdict()== {
392+
"attr1": [9,7,8],
393+
"alist": [1,2,3],
394+
}
395+
result=fake_object.asdict()
396+
result["attr1"].append(1)
397+
assertfake_object.asdict()== {
398+
"attr1": [9,7,8],
399+
"alist": [1,2,3],
400+
}
401+
402+
deftest_asdict_modify_object(self,fake_object):
403+
# asdict() returns the updated value
404+
fake_object.attr1="spam"
405+
assertfake_object.asdict()== {"attr1":"spam","alist": [1,2,3]}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp