summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn L. Villalovos <john@sodarock.com>2023-03-04 14:45:24 -0800
committerNejc Habjan <hab.nejc@gmail.com>2023-03-12 11:11:49 +0100
commitf2b5e4fa375e88d6102a8d023ae2fe8206042545 (patch)
treea0e2f4667d6dc5fe76353c2c36ff7c4b689b707a
parentd387d91401fdf933b1832ea2593614ea6b7d8acf (diff)
downloadgitlab-f2b5e4fa375e88d6102a8d023ae2fe8206042545.tar.gz
chore: use a dataclass to return values from `prepare_send_data`
I found the tuple of three values confusing. So instead use a dataclass to return the three values. It is still confusing but a little bit less so. Also add some unit tests
-rw-r--r--gitlab/_backends/requests_backend.py29
-rw-r--r--gitlab/client.py10
-rw-r--r--tests/unit/_backends/__init__.py0
-rw-r--r--tests/unit/_backends/test_requests_backend.py38
4 files changed, 62 insertions, 15 deletions
diff --git a/gitlab/_backends/requests_backend.py b/gitlab/_backends/requests_backend.py
index fd40baa..d70cf42 100644
--- a/gitlab/_backends/requests_backend.py
+++ b/gitlab/_backends/requests_backend.py
@@ -1,6 +1,7 @@
from __future__ import annotations
-from typing import Any, Dict, Optional, Tuple, TYPE_CHECKING, Union
+import dataclasses
+from typing import Any, Dict, Optional, TYPE_CHECKING, Union
import requests
from requests.structures import CaseInsensitiveDict
@@ -9,6 +10,20 @@ from requests_toolbelt.multipart.encoder import MultipartEncoder # type: ignore
from . import protocol
+@dataclasses.dataclass
+class SendData:
+ content_type: str
+ data: Optional[Union[Dict[str, Any], MultipartEncoder]] = None
+ json: Optional[Union[Dict[str, Any], bytes]] = None
+
+ def __post_init__(self) -> None:
+ if self.json is not None and self.data is not None:
+ raise ValueError(
+ f"`json` and `data` are mutually exclusive. Only one can be set. "
+ f"json={self.json!r} data={self.data!r}"
+ )
+
+
class RequestsResponse(protocol.BackendResponse):
def __init__(self, response: requests.Response) -> None:
self._response: requests.Response = response
@@ -50,11 +65,7 @@ class RequestsBackend(protocol.Backend):
files: Optional[Dict[str, Any]] = None,
post_data: Optional[Union[Dict[str, Any], bytes]] = None,
raw: bool = False,
- ) -> Tuple[
- Optional[Union[Dict[str, Any], bytes]],
- Optional[Union[Dict[str, Any], MultipartEncoder]],
- str,
- ]:
+ ) -> SendData:
if files:
if post_data is None:
post_data = {}
@@ -70,12 +81,12 @@ class RequestsBackend(protocol.Backend):
post_data["avatar"] = files.get("avatar")
data = MultipartEncoder(post_data)
- return (None, data, data.content_type)
+ return SendData(data=data, content_type=data.content_type)
if raw and post_data:
- return (None, post_data, "application/octet-stream")
+ return SendData(data=post_data, content_type="application/octet-stream")
- return (post_data, None, "application/json")
+ return SendData(json=post_data, content_type="application/json")
def http_request(
self,
diff --git a/gitlab/client.py b/gitlab/client.py
index c3982f3..495ed44 100644
--- a/gitlab/client.py
+++ b/gitlab/client.py
@@ -716,10 +716,8 @@ class Gitlab:
retry_transient_errors = self.retry_transient_errors
# We need to deal with json vs. data when uploading files
- json, data, content_type = self._backend.prepare_send_data(
- files, post_data, raw
- )
- opts["headers"]["Content-type"] = content_type
+ send_data = self._backend.prepare_send_data(files, post_data, raw)
+ opts["headers"]["Content-type"] = send_data.content_type
cur_retries = 0
while True:
@@ -727,8 +725,8 @@ class Gitlab:
result = self._backend.http_request(
method=verb,
url=url,
- json=json,
- data=data,
+ json=send_data.json,
+ data=send_data.data,
params=params,
timeout=timeout,
verify=verify,
diff --git a/tests/unit/_backends/__init__.py b/tests/unit/_backends/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/unit/_backends/__init__.py
diff --git a/tests/unit/_backends/test_requests_backend.py b/tests/unit/_backends/test_requests_backend.py
new file mode 100644
index 0000000..d83703d
--- /dev/null
+++ b/tests/unit/_backends/test_requests_backend.py
@@ -0,0 +1,38 @@
+import pytest
+from requests_toolbelt.multipart.encoder import MultipartEncoder # type: ignore
+
+from gitlab._backends import requests_backend
+
+
+class TestSendData:
+ def test_senddata_json(self) -> None:
+ result = requests_backend.SendData(
+ json={"a": 1}, content_type="application/json"
+ )
+ assert result.data is None
+
+ def test_senddata_data(self) -> None:
+ result = requests_backend.SendData(
+ data={"b": 2}, content_type="application/octet-stream"
+ )
+ assert result.json is None
+
+ def test_senddata_json_and_data(self) -> None:
+ with pytest.raises(ValueError, match=r"json={'a': 1} data={'b': 2}"):
+ requests_backend.SendData(
+ json={"a": 1}, data={"b": 2}, content_type="application/json"
+ )
+
+
+class TestRequestsBackend:
+ def test_prepare_send_data_str_parentid(self) -> None:
+ file = "12345"
+ files = {"file": ("file.tar.gz", file, "application/octet-stream")}
+ post_data = {"parent_id": "12"}
+
+ result = requests_backend.RequestsBackend.prepare_send_data(
+ files=files, post_data=post_data, raw=False
+ )
+ assert result.json is None
+ assert result.content_type.startswith("multipart/form-data")
+ assert isinstance(result.data, MultipartEncoder)