diff --git a/.gitignore b/.gitignore index c480c1306..a78530840 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ docs/_build .tox venv/ tags +.venv/ diff --git a/gitlab/client.py b/gitlab/client.py index 9312b30d8..5c89d6e7a 100644 --- a/gitlab/client.py +++ b/gitlab/client.py @@ -21,13 +21,18 @@ import time from typing import Union -import httpx - import gitlab import gitlab.config +import httpx from gitlab import exceptions as exc from gitlab import utils -from gitlab.exceptions import GitlabHttpError, GitlabParsingError, on_http_error +from gitlab.exceptions import ( + GitlabAuthenticationError, + GitlabHttpError, + GitlabParsingError, + RedirectError, + on_http_error, +) from gitlab.types import GitlabList from gitlab.utils import inherit_docstrings @@ -159,7 +164,7 @@ def _get_client(self) -> httpx.AsyncClient: auth = None if self.http_username: - auth = httpx.auth.BasicAuth(self.http_username, self.http_password) + auth = httpx.BasicAuth(self.http_username, self.http_password) return self._httpx_client_class( auth=auth, verify=self.ssl_verify, timeout=self.timeout, diff --git a/gitlab/tests/objects/test_application.py b/gitlab/tests/objects/test_application.py index 1b027bafa..eef68259c 100644 --- a/gitlab/tests/objects/test_application.py +++ b/gitlab/tests/objects/test_application.py @@ -2,9 +2,8 @@ import pytest import respx -from httpx.status_codes import StatusCode - from gitlab import AsyncGitlab +from httpx import codes class TestApplicationAppearance: @@ -31,7 +30,7 @@ async def test_get_update_appearance(self, gl, gl_get_value, is_gl_sync): "message_font_color": "#ffffff", "email_header_and_footer_enabled": False, }, - status_code=StatusCode.OK, + status_code=codes.OK, ) request_update_appearance = respx.put( "http://localhost/api/v4/application/appearance", @@ -48,7 +47,7 @@ async def test_get_update_appearance(self, gl, gl_get_value, is_gl_sync): "message_font_color": "#ffffff", "email_header_and_footer_enabled": False, }, - status_code=StatusCode.OK, + status_code=codes.OK, ) appearance = gl.appearance.get() @@ -86,7 +85,7 @@ async def test_update_appearance(self, gl, is_gl_sync): "message_font_color": "#ffffff", "email_header_and_footer_enabled": False, }, - status_code=StatusCode.OK, + status_code=codes.OK, ) if is_gl_sync: diff --git a/gitlab/tests/objects/test_projects.py b/gitlab/tests/objects/test_projects.py index e3a846846..a970cd42e 100644 --- a/gitlab/tests/objects/test_projects.py +++ b/gitlab/tests/objects/test_projects.py @@ -1,8 +1,7 @@ import pytest import respx -from httpx.status_codes import StatusCode - from gitlab import AsyncGitlab +from httpx import codes class TestProjectSnippets: @@ -22,7 +21,7 @@ async def test_list_project_snippets(self, gl, gl_get_value): "visibility": visibility, } ], - status_code=StatusCode.OK, + status_code=codes.OK, ) project = gl.projects.get(1, lazy=True) @@ -47,7 +46,7 @@ async def test_get_project_snippet(self, gl, gl_get_value): "content": "source code with multiple lines", "visibility": visibility, }, - status_code=StatusCode.OK, + status_code=codes.OK, ) project = gl.projects.get(1, lazy=True) @@ -71,7 +70,7 @@ async def test_create_update_project_snippets(self, gl, gl_get_value, is_gl_sync "content": "source code with multiple lines", "visibility": visibility, }, - status_code=StatusCode.OK, + status_code=codes.OK, ) request_create = respx.post( @@ -83,7 +82,7 @@ async def test_create_update_project_snippets(self, gl, gl_get_value, is_gl_sync "content": "source code with multiple lines", "visibility": visibility, }, - status_code=StatusCode.OK, + status_code=codes.OK, ) project = gl.projects.get(1, lazy=True) diff --git a/gitlab/tests/test_async_mixins.py b/gitlab/tests/test_async_mixins.py index fe013cea3..cc5876182 100644 --- a/gitlab/tests/test_async_mixins.py +++ b/gitlab/tests/test_async_mixins.py @@ -1,7 +1,5 @@ import pytest import respx -from httpx.status_codes import StatusCode - from gitlab import AsyncGitlab from gitlab.base import RESTObject, RESTObjectList from gitlab.mixins import ( @@ -15,6 +13,7 @@ SetMixin, UpdateMixin, ) +from httpx import codes from .test_mixins import FakeManager, FakeObject @@ -36,7 +35,7 @@ class M(GetMixin, FakeManager): "http://localhost/api/v4/tests/42", headers={"Content-Type": "application/json"}, content={"id": 42, "foo": "bar"}, - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) obj = await mgr.get(42) @@ -54,7 +53,7 @@ class O(RefreshMixin, FakeObject): "http://localhost/api/v4/tests/42", headers={"Content-Type": "application/json"}, content={"id": 42, "foo": "bar"}, - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = FakeManager(gl) obj = O(mgr, {"id": 42}) @@ -73,7 +72,7 @@ class M(GetWithoutIdMixin, FakeManager): "http://localhost/api/v4/tests", headers={"Content-Type": "application/json"}, content='{"foo": "bar"}', - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) @@ -92,7 +91,7 @@ class M(ListMixin, FakeManager): "http://localhost/api/v4/tests", headers={"Content-Type": "application/json"}, content='[{"id": 42, "foo": "bar"},{"id": 43, "foo": "baz"}]', - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) @@ -119,7 +118,7 @@ class M(ListMixin, FakeManager): "http://localhost/api/v4/others", headers={"Content-Type": "application/json"}, content='[{"id": 42, "foo": "bar"}]', - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) @@ -142,7 +141,7 @@ class M(CreateMixin, FakeManager): "http://localhost/api/v4/tests", headers={"Content-Type": "application/json"}, content='{"id": 42, "foo": "bar"}', - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) @@ -162,7 +161,7 @@ class M(CreateMixin, FakeManager): "http://localhost/api/v4/others", headers={"Content-Type": "application/json"}, content='{"id": 42, "foo": "bar"}', - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) @@ -182,7 +181,7 @@ class M(UpdateMixin, FakeManager): "http://localhost/api/v4/tests/42", headers={"Content-Type": "application/json"}, content='{"id": 42, "foo": "baz"}', - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) @@ -202,7 +201,7 @@ class M(UpdateMixin, FakeManager): "http://localhost/api/v4/tests", headers={"Content-Type": "application/json"}, content='{"foo": "baz"}', - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) server_data = await mgr.update(new_data={"foo": "baz"}) @@ -219,7 +218,7 @@ class M(DeleteMixin, FakeManager): "http://localhost/api/v4/tests/42", headers={"Content-Type": "application/json"}, content="", - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) @@ -238,7 +237,7 @@ class O(SaveMixin, RESTObject): "http://localhost/api/v4/tests/42", headers={"Content-Type": "application/json"}, content='{"id": 42, "foo": "baz"}', - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) @@ -258,7 +257,7 @@ class M(SetMixin, FakeManager): "http://localhost/api/v4/tests/foo", headers={"Content-Type": "application/json"}, content='{"key": "foo", "value": "bar"}', - status_code=StatusCode.OK, + status_code=codes.OK, ) mgr = M(gl) diff --git a/gitlab/tests/test_gitlab.py b/gitlab/tests/test_gitlab.py index 2a659c830..5046790b1 100644 --- a/gitlab/tests/test_gitlab.py +++ b/gitlab/tests/test_gitlab.py @@ -23,8 +23,6 @@ import httpx import pytest import respx -from httpx.status_codes import StatusCode - from gitlab import AsyncGitlab, Gitlab from gitlab import exceptions as exc from gitlab.client import _sanitize @@ -41,6 +39,7 @@ User, UserStatus, ) +from httpx import codes valid_config = b"""[global] default = one @@ -144,7 +143,7 @@ def test_http_auth(self, gitlab_class): assert gl.private_token == "private_token" assert gl.oauth_token is None assert gl.job_token is None - assert isinstance(gl.client.auth, httpx.auth.BasicAuth) + assert isinstance(gl.client.auth, httpx.BasicAuth) assert gl.headers["PRIVATE-TOKEN"] == "private_token" assert "Authorization" not in gl.headers @@ -167,7 +166,7 @@ async def test_build_list(self, gl, gl_get_value, is_gl_sync): ), }, content=[{"a": "b"}], - status_code=StatusCode.OK, + status_code=codes.OK, ) request_2 = respx.get( "http://localhost/api/v4/tests?per_page=1&page=2", @@ -180,7 +179,7 @@ async def test_build_list(self, gl, gl_get_value, is_gl_sync): "X-Total": "2", }, content=[{"c": "d"}], - status_code=StatusCode.OK, + status_code=codes.OK, ) obj = gl.http_list("/tests", as_list=False) obj = await gl_get_value(obj) @@ -217,7 +216,7 @@ async def test_all_ommited_when_as_list(self, gl, gl_get_value): "X-Total": "2", }, content=[{"c": "d"}], - status_code=StatusCode.OK, + status_code=codes.OK, ) result = gl.http_list("/tests", as_list=False, all=True) @@ -242,14 +241,14 @@ async def test_http_request(self, gl, gl_get_value): "http://localhost/api/v4/projects", headers={"content-type": "application/json"}, content=[{"name": "project1"}], - status_code=StatusCode.OK, + status_code=codes.OK, ) http_r = gl.http_request("get", "/projects") http_r = await gl_get_value(http_r) http_r.json() - assert http_r.status_code == StatusCode.OK + assert http_r.status_code == codes.OK @respx.mock @pytest.mark.asyncio @@ -258,7 +257,7 @@ async def test_get_request(self, gl, gl_get_value): "http://localhost/api/v4/projects", headers={"content-type": "application/json"}, content={"name": "project1"}, - status_code=StatusCode.OK, + status_code=codes.OK, ) result = gl.http_get("/projects") @@ -274,7 +273,7 @@ async def test_get_request_raw(self, gl, gl_get_value): "http://localhost/api/v4/projects", headers={"content-type": "application/octet-stream"}, content="content", - status_code=StatusCode.OK, + status_code=codes.OK, ) result = gl.http_get("/projects") @@ -290,7 +289,7 @@ async def test_get_request_raw(self, gl, gl_get_value): { "url": "http://localhost/api/v4/not_there", "content": "Here is why it failed", - "status_code": StatusCode.NOT_FOUND, + "status_code": codes.NOT_FOUND, }, exc.GitlabHttpError, "/not_there", @@ -300,7 +299,7 @@ async def test_get_request_raw(self, gl, gl_get_value): "url": "http://localhost/api/v4/projects", "headers": {"content-type": "application/json"}, "content": '["name": "project1"]', - "status_code": StatusCode.OK, + "status_code": codes.OK, }, exc.GitlabParsingError, "/projects", @@ -335,7 +334,7 @@ async def test_list_request(self, gl, gl_get_value): "http://localhost/api/v4/projects", headers={"content-type": "application/json", "X-Total": "1"}, content=[{"name": "project1"}], - status_code=StatusCode.OK, + status_code=codes.OK, ) result = gl.http_list("/projects", as_list=True) @@ -360,7 +359,7 @@ async def test_post_request(self, gl, gl_get_value): "http://localhost/api/v4/projects", headers={"content-type": "application/json"}, content={"name": "project1"}, - status_code=StatusCode.OK, + status_code=codes.OK, ) result = gl.http_post("/projects") @@ -376,7 +375,7 @@ async def test_put_request(self, gl, gl_get_value): "http://localhost/api/v4/projects", headers={"content-type": "application/json"}, content='{"name": "project1"}', - status_code=StatusCode.OK, + status_code=codes.OK, ) result = gl.http_put("/projects") result = await gl_get_value(result) @@ -391,7 +390,7 @@ async def test_delete_request(self, gl, gl_get_value): "http://localhost/api/v4/projects", headers={"content-type": "application/json"}, content="true", - status_code=StatusCode.OK, + status_code=codes.OK, ) result = gl.http_delete("/projects") @@ -406,7 +405,7 @@ async def test_delete_request_404(self, gl, is_gl_sync): result = respx.delete( "http://localhost/api/v4/not_there", content="Here is why it failed", - status_code=StatusCode.NOT_FOUND, + status_code=codes.NOT_FOUND, ) with pytest.raises(exc.GitlabHttpError): @@ -444,7 +443,7 @@ async def test_token_auth(self, gl, is_gl_sync): content='{{"id": {0:d}, "username": "{1:s}"}}'.format(id_, name).encode( "utf-8" ), - status_code=StatusCode.OK, + status_code=codes.OK, ) if is_gl_sync: @@ -462,7 +461,7 @@ async def test_hooks(self, gl, gl_get_value): "http://localhost/api/v4/hooks/1", headers={"content-type": "application/json"}, content='{"url": "testurl", "id": 1}'.encode("utf-8"), - status_code=StatusCode.OK, + status_code=codes.OK, ) data = gl.hooks.get(1) @@ -479,7 +478,7 @@ async def test_projects(self, gl, gl_get_value): "http://localhost/api/v4/projects/1", headers={"content-type": "application/json"}, content='{"name": "name", "id": 1}'.encode("utf-8"), - status_code=StatusCode.OK, + status_code=codes.OK, ) data = gl.projects.get(1) @@ -495,7 +494,7 @@ async def test_project_environments(self, gl, gl_get_value): "http://localhost/api/v4/projects/1", headers={"content-type": "application/json"}, content='{"name": "name", "id": 1}'.encode("utf-8"), - status_code=StatusCode.OK, + status_code=codes.OK, ) request_get_environment = respx.get( "http://localhost/api/v4/projects/1/environments/1", @@ -503,7 +502,7 @@ async def test_project_environments(self, gl, gl_get_value): content='{"name": "environment_name", "id": 1, "last_deployment": "sometime"}'.encode( "utf-8" ), - status_code=StatusCode.OK, + status_code=codes.OK, ) project = gl.projects.get(1) @@ -523,7 +522,7 @@ async def test_project_additional_statistics(self, gl, gl_get_value): "http://localhost/api/v4/projects/1", headers={"content-type": "application/json"}, content='{"name": "name", "id": 1}'.encode("utf-8"), - status_code=StatusCode.OK, + status_code=codes.OK, ) request_get_environment = respx.get( "http://localhost/api/v4/projects/1/statistics", @@ -531,7 +530,7 @@ async def test_project_additional_statistics(self, gl, gl_get_value): content="""{"fetches": {"total": 50, "days": [{"count": 10, "date": "2018-01-10"}]}}""".encode( "utf-8" ), - status_code=StatusCode.OK, + status_code=codes.OK, ) project = gl.projects.get(1) project = await gl_get_value(project) @@ -547,7 +546,7 @@ async def test_project_issues_statistics(self, gl, gl_get_value): "http://localhost/api/v4/projects/1", headers={"content-type": "application/json"}, content='{"name": "name", "id": 1}'.encode("utf-8"), - status_code=StatusCode.OK, + status_code=codes.OK, ) request_get_environment = respx.get( "http://localhost/api/v4/projects/1/issues_statistics", @@ -555,7 +554,7 @@ async def test_project_issues_statistics(self, gl, gl_get_value): content="""{"statistics": {"counts": {"all": 20, "closed": 5, "opened": 15}}}""".encode( "utf-8" ), - status_code=StatusCode.OK, + status_code=codes.OK, ) project = gl.projects.get(1) @@ -573,7 +572,7 @@ async def test_groups(self, gl, gl_get_value): "http://localhost/api/v4/groups/1", headers={"content-type": "application/json"}, content='{"name": "name", "id": 1, "path": "path"}'.encode("utf-8"), - status_code=StatusCode.OK, + status_code=codes.OK, ) data = gl.groups.get(1) @@ -591,7 +590,7 @@ async def test_issues(self, gl, gl_get_value): headers={"content-type": "application/json"}, content='[{"name": "name", "id": 1}, ' '{"name": "other_name", "id": 2}]'.encode("utf-8"), - status_code=StatusCode.OK, + status_code=codes.OK, ) data = gl.issues.list() @@ -608,7 +607,7 @@ def respx_get_user_params(self): '{"name": "name", "id": 1, "password": "password", ' '"username": "username", "email": "email"}'.encode("utf-8") ), - "status_code": StatusCode.OK, + "status_code": codes.OK, } @respx.mock @@ -632,7 +631,7 @@ async def test_user_status(self, gl, gl_get_value, respx_get_user_params): content='{"message": "test", "message_html": "

Message

", "emoji": "thumbsup"}'.encode( "utf-8" ), - status_code=StatusCode.OK, + status_code=codes.OK, ) request_user = respx.get(**respx_get_user_params) @@ -657,13 +656,13 @@ async def test_todo(self, gl, gl_get_value, is_gl_sync): "http://localhost/api/v4/todos", headers={"content-type": "application/json"}, content=encoded_content, - status_code=StatusCode.OK, + status_code=codes.OK, ) request_mark_as_done = respx.post( "http://localhost/api/v4/todos/102/mark_as_done", headers={"content-type": "application/json"}, content=json.dumps(json_content[0]).encode("utf-8"), - status_code=StatusCode.OK, + status_code=codes.OK, ) todo_list = gl.todos.list() @@ -703,7 +702,7 @@ async def test_deployment(self, gl, gl_get_value, is_gl_sync): "http://localhost/api/v4/projects/1/deployments", headers={"content-type": "application/json"}, content=json_content, - status_code=StatusCode.OK, + status_code=codes.OK, ) project = gl.projects.get(1, lazy=True) @@ -726,7 +725,7 @@ async def test_deployment(self, gl, gl_get_value, is_gl_sync): "http://localhost/api/v4/projects/1/deployments/42", headers={"content-type": "application/json"}, content=json_content, - status_code=StatusCode.OK, + status_code=codes.OK, ) deployment.status = "failed" @@ -744,13 +743,13 @@ async def test_user_activate_deactivate(self, gl, is_gl_sync): "http://localhost/api/v4/users/1/activate", headers={"content-type": "application/json"}, content={}, - status_code=StatusCode.CREATED, + status_code=codes.CREATED, ) request_deactivate = respx.post( "http://localhost/api/v4/users/1/deactivate", headers={"content-type": "application/json"}, content={}, - status_code=StatusCode.CREATED, + status_code=codes.CREATED, ) user = gl.users.get(1, lazy=True) @@ -768,7 +767,7 @@ async def test_update_submodule(self, gl, gl_get_value): "http://localhost/api/v4/projects/1", headers={"content-type": "application/json"}, content='{"name": "name", "id": 1}'.encode("utf-8"), - status_code=StatusCode.OK, + status_code=codes.OK, ) request_update_submodule = respx.put( "http://localhost/api/v4/projects/1/repository/submodules/foo%2Fbar", @@ -789,7 +788,7 @@ async def test_update_submodule(self, gl, gl_get_value): "status": null}""".encode( "utf-8" ), - status_code=StatusCode.OK, + status_code=codes.OK, ) project = gl.projects.get(1) project = await gl_get_value(project) @@ -822,7 +821,7 @@ async def test_import_github(self, gl, gl_get_value): }""".encode( "utf-8" ), - status_code=StatusCode.OK, + status_code=codes.OK, ) base_path = "/root" name = "my-repo" diff --git a/requirements.txt b/requirements.txt index 54876157b..8ef0b29dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -httpx>=0.11.1,<0.12 +httpx>=0.14.3,<0.15 diff --git a/setup.py b/setup.py index 06f444fc2..d95bebb31 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ def get_version(): license="LGPLv3", url="https://github.com/python-gitlab/python-gitlab", packages=find_packages(), - install_requires=["httpx>=0.11.1,<0.12"], + install_requires=["httpx>=0.18.1,<0.19"], python_requires=">=3.6.0", entry_points={"console_scripts": ["gitlab = gitlab.cli:main"]}, classifiers=[ diff --git a/test-requirements.txt b/test-requirements.txt index bbb8142ee..6d1965adc 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -8,6 +8,6 @@ mock sphinx>=1.3 sphinx_rtd_theme requests>=2.22.0 -respx>=0.10.0,<0.11 +respx>=0.12.1,<0.13 pytest pytest-asyncio