8000 refactor(mixins): extract custom type transforms into utils · python-gitlab/python-gitlab@09b3b22 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 09b3b22

Browse files
nejchJohnVillalovos
authored andcommitted
refactor(mixins): extract custom type transforms into utils
1 parent 387a140 commit 09b3b22

File tree

3 files changed

+68
-46
lines changed

3 files changed

+68
-46
lines changed

gitlab/mixins.py

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import gitlab
3434
from gitlab import base, cli
3535
from gitlab import exceptions as exc
36-
from gitlab import types as g_types
3736
from gitlab import utils
3837

3938
__all__ = [
@@ -214,8 +213,8 @@ def list(self, **kwargs: Any) -> Union[base.RESTObjectList, List[base.RESTObject
214213
GitlabListError: If the server cannot perform the request
215214
"""
216215

217-
# Duplicate data to avoid messing with what the user sent us
218-
data = kwargs.copy()
216+
data, _ = utils._transform_types(kwargs, self._types, transform_files=False)
217+
219218
if self.gitlab.per_page:
220219
data.setdefault("per_page", self.gitlab.per_page)
221220

@@ -226,13 +225,6 @@ def list(self, **kwargs: Any) -> Union[base.RESTObjectList, List[base.RESTObject
226225
if self.gitlab.order_by:
227226
data.setdefault("order_by", self.gitlab.order_by)
228227

229-
# We get the attributes that need some special transformation
230-
if self._types:
231-
for attr_name, type_cls in self._types.items():
232-
if attr_name in data.keys():
233-
type_obj = type_cls(data[attr_name])
234-
data[attr_name] = type_obj.get_for_api()
235-
236228
# Allow to overwrite the path, handy for custom listings
237229
path = data.pop("path", self.path)
238230

@@ -298,23 +290,7 @@ def create(
298290
data = {}
299291

300292
self._check_missing_create_attrs(data)
301-
files = {}
302-
303-
# We get the attributes that need some special transformation
304-
if self._types:
305-
# Duplicate data to avoid messing with what the user sent us
306-
data = data.copy()
307-
for attr_name, type_cls in self._types.items():
308-
if attr_name in data.keys():
309-
type_obj = type_cls(data[attr_name])
310-
311-
# if the type if FileAttribute we need to pass the data as
312-
# file
313-
if isinstance(type_obj, g_types.FileAttribute):
314-
k = type_obj.get_file_name(attr_name)
315-
files[attr_name] = (k, data.pop(attr_name))
316-
else:
317-
data[attr_name] = type_obj.get_for_api()
293+
data, files = utils._transform_types(data, self._types)
318294

319295
# Handle specific URL for creation
320296
path = kwargs.pop("path", self.path)
@@ -394,23 +370,7 @@ def update(
394370
path = f"{self.path}/{utils.EncodedId(id)}"
395371

396372
self._check_missing_update_attrs(new_data)
397-
files = {}
398-
399-
# We get the attributes that need some special transformation
400-
if self._types:
401-
# Duplicate data to avoid messing with what the user sent us
402-
new_data = new_data.copy()
403-
for attr_name, type_cls in self._types.items():
404-
if attr_name in new_data.keys():
405-
type_obj = type_cls(new_data[attr_name])
406-
407-
# if the type if FileAttribute we need to pass the data as
408-
# file
409-
if isinstance(type_obj, g_types.FileAttribute):
410-
k = type_obj.get_file_name(attr_name)
411-
files[attr_name] = (k, new_data.pop(attr_name))
412-
else:
413-
new_data[attr_name] = type_obj.get_for_api()
373+
new_data, files = utils._transform_types(new_data, self._types)
414374

415375
http_method = self._get_update_method()
416376
result = http_method(path, post_data=new_data, files=files, **kwargs)

gitlab/utils.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
import traceback
2020
import urllib.parse
2121
import warnings
22-
from typing import Any, Callable, Dict, Optional, Type, Union
22+
from typing import Any, Callable, Dict, Optional, Tuple, Type, Union
2323

2424
import requests
2525

26+
from gitlab import types
27+
2628

2729
class _StdoutStream:
2830
def __call__(self, chunk: Any) -> None:
@@ -47,6 +49,39 @@ def response_content(
4749
return None
4850

4951

52+
def _transform_types(
53+
data: Dict[str, Any], custom_types: dict, *, transform_files: Optional[bool] = True
54+
) -> Tuple[dict, dict]:
55+
"""Copy the data dict with attributes that have custom types and transform them
56+
before being sent to the server.
57+
58+
If ``transform_files`` is ``True`` (default), also populates the ``files`` dict for
59+
FileAttribute types with tuples to prepare fields for requests' MultipartEncoder:
60+
https://toolbelt.readthedocs.io/en/latest/user.html#multipart-form-data-encoder
61+
62+
Returns:
63+
A tuple of the transformed data dict and files dict"""
64+
65+
# Duplicate data to avoid messing with what the user sent us
66+
data = data.copy()
67+
files = {}
68+
69+
for attr_name, type_cls in custom_types.items():
70+
if attr_name not in data:
71+
continue
72+
73+
type_obj = type_cls(data[attr_name])
74+
75+
# if the type if FileAttribute we need to pass the data as file
76+
if transform_files and isinstance(type_obj, types.FileAttribute):
77+
key = type_obj.get_file_name(attr_name)
78+
files[attr_name] = (key, data.pop(attr_name))
79+
else:
80+
data[attr_name] = type_obj.get_for_api()
81+
82+
return data, files
83+
84+
5085
def copy_dict(
5186
*,
5287
src: Dict[str, Any],

tests/unit/test_utils.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import json
1919
import warnings
2020

21-
from gitlab import utils
21+
from gitlab import types, utils
2222

2323

2424
class TestEncodedId:
@@ -95,3 +95,30 @@ def test_warn(self):
9595
assert warn_message in str(warning.message)
9696
assert __file__ in str(warning.message)
9797
assert warn_source == warning.source
98+
99+
100+
def test_transform_types_copies_data_with_empty_files():
101+
data = {"attr": "spam"}
102+
new_data, files = utils._transform_types(data, {})
103+
104+
assert new_data is not data
105+
assert new_data == data
106+
assert files == {}
107+
108+
109+
def test_transform_types_with_transform_files_populates_files():
110+
custom_types = {"attr": types.FileAttribute}
111+
data = {"attr": "spam"}
112+
new_data, files = utils._transform_types(data, custom_types)
113+
114+
assert new_data == {}
115+
assert files["attr"] == ("attr", "spam")
116+
117+
118+
def test_transform_types_without_transform_files_populates_data_with_empty_files():
119+
custom_types = {"attr": types.FileAttribute}
120+
data = {"attr": "spam"}
121+
new_data, files = utils._transform_types(data, custom_types, transform_files=False)
122+
123+
assert new_data == {"attr": "spam"}
124+
assert files == {}

0 commit comments

Comments
 (0)
0