Skip to content

Commit 1a3e23d

Browse files
author
Liora Milbaum
committed
feat: Initial support for httpx
1 parent eec6c02 commit 1a3e23d

8 files changed

+88
-20
lines changed

.pre-commit-config.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ repos:
2323
rev: v2.15.4
2424
hooks:
2525
- id: pylint
26-
additional_dependencies:
26+
additional_dependencies:
2727
- argcomplete==2.0.0
2828
- pytest==7.1.3
29+
- httpx==0.23.0
2930
- requests==2.28.1
3031
- requests-toolbelt==0.9.1
3132
files: 'gitlab/'
@@ -35,6 +36,7 @@ repos:
3536
- id: mypy
3637
args: []
3738
additional_dependencies:
39+
- httpx==0.23.0
3840
- types-PyYAML==6.0.12
3941
- types-requests==2.28.11.2
4042
- types-setuptools==64.0.1

gitlab/client.py

+34-14
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
"""Wrapper for the GitLab API."""
2+
from __future__ import annotations
23

34
import os
45
import re
6+
import sys
57
import time
68
from typing import Any, cast, Dict, List, Optional, Tuple, TYPE_CHECKING, Union
79
from urllib import parse
810

11+
import httpx
912
import requests
1013
import requests.utils
1114
from requests_toolbelt.multipart.encoder import MultipartEncoder # type: ignore
@@ -16,6 +19,14 @@
1619
import gitlab.exceptions
1720
from gitlab import utils
1821

