Skip to content

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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy