From 722312eb23e8d46d97c396ea4689f846a4a33f32 Mon Sep 17 00:00:00 2001
From: Liora Milbaum <liora@lmb.co.il>
Date: Mon, 26 Dec 2022 06:39:58 +0200
Subject: [PATCH] feat: protocol backend classes to indentify breaking api
 changes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

PEP 544 – Protocols: Structural subtyping (static duck typing)
---
 gitlab/_backends/protocol.py         | 34 ++++++++++++++++++++++++++++
 gitlab/_backends/requests_backend.py |  6 +++--
 2 files changed, 38 insertions(+), 2 deletions(-)
 create mode 100644 gitlab/_backends/protocol.py

diff --git a/gitlab/_backends/protocol.py b/gitlab/_backends/protocol.py
new file mode 100644
index 000000000..f89740b25
--- /dev/null
+++ b/gitlab/_backends/protocol.py
@@ -0,0 +1,34 @@
+import abc
+import sys
+from typing import Any, Dict, Optional, Union
+
+import requests
+from requests_toolbelt.multipart.encoder import MultipartEncoder  # type: ignore
+
+if sys.version_info >= (3, 8):
+    from typing import Protocol
+else:
+    from typing_extensions import Protocol
+
+
+class BackendResponse(Protocol):
+    @abc.abstractmethod
+    def __init__(self, response: requests.Response) -> None:
+        ...
+
+
+class Backend(Protocol):
+    @abc.abstractmethod
+    def http_request(
+        self,
+        method: str,
+        url: str,
+        json: Optional[Union[Dict[str, Any], bytes]],
+        data: Optional[Union[Dict[str, Any], MultipartEncoder]],
+        params: Optional[Any],
+        timeout: Optional[float],
+        verify: Optional[Union[bool, str]],
+        stream: Optional[bool],
+        **kwargs: Any,
+    ) -> BackendResponse:
+        ...
diff --git a/gitlab/_backends/requests_backend.py b/gitlab/_backends/requests_backend.py
index 4ea23a7ba..fd40baa64 100644
--- a/gitlab/_backends/requests_backend.py
+++ b/gitlab/_backends/requests_backend.py
@@ -6,8 +6,10 @@
 from requests.structures import CaseInsensitiveDict
 from requests_toolbelt.multipart.encoder import MultipartEncoder  # type: ignore
 
+from . import protocol
 
-class RequestsResponse:
+
+class RequestsResponse(protocol.BackendResponse):
     def __init__(self, response: requests.Response) -> None:
         self._response: requests.Response = response
 
@@ -35,7 +37,7 @@ def json(self) -> Any:
         return self._response.json()
 
 
-class RequestsBackend:
+class RequestsBackend(protocol.Backend):
     def __init__(self, session: Optional[requests.Session] = None) -> None:
         self._client: requests.Session = session or requests.Session()