Skip to content

Commit 74e5c89

Browse files
committed
refactor HttpClient's request interface
1 parent c5537ce commit 74e5c89

File tree

3 files changed

+59
-17
lines changed

3 files changed

+59
-17
lines changed

tests/test_requests.py

+32-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44
from web_poet.page_inputs import ResponseData
55
from web_poet.requests import (
6-
GenericRequest,
6+
Request,
77
perform_request,
88
HttpClient,
99
RequestBackendError,
@@ -25,13 +25,13 @@ async def async_test(req):
2525

2626
def test_generic_request():
2727

28-
req = GenericRequest("url")
28+
req = Request("url")
2929
assert req.url == "url"
3030
assert req.method == "GET"
3131
assert req.headers is None
3232
assert req.body is None
3333

34-
req = GenericRequest(
34+
req = Request(
3535
"url", method="POST", headers={"User-Agent": "test agent"}, body=b"body"
3636
)
3737
assert req.method == "POST"
@@ -42,7 +42,7 @@ def test_generic_request():
4242
@pytest.mark.asyncio
4343
async def test_perform_request(async_mock):
4444

45-
req = GenericRequest("url")
45+
req = Request("url")
4646

4747
with pytest.raises(RequestBackendError):
4848
await perform_request(req)
@@ -56,16 +56,36 @@ async def test_perform_request(async_mock):
5656

5757

5858
@pytest.mark.asyncio
59-
async def test_http_client(async_mock):
59+
async def test_http_client_single_requests(async_mock):
6060
client = HttpClient(async_mock)
6161
assert client.request_downloader == async_mock
6262

63-
req_1 = GenericRequest("url-1")
64-
req_2 = GenericRequest("url-2")
63+
with mock.patch("web_poet.requests.Request") as mock_request:
64+
response = await client.request("url")
65+
response.url == "url"
6566

66-
# It should be able to accept arbitrary number of requests
67-
client.request(req_1)
68-
responses = await client.request(req_1, req_2)
67+
response = await client.get("url-get")
68+
response.url == "url-get"
6969

70-
assert responses[0].url == req_1.url
71-
assert responses[1].url == req_2.url
70+
response = await client.post("url-post")
71+
response.url == "url-post"
72+
73+
assert mock_request.call_args_list == [
74+
mock.call("url", "GET", None, None),
75+
mock.call("url-get", "GET", None, None),
76+
mock.call("url-post", "POST", None, None),
77+
]
78+
79+
80+
@pytest.mark.asyncio
81+
async def test_http_client_batch_requests(async_mock):
82+
client = HttpClient(async_mock)
83+
84+
requests = [
85+
Request("url-1"),
86+
Request("url-get", method="GET"),
87+
Request("url-post", method="POST"),
88+
]
89+
responses = await client.batch_requests(*requests)
90+
91+
assert all([isinstance(response, ResponseData) for response in responses])

web_poet/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from .pages import WebPage, ItemPage, ItemWebPage, Injectable
22
from .page_inputs import ResponseData
3-
from .requests import request_backend_var, GenericRequest, HttpClient
3+
from .requests import request_backend_var, Request, HttpClient

web_poet/requests.py

+26-4
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,13 @@
5050

5151
import attr
5252

53+
from web_poet.page_inputs import ResponseData
54+
5355
logger = logging.getLogger(__name__)
5456

5557

58+
mapping = Dict[Union[str, ByteString], Any]
59+
5660
# Frameworks that wants to support additional requests in ``web-poet`` should
5761
# set the appropriate implementation for requesting data.
5862
request_backend_var: ContextVar = ContextVar("request_backend")
@@ -63,16 +67,16 @@ class RequestBackendError(Exception):
6367

6468

6569
@attr.define
66-
class GenericRequest:
70+
class Request:
6771
"""Represents a generic HTTP request."""
6872

6973
url: str
7074
method: str = "GET"
71-
headers: Optional[Dict[Union[str, ByteString], Any]] = None
75+
headers: Optional[mapping] = None
7276
body: Optional[str] = None
7377

7478

75-
async def perform_request(request: GenericRequest):
79+
async def perform_request(request: Request):
7680
logger.info(f"Requesting page: {request}")
7781

7882
try:
@@ -92,7 +96,25 @@ class HttpClient:
9296
def __init__(self, request_downloader=None):
9397
self.request_downloader = request_downloader or perform_request
9498

95-
async def request(self, *requests: List[GenericRequest]):
99+
async def request(
100+
self,
101+
url: str,
102+
method: str = "GET",
103+
headers: Optional[mapping] = None,
104+
body: Optional[str] = None,
105+
) -> ResponseData:
106+
r = Request(url, method, headers, body)
107+
return await self.request_downloader(r)
108+
109+
async def get(self, url: str, headers: Optional[mapping] = None) -> ResponseData:
110+
return await self.request(url=url, method="GET", headers=headers)
111+
112+
async def post(
113+
self, url: str, headers: Optional[mapping] = None, body: Optional[str] = None
114+
) -> ResponseData:
115+
return await self.request(url=url, method="POST", headers=headers, body=body)
116+
117+
async def batch_requests(self, *requests: List[Request]):
96118
coroutines = [self.request_downloader(r) for r in requests]
97119
responses = await asyncio.gather(*coroutines)
98120
return responses

0 commit comments

Comments
 (0)