|
1 |
| -"""This module has a full support for :mod:`asyncio` that enables developers to |
2 |
| -perform asynchronous additional requests inside of Page Objects. |
3 |
| -
|
4 |
| -Note that the implementation to fully execute any :class:`~.Request` is not |
5 |
| -handled in this module. With that, the framework using **web-poet** must supply |
6 |
| -the implementation. |
7 |
| -
|
8 |
| -You can read more about this in the :ref:`advanced-downloader-impl` documentation. |
9 |
| -""" |
10 |
| - |
11 |
| -import asyncio |
12 | 1 | import logging
|
13 | 2 | from contextvars import ContextVar
|
14 |
| -from typing import Optional, List, Callable, Union, Dict |
15 |
| - |
16 |
| -import attrs |
17 | 3 |
|
18 |
| -from web_poet.page_inputs import ( |
19 |
| - HttpResponse, |
| 4 | +from web_poet.exceptions import RequestBackendError |
| 5 | +from web_poet.page_inputs.http import ( |
20 | 6 | HttpRequest,
|
21 |
| - HttpRequestHeaders, |
22 |
| - HttpRequestBody, |
| 7 | + HttpResponse, |
23 | 8 | )
|
24 |
| -from web_poet.exceptions import RequestBackendError |
25 | 9 |
|
26 | 10 | logger = logging.getLogger(__name__)
|
27 | 11 |
|
28 |
| -_StrMapping = Dict[str, str] |
29 |
| -_Headers = Union[_StrMapping, HttpRequestHeaders] |
30 |
| -_Body = Union[bytes, HttpRequestBody] |
31 |
| - |
32 |
| - |
33 | 12 | # Frameworks that wants to support additional requests in ``web-poet`` should
|
34 | 13 | # set the appropriate implementation for requesting data.
|
35 | 14 | request_backend_var: ContextVar = ContextVar("request_backend")
|
@@ -60,99 +39,3 @@ async def _perform_request(request: HttpRequest) -> HttpResponse:
|
60 | 39 |
|
61 | 40 | response_data: HttpResponse = await request_backend(request)
|
62 | 41 | return response_data
|
63 |
| - |
64 |
| - |
65 |
| -class HttpClient: |
66 |
| - """A convenient client to easily execute requests. |
67 |
| -
|
68 |
| - By default, it uses the request implementation assigned in the |
69 |
| - ``web_poet.request_backend_var`` which is a :mod:`contextvars` instance to |
70 |
| - download the actual requests. However, it can easily be overridable by |
71 |
| - providing an optional ``request_downloader`` callable. |
72 |
| -
|
73 |
| - Providing the request implementation by dependency injection would be a good |
74 |
| - alternative solution when you want to avoid setting up :mod:`contextvars` |
75 |
| - like ``web_poet.request_backend_var``. |
76 |
| -
|
77 |
| - In any case, this doesn't contain any implementation about how to execute |
78 |
| - any requests fed into it. When setting that up, make sure that the downloader |
79 |
| - implementation returns a :class:`~.HttpResponse` instance. |
80 |
| - """ |
81 |
| - |
82 |
| - def __init__(self, request_downloader: Callable = None): |
83 |
| - self._request_downloader = request_downloader or _perform_request |
84 |
| - |
85 |
| - async def request( |
86 |
| - self, |
87 |
| - url: str, |
88 |
| - *, |
89 |
| - method: str = "GET", |
90 |
| - headers: Optional[_Headers] = None, |
91 |
| - body: Optional[_Body] = None, |
92 |
| - ) -> HttpResponse: |
93 |
| - """This is a shortcut for creating a :class:`~.HttpRequest` instance and executing |
94 |
| - that request. |
95 |
| -
|
96 |
| - A :class:`~.HttpResponse` instance should then be returned. |
97 |
| -
|
98 |
| - .. warning:: |
99 |
| - By convention, the request implementation supplied optionally to |
100 |
| - :class:`~.HttpClient` should return a :class:`~.HttpResponse` instance. |
101 |
| - However, the underlying implementation supplied might change that, |
102 |
| - depending on how the framework using **web-poet** implements it. |
103 |
| - """ |
104 |
| - headers = headers or {} |
105 |
| - body = body or b"" |
106 |
| - req = HttpRequest(url=url, method=method, headers=headers, body=body) |
107 |
| - return await self.execute(req) |
108 |
| - |
109 |
| - async def get(self, url: str, *, headers: Optional[_Headers] = None) -> HttpResponse: |
110 |
| - """Similar to :meth:`~.HttpClient.request` but peforming a ``GET`` |
111 |
| - request. |
112 |
| - """ |
113 |
| - return await self.request(url=url, method="GET", headers=headers) |
114 |
| - |
115 |
| - async def post( |
116 |
| - self, |
117 |
| - url: str, |
118 |
| - *, |
119 |
| - headers: Optional[_Headers] = None, |
120 |
| - body: Optional[_Body] = None, |
121 |
| - ) -> HttpResponse: |
122 |
| - """Similar to :meth:`~.HttpClient.request` but performing a ``POST`` |
123 |
| - request. |
124 |
| - """ |
125 |
| - return await self.request(url=url, method="POST", headers=headers, body=body) |
126 |
| - |
127 |
| - async def execute(self, request: HttpRequest) -> HttpResponse: |
128 |
| - """Accepts a single instance of :class:`~.HttpRequest` and executes it |
129 |
| - using the request implementation configured in the :class:`~.HttpClient` |
130 |
| - instance. |
131 |
| -
|
132 |
| - This returns a single :class:`~.HttpResponse`. |
133 |
| - """ |
134 |
| - return await self._request_downloader(request) |
135 |
| - |
136 |
| - async def batch_execute( |
137 |
| - self, *requests: HttpRequest, return_exceptions: bool = False |
138 |
| - ) -> List[Union[HttpResponse, Exception]]: |
139 |
| - """Similar to :meth:`~.HttpClient.execute` but accepts a collection of |
140 |
| - :class:`~.HttpRequest` instances that would be batch executed. |
141 |
| -
|
142 |
| - The order of the :class:`~.HttpResponses` would correspond to the order |
143 |
| - of :class:`~.HttpRequest` passed. |
144 |
| -
|
145 |
| - If any of the :class:`~.HttpRequest` raises an exception upon execution, |
146 |
| - the exception is raised. |
147 |
| -
|
148 |
| - To prevent this, the actual exception can be returned alongside any |
149 |
| - successful :class:`~.HttpResponse`. This enables salvaging any usable |
150 |
| - responses despite any possible failures. This can be done by setting |
151 |
| - ``True`` to the ``return_exceptions`` parameter. |
152 |
| - """ |
153 |
| - |
154 |
| - coroutines = [self._request_downloader(r) for r in requests] |
155 |
| - responses = await asyncio.gather( |
156 |
| - *coroutines, return_exceptions=return_exceptions |
157 |
| - ) |
158 |
| - return responses |
0 commit comments