Skip to content

Commit 8d410ad

Browse files
authored
Merge pull request #374 from maxnoe/remove_requests
Requests → httpx
2 parents b3b2f73 + 97a0bda commit 8d410ad

File tree

11 files changed

+64
-43
lines changed

11 files changed

+64
-43
lines changed

diracx-cli/src/diracx/cli/auth.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import asyncio
66
import json
77
import os
8+
from asyncio import sleep
89
from datetime import datetime, timedelta, timezone
910
from typing import Annotated, Optional
1011

@@ -92,7 +93,7 @@ async def login(
9293
if response.error == "authorization_pending":
9394
# TODO: Setting more than 5 seconds results in an error
9495
# Related to keep-alive disconnects from uvicon (--timeout-keep-alive)
95-
await asyncio.sleep(2)
96+
await sleep(2)
9697
continue
9798
raise RuntimeError(f"Device flow failed with {response}")
9899
break

diracx-client/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ classifiers = [
1212
"Topic :: Scientific/Engineering",
1313
"Topic :: System :: Distributed Computing",
1414
]
15-
dependencies = ["azure-core", "diracx-core", "isodate", "requests"]
15+
dependencies = ["azure-core", "diracx-core", "isodate", "httpx"]
1616
dynamic = ["version"]
1717

1818
[project.optional-dependencies]
1919
testing = ["diracx-testing"]
20-
types = ["types-requests"]
20+
types = []
2121

2222
[tool.setuptools.packages.find]
2323
where = ["src"]

diracx-client/src/diracx/client/generated/_patch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import importlib.util
1414
import json
1515
import jwt
16-
import requests
16+
import httpx
1717

1818
from pathlib import Path
1919
from typing import Any, Dict, List, Optional, cast

diracx-client/src/diracx/client/patches/utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import json
88
import os
99
from diracx.core.utils import EXPIRES_GRACE_SECONDS, serialize_credentials
10+
import httpx
1011
import jwt
11-
import requests
1212

1313
from datetime import datetime, timezone
1414
from importlib.metadata import PackageNotFoundError, distribution
@@ -43,11 +43,11 @@ def get_openid_configuration(
4343
endpoint: str, *, verify: bool | str = True
4444
) -> Dict[str, str]:
4545
"""Get the openid configuration from the .well-known endpoint"""
46-
response = requests.get(
46+
response = httpx.get(
4747
url=parse.urljoin(endpoint, ".well-known/openid-configuration"),
4848
verify=verify,
4949
)
50-
if not response.ok:
50+
if not response.is_success:
5151
raise RuntimeError("Cannot fetch any information from the .well-known endpoint")
5252
return response.json()
5353

@@ -123,7 +123,7 @@ def refresh_token(
123123
verify: bool | str = True,
124124
) -> TokenResponse:
125125
"""Refresh the access token using the refresh_token flow."""
126-
response = requests.post(
126+
response = httpx.post(
127127
url=token_endpoint,
128128
data={
129129
"client_id": client_id,

diracx-core/tests/test_s3.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import random
66
import secrets
77

8+
import httpx
89
import pytest
9-
import requests
1010
from aiobotocore.session import get_session
1111

1212
from diracx.core.s3 import (
@@ -82,9 +82,13 @@ async def test_presigned_upload_moto(moto_s3):
8282
)
8383

8484
# Upload the file
85-
r = requests.post(
86-
upload_info["url"], data=upload_info["fields"], files={"file": file_content}
87-
)
85+
async with httpx.AsyncClient() as client:
86+
r = await client.post(
87+
upload_info["url"],
88+
data=upload_info["fields"],
89+
files={"file": file_content},
90+
)
91+
8892
assert r.status_code == 204, r.text
8993

9094
# Make sure the object is actually there
@@ -120,12 +124,18 @@ async def test_bucket(minio_client):
120124
"content,checksum,size,expected_error",
121125
[
122126
# Make sure a valid request works
123-
[*_random_file(128), 128, None],
127+
pytest.param(*_random_file(128), 128, None, id="valid"),
124128
# Check with invalid sizes
125-
[*_random_file(128), 127, "exceeds the maximum"],
126-
[*_random_file(128), 129, "smaller than the minimum"],
129+
pytest.param(*_random_file(128), 127, "exceeds the maximum", id="maximum"),
130+
pytest.param(*_random_file(128), 129, "smaller than the minimum", id="minimum"),
127131
# Check with invalid checksum
128-
[_random_file(128)[0], _random_file(128)[1], 128, "ContentChecksumMismatch"],
132+
pytest.param(
133+
_random_file(128)[0],
134+
_random_file(128)[1],
135+
128,
136+
"ContentChecksumMismatch",
137+
id="checksum",
138+
),
129139
],
130140
)
131141
async def test_presigned_upload_minio(
@@ -143,9 +153,11 @@ async def test_presigned_upload_minio(
143153
minio_client, test_bucket, key, "sha256", checksum, size, 60
144154
)
145155
# Ensure the URL doesn't work
146-
r = requests.post(
147-
upload_info["url"], data=upload_info["fields"], files={"file": content}
148-
)
156+
async with httpx.AsyncClient() as client:
157+
r = await client.post(
158+
upload_info["url"], data=upload_info["fields"], files={"file": content}
159+
)
160+
149161
if expected_error is None:
150162
assert r.status_code == 204, r.text
151163
assert await s3_object_exists(minio_client, test_bucket, key)

diracx-routers/pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ types = [
4343
"types-cachetools",
4444
"types-python-dateutil",
4545
"types-PyYAML",
46-
"types-requests",
4746
]
4847

4948
[project.entry-points."diracx.services"]

diracx-routers/tests/jobs/test_sandboxes.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
from copy import deepcopy
66
from io import BytesIO
77

8+
import httpx
89
import pytest
9-
import requests
1010
from fastapi.testclient import TestClient
1111

1212
from diracx.routers.auth.token import create_token
@@ -57,15 +57,15 @@ def test_upload_then_download(
5757

5858
# Actually upload the file
5959
files = {"file": ("file", BytesIO(data))}
60-
r = requests.post(upload_info["url"], data=upload_info["fields"], files=files)
60+
r = httpx.post(upload_info["url"], data=upload_info["fields"], files=files)
6161
assert r.status_code == 204, r.text
6262

6363
# Make sure we can download it and get the same data back
6464
r = normal_user_client.get("/api/jobs/sandbox", params={"pfn": sandbox_pfn})
6565
assert r.status_code == 200, r.text
6666
download_info = r.json()
6767
assert download_info["expires_in"] > 5
68-
r = requests.get(download_info["url"])
68+
r = httpx.get(download_info["url"])
6969
assert r.status_code == 200, r.text
7070
assert r.content == data
7171

diracx-testing/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies = [
1717
"pytest-asyncio",
1818
"pytest-cov",
1919
"pytest-xdist",
20+
"httpx",
2021
]
2122
dynamic = ["version"]
2223

diracx-testing/src/diracx/testing/utils.py

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
from urllib.parse import parse_qs, urljoin, urlparse
1919
from uuid import uuid4
2020

21+
import httpx
2122
import pytest
22-
import requests
2323

2424
if TYPE_CHECKING:
2525
from diracx.core.settings import DevelopmentSettings
@@ -616,7 +616,7 @@ async def test_login(monkeypatch, capfd, cli_env):
616616

617617
poll_attempts = 0
618618

619-
def fake_sleep(*args, **kwargs):
619+
async def fake_sleep(*args, **kwargs):
620620
nonlocal poll_attempts
621621

622622
# Keep track of the number of times this is called
@@ -629,13 +629,13 @@ def fake_sleep(*args, **kwargs):
629629
match = re.search(rf"{cli_env['DIRACX_URL']}[^\n]+", captured.out)
630630
assert match, captured
631631

632-
do_device_flow_with_dex(match.group(), cli_env["DIRACX_CA_PATH"])
632+
await do_device_flow_with_dex(match.group(), cli_env["DIRACX_CA_PATH"])
633633

634634
# Ensure we don't poll forever
635635
assert poll_attempts <= 100
636636

637637
# Reduce the sleep duration to zero to speed up the test
638-
return unpatched_sleep(0)
638+
await unpatched_sleep(0.0)
639639

640640
# We monkeypatch asyncio.sleep to provide a hook to run the actions that
641641
# would normally be done by a user. This includes capturing the login URL
@@ -650,7 +650,7 @@ def fake_sleep(*args, **kwargs):
650650

651651
# Run the login command
652652
with monkeypatch.context() as m:
653-
m.setattr("asyncio.sleep", fake_sleep)
653+
m.setattr("diracx.cli.auth.sleep", fake_sleep)
654654
await cli.auth.login(vo="diracAdmin", group=None, property=None)
655655
captured = capfd.readouterr()
656656
assert "Login successful!" in captured.out
@@ -664,18 +664,22 @@ def fake_sleep(*args, **kwargs):
664664
return expected_credentials_path.read_text()
665665

666666

667-
def do_device_flow_with_dex(url: str, ca_path: str) -> None:
667+
async def do_device_flow_with_dex(url: str, ca_path: str) -> None:
668668
"""Do the device flow with dex."""
669669

670670
class DexLoginFormParser(HTMLParser):
671671
def handle_starttag(self, tag, attrs):
672672
nonlocal action_url
673673
if "form" in str(tag):
674674
assert action_url is None
675-
action_url = urljoin(login_page_url, dict(attrs)["action"])
675+
action_url = urljoin(str(login_page_url), dict(attrs)["action"])
676676

677+
ssl_context = ssl.create_default_context(cafile=ca_path)
678+
client_kwargs = dict(verify=ssl_context, follow_redirects=True)
677679
# Get the login page
678-
r = requests.get(url, verify=ca_path)
680+
async with httpx.AsyncClient(**client_kwargs) as client:
681+
r = await client.get(url)
682+
679683
r.raise_for_status()
680684
login_page_url = r.url # This is not the same as URL as we redirect to dex
681685
login_page_body = r.text
@@ -686,19 +690,24 @@ def handle_starttag(self, tag, attrs):
686690
assert action_url is not None, login_page_body
687691

688692
# Do the actual login
689-
r = requests.post(
690-
action_url,
691-
data={"login": "admin@example.com", "password": "password"},
692-
verify=ca_path,
693-
)
693+
async with httpx.AsyncClient(**client_kwargs) as client:
694+
r = await client.post(
695+
action_url,
696+
data={"login": "admin@example.com", "password": "password"},
697+
)
698+
694699
r.raise_for_status()
695700
approval_url = r.url # This is not the same as URL as we redirect to dex
696701
# Do the actual approval
697-
r = requests.post(
698-
approval_url,
699-
{"approval": "approve", "req": parse_qs(urlparse(r.url).query)["req"][0]},
700-
verify=ca_path,
701-
)
702+
703+
async with httpx.AsyncClient(**client_kwargs) as client:
704+
r = await client.post(
705+
approval_url,
706+
data={
707+
"approval": "approve",
708+
"req": parse_qs(urlparse(str(r.url)).query)["req"][0],
709+
},
710+
)
702711

703712
# This should have redirected to the DiracX page that shows the login is complete
704713
assert "Please close the window" in r.text

extensions/gubbins/gubbins-client/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ dynamic = ["version"]
1717

1818
[project.optional-dependencies]
1919
testing = ["diracx-client[testing]", "diracx-testing"]
20-
types = ["types-requests"]
20+
types = []
2121

2222
[tool.setuptools.packages.find]
2323
where = ["src"]

0 commit comments

Comments
 (0)