mm-std 0.3.23__py3-none-any.whl → 0.3.25__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mm_std/http_.py
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
import asyncio
|
2
1
|
import json
|
3
2
|
from dataclasses import asdict, dataclass, field
|
4
|
-
from typing import Any
|
5
|
-
from urllib.parse import urlencode
|
3
|
+
from typing import Any, cast
|
4
|
+
from urllib.parse import urlencode, urlparse
|
6
5
|
|
7
6
|
import aiohttp
|
8
7
|
import pydash
|
9
8
|
import requests
|
10
9
|
from aiohttp_socks import ProxyConnector
|
10
|
+
from multidict import CIMultiDictProxy
|
11
11
|
from requests.auth import AuthBase
|
12
12
|
|
13
13
|
from mm_std.result import Err, Ok, Result
|
@@ -73,10 +73,13 @@ class HResponse:
|
|
73
73
|
return self.error == "timeout"
|
74
74
|
|
75
75
|
def is_proxy_error(self) -> bool:
|
76
|
-
return self.error == "
|
76
|
+
return self.error == "proxy"
|
77
77
|
|
78
78
|
def is_connection_error(self) -> bool:
|
79
|
-
return self.error is not None and self.error.startswith("
|
79
|
+
return self.error is not None and self.error.startswith("connection:")
|
80
|
+
|
81
|
+
def is_dns_error(self) -> bool:
|
82
|
+
return self.error is not None and self.error.startswith("dns:")
|
80
83
|
|
81
84
|
def to_dict(self) -> dict[str, Any]:
|
82
85
|
return pydash.omit(asdict(self), "_json_data")
|
@@ -136,9 +139,9 @@ def hrequest(
|
|
136
139
|
except requests.exceptions.Timeout:
|
137
140
|
return HResponse(error="timeout")
|
138
141
|
except requests.exceptions.ProxyError:
|
139
|
-
return HResponse(error="
|
142
|
+
return HResponse(error="proxy")
|
140
143
|
except requests.exceptions.RequestException as err:
|
141
|
-
return HResponse(error=f"
|
144
|
+
return HResponse(error=f"connection: {err}")
|
142
145
|
except Exception as err:
|
143
146
|
return HResponse(error=f"exception: {err}")
|
144
147
|
|
@@ -155,7 +158,6 @@ async def hrequest_async(
|
|
155
158
|
user_agent: str | None = None,
|
156
159
|
json_params: bool = True,
|
157
160
|
auth: tuple[str, str] | None = None,
|
158
|
-
verify: bool = True,
|
159
161
|
) -> HResponse:
|
160
162
|
query_params: dict[str, Any] | None = None
|
161
163
|
data: dict[str, Any] | None = None
|
@@ -174,54 +176,65 @@ async def hrequest_async(
|
|
174
176
|
data = params
|
175
177
|
|
176
178
|
try:
|
177
|
-
|
178
|
-
if
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
request_kwargs
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
if data:
|
194
|
-
request_kwargs["data"] = data
|
195
|
-
|
196
|
-
if auth and isinstance(auth, tuple) and len(auth) == 2:
|
197
|
-
request_kwargs["auth"] = aiohttp.BasicAuth(auth[0], auth[1])
|
198
|
-
|
199
|
-
# Set HTTP proxy (not needed for SOCKS5)
|
200
|
-
if proxy and not proxy.startswith("socks5://"):
|
201
|
-
request_kwargs["proxy"] = proxy
|
202
|
-
|
203
|
-
try:
|
204
|
-
async with await asyncio.wait_for(session.request(method, url, **request_kwargs), timeout=timeout) as response:
|
205
|
-
body = await response.text()
|
206
|
-
return HResponse(code=response.status, body=body, headers=dict(response.headers))
|
207
|
-
except TimeoutError:
|
208
|
-
return HResponse(error="timeout")
|
209
|
-
except (aiohttp.ClientProxyConnectionError, aiohttp.ClientHttpProxyError):
|
210
|
-
return HResponse(error="proxy_error")
|
211
|
-
except aiohttp.ClientConnectorError as err:
|
212
|
-
return HResponse(error=f"connection_error: {err}")
|
213
|
-
except aiohttp.ClientError as err:
|
214
|
-
return HResponse(error=f"connection_error: {err}")
|
215
|
-
except Exception as err:
|
216
|
-
if "couldn't connect to proxy" in str(err).lower():
|
217
|
-
return HResponse(error="proxy_error")
|
218
|
-
return HResponse(error=f"exception: {err}")
|
179
|
+
request_kwargs: dict[str, Any] = {"headers": headers}
|
180
|
+
if query_params:
|
181
|
+
request_kwargs["params"] = query_params
|
182
|
+
if json_:
|
183
|
+
request_kwargs["json"] = json_
|
184
|
+
if data:
|
185
|
+
request_kwargs["data"] = data
|
186
|
+
if cookies:
|
187
|
+
request_kwargs["cookies"] = cookies
|
188
|
+
if auth and isinstance(auth, tuple) and len(auth) == 2:
|
189
|
+
request_kwargs["auth"] = aiohttp.BasicAuth(auth[0], auth[1])
|
190
|
+
|
191
|
+
if proxy and proxy.startswith("socks"):
|
192
|
+
return await _aiohttp_socks5(url, method, proxy, request_kwargs, timeout)
|
193
|
+
return await _aiohttp(url, method, request_kwargs, timeout=timeout, proxy=proxy)
|
194
|
+
|
219
195
|
except TimeoutError:
|
220
196
|
return HResponse(error="timeout")
|
197
|
+
except (aiohttp.ClientProxyConnectionError, aiohttp.ClientHttpProxyError, aiohttp.ClientConnectorError) as err:
|
198
|
+
if is_proxy_error(str(err), proxy):
|
199
|
+
return HResponse(error="proxy")
|
200
|
+
return HResponse(error=f"connection: {err}")
|
201
|
+
except aiohttp.ClientError as err:
|
202
|
+
return HResponse(error=f"error: {err}")
|
221
203
|
except Exception as err:
|
222
204
|
return HResponse(error=f"exception: {err}")
|
223
205
|
|
224
206
|
|
207
|
+
def is_proxy_error(error_message: str, proxy: str | None) -> bool:
|
208
|
+
if not proxy:
|
209
|
+
return False
|
210
|
+
error_message = error_message.lower()
|
211
|
+
if "proxy" in error_message:
|
212
|
+
return True
|
213
|
+
return bool("cannot connect to" in error_message and cast(str, urlparse(proxy).hostname) in error_message)
|
214
|
+
|
215
|
+
|
216
|
+
async def _aiohttp(
|
217
|
+
url: str, method: str, request_kwargs: dict[str, object], timeout: float | None = None, proxy: str | None = None
|
218
|
+
) -> HResponse:
|
219
|
+
if proxy:
|
220
|
+
request_kwargs["proxy"] = proxy
|
221
|
+
client_timeout = aiohttp.ClientTimeout(total=timeout) if timeout else None
|
222
|
+
async with aiohttp.ClientSession(timeout=client_timeout) as session, session.request(method, url, **request_kwargs) as res: # type: ignore[arg-type]
|
223
|
+
return HResponse(code=res.status, body=await res.text(), headers=headers_dict(res.headers))
|
224
|
+
|
225
|
+
|
226
|
+
async def _aiohttp_socks5(
|
227
|
+
url: str, method: str, proxy: str, request_kwargs: dict[str, object], timeout: float | None = None
|
228
|
+
) -> HResponse:
|
229
|
+
connector = ProxyConnector.from_url(proxy)
|
230
|
+
client_timeout = aiohttp.ClientTimeout(total=timeout) if timeout else None
|
231
|
+
async with (
|
232
|
+
aiohttp.ClientSession(connector=connector, timeout=client_timeout) as session,
|
233
|
+
session.request(method, url, **request_kwargs) as res, # type: ignore[arg-type]
|
234
|
+
):
|
235
|
+
return HResponse(code=res.status, body=await res.text(), headers=headers_dict(res.headers))
|
236
|
+
|
237
|
+
|
225
238
|
def add_query_params_to_url(url: str, params: dict[str, object]) -> str:
|
226
239
|
query_params = urlencode({k: v for k, v in params.items() if v is not None})
|
227
240
|
if query_params:
|
@@ -231,3 +244,14 @@ def add_query_params_to_url(url: str, params: dict[str, object]) -> str:
|
|
231
244
|
|
232
245
|
hr = hrequest
|
233
246
|
hra = hrequest_async
|
247
|
+
|
248
|
+
|
249
|
+
def headers_dict(headers: CIMultiDictProxy[str]) -> dict[str, str]:
|
250
|
+
result: dict[str, str] = {}
|
251
|
+
for key in headers:
|
252
|
+
values = headers.getall(key)
|
253
|
+
if len(values) == 1:
|
254
|
+
result[key] = values[0]
|
255
|
+
else:
|
256
|
+
result[key] = ", ".join(values)
|
257
|
+
return result
|
@@ -6,7 +6,7 @@ mm_std/date.py,sha256=976eEkSONuNqHQBgSRu8hrtH23tJqztbmHFHLdbP2TY,1879
|
|
6
6
|
mm_std/dict.py,sha256=6GkhJPXD0LiJDxPcYe6jPdEDw-MN7P7mKu6U5XxwYDk,675
|
7
7
|
mm_std/env.py,sha256=5zaR9VeIfObN-4yfgxoFeU5IM1GDeZZj9SuYf7t9sOA,125
|
8
8
|
mm_std/fs.py,sha256=RwarNRJq3tIMG6LVX_g03hasfYpjYFh_O27oVDt5IPQ,291
|
9
|
-
mm_std/http_.py,sha256=
|
9
|
+
mm_std/http_.py,sha256=5_V5Hx1M07xwzf0VVqAsxSFJkvtaAhj9_sFQP_HliQw,8215
|
10
10
|
mm_std/json_.py,sha256=Naa6mBE4D0yiQGkPNRrFvndnUH3R7ovw3FeaejWV60o,1196
|
11
11
|
mm_std/log.py,sha256=0TkTsAlUTt00gjgukvsvnZRIAGELq0MI6Lv8mKP-Wz4,2887
|
12
12
|
mm_std/net.py,sha256=qdRCBIDneip6FaPNe5mx31UtYVmzqam_AoUF7ydEyjA,590
|
@@ -25,6 +25,6 @@ mm_std/concurrency/async_task_runner.py,sha256=EN7tN2enkVYVgDbhSiAr-_W4o9m9wBXCv
|
|
25
25
|
mm_std/concurrency/sync_decorators.py,sha256=syCQBOmN7qPO55yzgJB2rbkh10CVww376hmyvs6e5tA,1080
|
26
26
|
mm_std/concurrency/sync_scheduler.py,sha256=j4tBL_cBI1spr0cZplTA7N2CoYsznuORMeRN8rpR6gY,2407
|
27
27
|
mm_std/concurrency/sync_task_runner.py,sha256=s5JPlLYLGQGHIxy4oDS-PN7O9gcy-yPZFoNm8RQwzcw,1780
|
28
|
-
mm_std-0.3.
|
29
|
-
mm_std-0.3.
|
30
|
-
mm_std-0.3.
|
28
|
+
mm_std-0.3.25.dist-info/METADATA,sha256=dLHZWg8G8cs5y3S8bu3zwxW-qgJaGaBGVQxS8vl4lcg,415
|
29
|
+
mm_std-0.3.25.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
30
|
+
mm_std-0.3.25.dist-info/RECORD,,
|
File without changes
|