22+
from .clients._httpxclient import _HttpxClient
23+
from .clients._requestsclient import _RequestsClient
24+
25+
if sys.version_info >= (3, 8):
26+
from typing import Literal
27+
else:
28+
from typing_extensions import Literal
29+
1930
REDIRECT_MSG = (
2031
"python-gitlab detected a {status_code} ({reason!r}) redirection. You must update "
2132
"your GitLab URL to the correct URL to avoid issues. The redirection was from: "
@@ -56,7 +67,7 @@ class Gitlab:
5667
"""
5768

5869
def __init__(
59-
self,
70+
self: Gitlab,
6071
url: Optional[str] = None,
6172
private_token: Optional[str] = None,
6273
oauth_token: Optional[str] = None,
@@ -66,7 +77,9 @@ def __init__(
6677
http_password: Optional[str] = None,
6778
timeout: Optional[float] = None,
6879
api_version: str = "4",
80+
http: Optional[Literal["requests", "httpx"]] = "requests",
6981
session: Optional[requests.Session] = None,
82+
client: Optional[httpx.Client] = None,
7083
per_page: Optional[int] = None,
7184
pagination: Optional[str] = None,
7285
order_by: Optional[str] = None,
@@ -75,7 +88,21 @@ def __init__(
7588
keep_base_url: bool = False,
7689
) -> None:
7790

91+
# We only support v4 API at this time
92+
if api_version not in ("4",):
93+
raise ModuleNotFoundError(f"gitlab.v{api_version}.objects")
94+
# NOTE: We must delay import of gitlab.v4.objects until now or
95+
# otherwise it will cause circular import errors
96+
from gitlab.v4 import objects
97+
7898
self._api_version = str(api_version)
99+
100+
if http == "requests":
101+
self._requests_client = _RequestsClient(session=session)
102+
self.session = self._requests_client.get_session
103+
elif http == "httpx":
104+
self._httpx_client = _HttpxClient(client=client)
105+
79106
self._server_version: Optional[str] = None
80107
self._server_revision: Optional[str] = None
81108
self._base_url = self._get_base_url(url)
@@ -97,20 +124,10 @@ def __init__(
97124
self.job_token = job_token
98125
self._set_auth_info()
99126

100-
#: Create a session object for requests
101-
self.session = session or requests.Session()
102-
103127
self.per_page = per_page
104128
self.pagination = pagination
105129
self.order_by = order_by
106130

107-
# We only support v4 API at this time
108-
if self._api_version not in ("4",):
109-
raise ModuleNotFoundError(f"gitlab.v{self._api_version}.objects")
110-
# NOTE: We must delay import of gitlab.v4.objects until now or
111-
# otherwise it will cause circular import errors
112-
from gitlab.v4 import objects
113-
114131
self._objects = objects
115132
self.user: Optional[objects.CurrentUser] = None
116133

@@ -189,11 +206,14 @@ def __init__(
189206
self.topics = objects.TopicManager(self)
190207
"""See :class:`~gitlab.v4.objects.TopicManager`"""
191208

192-
def __enter__(self) -> "Gitlab":
209+
def __enter__(self: Gitlab) -> Gitlab:
193210
return self
194211

195-
def __exit__(self, *args: Any) -> None:
196-
self.session.close()
212+
def __exit__(self: Gitlab, *args: Any) -> None:
213+
if self._requests_client:
214+
self._requests_client.close()
215+
elif self._httpx_client:
216+
self._httpx_client.close()
197217

198218
def __getstate__(self) -> Dict[str, Any]:
199219
state = self.__dict__.copy()

gitlab/clients/__init__.py

Whitespace-only changes.

gitlab/clients/_httpxclient.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from __future__ import annotations
2+
3+
from typing import Optional
4+
5+
import httpx
6+
7+
8+
class _HttpxClient:
9+
def __init__(
10+
self,
11+
client: Optional[httpx.Client] = None,
12+
) -> None:
13+
self._client = client or httpx.Client()
14+
15+
def __enter__(self: _HttpxClient) -> _HttpxClient:
16+
return self
17+
18+
def close(self: _HttpxClient) -> None:
19+
self._client.close()

gitlab/clients/_requestsclient.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from __future__ import annotations
2+
3+
from typing import Optional
4+
5+
import requests
6+
7+
8+
class _RequestsClient:
9+
def __init__(
10+
self,
11+
session: Optional[requests.Session] = None,
12+
) -> None:
13+
self._session = session or requests.Session()
14+
15+
@property
16+
def get_session(self: _RequestsClient) -> requests.Session:
17+
return self._session
18+
19+
def __enter__(self: _RequestsClient) -> _RequestsClient:
20+
return self
21+
22+
def close(self: _RequestsClient) -> None:
23+
self._session.close()

requirements.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
requests==2.28.1
1+
httpx==0.23.0
22
requests-toolbelt==0.10.0
3+
requests==2.28.1

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def get_version() -> str:
2828
license="LGPLv3",
2929
url="https://github.com/python-gitlab/python-gitlab",
3030
packages=find_packages(exclude=["docs*", "tests*"]),
31-
install_requires=["requests>=2.25.0", "requests-toolbelt>=0.9.1"],
31+
install_requires=["requests>=2.25.0", "requests-toolbelt>=0.9.1", "httpx==0.23.0"],
3232
package_data={
3333
"gitlab": ["py.typed"],
3434
},

tox.ini

+6-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ commands =
4343
[testenv:mypy]
4444
basepython = python3
4545
envdir={toxworkdir}/lint
46-
deps = -r{toxinidir}/requirements-lint.txt
46+
deps = -r requirements.txt
47+
-r requirements-lint.txt
4748
commands =
4849
mypy {posargs}
4950

@@ -57,7 +58,8 @@ commands =
5758
[testenv:pylint]
5859
basepython = python3
5960
envdir={toxworkdir}/lint
60-
deps = -r{toxinidir}/requirements-lint.txt
61+
deps = -r requirements.txt
62+
-r requirements-lint.txt
6163
commands =
6264
pylint {posargs} gitlab/
6365

@@ -121,7 +123,8 @@ commands =
121123
pytest --cov --cov-report xml tests/functional/api {posargs}
122124

123125
[testenv:smoke]
124-
deps = -r{toxinidir}/requirements-test.txt
126+
deps = -r requirements.txt
127+
-r requirements-test.txt
125128
commands = pytest tests/smoke {posargs}
126129

127130
[testenv:pre-commit]

0 commit comments

Comments
 (0)