python-http_request 0.0.9__tar.gz → 0.1.0__tar.gz
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.
- {python_http_request-0.0.9 → python_http_request-0.1.0}/PKG-INFO +1 -1
- {python_http_request-0.0.9 → python_http_request-0.1.0}/http_request/__init__.py +82 -21
- {python_http_request-0.0.9 → python_http_request-0.1.0}/pyproject.toml +1 -1
- {python_http_request-0.0.9 → python_http_request-0.1.0}/LICENSE +0 -0
- {python_http_request-0.0.9 → python_http_request-0.1.0}/http_request/py.typed +0 -0
- {python_http_request-0.0.9 → python_http_request-0.1.0}/readme.md +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# encoding: utf-8
|
|
3
3
|
|
|
4
4
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
|
5
|
-
__version__ = (0,
|
|
5
|
+
__version__ = (0, 1, 0)
|
|
6
6
|
__all__ = [
|
|
7
7
|
"SupportsGeturl", "url_origin", "complete_url", "ensure_ascii_url",
|
|
8
8
|
"urlencode", "cookies_str_to_dict", "headers_str_to_dict_by_lines",
|
|
@@ -25,7 +25,10 @@ from os import PathLike
|
|
|
25
25
|
from os.path import basename
|
|
26
26
|
from re import compile as re_compile, Pattern
|
|
27
27
|
from string import punctuation
|
|
28
|
-
from typing import
|
|
28
|
+
from typing import (
|
|
29
|
+
cast, overload, runtime_checkable, Any, Final, Literal, Protocol,
|
|
30
|
+
TypedDict,
|
|
31
|
+
)
|
|
29
32
|
from urllib.parse import quote, urlparse, urlunparse
|
|
30
33
|
from uuid import uuid4
|
|
31
34
|
from yarl import URL
|
|
@@ -57,15 +60,17 @@ class SupportsGeturl[AnyStr: (bytes, str)](Protocol):
|
|
|
57
60
|
def geturl(self) -> AnyStr: ...
|
|
58
61
|
|
|
59
62
|
|
|
60
|
-
def url_origin(
|
|
63
|
+
def url_origin(
|
|
64
|
+
url: str,
|
|
65
|
+
/,
|
|
66
|
+
default_port: int = 0,
|
|
67
|
+
) -> str:
|
|
61
68
|
if url.startswith("/"):
|
|
62
69
|
url = "http://localhost" + url
|
|
63
70
|
elif url.startswith("//"):
|
|
64
71
|
url = "http:" + url
|
|
65
72
|
elif url.startswith("://"):
|
|
66
73
|
url = "http" + url
|
|
67
|
-
elif not CRE_URL_SCHEME_match(url):
|
|
68
|
-
url = "http://" + url
|
|
69
74
|
urlp = urlparse(url)
|
|
70
75
|
scheme, netloc = urlp.scheme or "http", urlp.netloc or "localhost"
|
|
71
76
|
if default_port and not urlp.port:
|
|
@@ -73,17 +78,27 @@ def url_origin(url: str, /, default_port: int = 0) -> str:
|
|
|
73
78
|
return f"{scheme}://{netloc}"
|
|
74
79
|
|
|
75
80
|
|
|
76
|
-
def complete_url(
|
|
81
|
+
def complete_url(
|
|
82
|
+
url: str,
|
|
83
|
+
/,
|
|
84
|
+
default_port: int = 0,
|
|
85
|
+
clean: bool = False,
|
|
86
|
+
) -> str:
|
|
77
87
|
if url.startswith("/"):
|
|
78
88
|
url = "http://localhost" + url
|
|
79
89
|
elif url.startswith("//"):
|
|
80
90
|
url = "http:" + url
|
|
81
91
|
elif url.startswith("://"):
|
|
82
92
|
url = "http" + url
|
|
83
|
-
|
|
84
|
-
|
|
93
|
+
if not (clean or default_port):
|
|
94
|
+
if not CRE_URL_SCHEME_match(url):
|
|
95
|
+
url = "http://" + url
|
|
96
|
+
return url
|
|
85
97
|
urlp = urlparse(url)
|
|
86
|
-
|
|
98
|
+
if clean:
|
|
99
|
+
repl = {"params": "", "query": "", "fragment": ""}
|
|
100
|
+
else:
|
|
101
|
+
repl = {}
|
|
87
102
|
if not urlp.scheme:
|
|
88
103
|
repl["scheme"] = "http"
|
|
89
104
|
netloc = urlp.netloc
|
|
@@ -91,7 +106,10 @@ def complete_url(url: str, /, default_port: int = 0) -> str:
|
|
|
91
106
|
netloc = "localhost"
|
|
92
107
|
if default_port and not urlp.port:
|
|
93
108
|
netloc = netloc.removesuffix(":") + f":{default_port}"
|
|
94
|
-
|
|
109
|
+
if netloc != urlp.netloc:
|
|
110
|
+
repl["netloc"] = netloc
|
|
111
|
+
if not repl:
|
|
112
|
+
return url
|
|
95
113
|
return urlunparse(urlp._replace(**repl)).rstrip("/")
|
|
96
114
|
|
|
97
115
|
|
|
@@ -166,12 +184,37 @@ def headers_str_to_dict_by_lines(headers: str, /, ) -> dict[str, str]:
|
|
|
166
184
|
return dict(batched(lines, 2)) # type: ignore
|
|
167
185
|
|
|
168
186
|
|
|
187
|
+
@overload
|
|
169
188
|
def encode_multipart_data(
|
|
170
|
-
data: None | Mapping[
|
|
171
|
-
files: None | Mapping[
|
|
189
|
+
data: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
190
|
+
files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
172
191
|
boundary: None | str = None,
|
|
173
192
|
file_suffix: str = "",
|
|
193
|
+
*,
|
|
194
|
+
async_: Literal[False] = False,
|
|
174
195
|
) -> tuple[dict, Iterator[Buffer]]:
|
|
196
|
+
...
|
|
197
|
+
@overload
|
|
198
|
+
def encode_multipart_data(
|
|
199
|
+
data: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
200
|
+
files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
201
|
+
boundary: None | str = None,
|
|
202
|
+
file_suffix: str = "",
|
|
203
|
+
*,
|
|
204
|
+
async_: Literal[True],
|
|
205
|
+
) -> tuple[dict, AsyncIterator[Buffer]]:
|
|
206
|
+
...
|
|
207
|
+
def encode_multipart_data(
|
|
208
|
+
data: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
209
|
+
files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
210
|
+
boundary: None | str = None,
|
|
211
|
+
file_suffix: str = "",
|
|
212
|
+
*,
|
|
213
|
+
async_: bool = False,
|
|
214
|
+
) -> tuple[dict, Iterator[Buffer]] | tuple[dict, AsyncIterator[Buffer]]:
|
|
215
|
+
if async_:
|
|
216
|
+
return encode_multipart_data_async(data, files, boundary)
|
|
217
|
+
|
|
175
218
|
if not boundary:
|
|
176
219
|
boundary = uuid4().hex
|
|
177
220
|
boundary_bytes = bytes(boundary, "ascii")
|
|
@@ -258,8 +301,8 @@ def encode_multipart_data(
|
|
|
258
301
|
|
|
259
302
|
|
|
260
303
|
def encode_multipart_data_async(
|
|
261
|
-
data: None | Mapping[
|
|
262
|
-
files: None | Mapping[
|
|
304
|
+
data: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
305
|
+
files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
263
306
|
boundary: None | str = None,
|
|
264
307
|
file_suffix: str = "",
|
|
265
308
|
) -> tuple[dict, AsyncIterator[Buffer]]:
|
|
@@ -380,8 +423,11 @@ def normalize_request_args(
|
|
|
380
423
|
params: Any = None,
|
|
381
424
|
data: Any = None,
|
|
382
425
|
json: Any = None,
|
|
426
|
+
files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
383
427
|
headers: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
|
|
384
428
|
ensure_ascii: bool = False,
|
|
429
|
+
*,
|
|
430
|
+
async_: bool = False,
|
|
385
431
|
) -> RequestArgs:
|
|
386
432
|
method = ensure_str(method).upper()
|
|
387
433
|
if isinstance(url, SupportsGeturl):
|
|
@@ -404,7 +450,14 @@ def normalize_request_args(
|
|
|
404
450
|
content_type = headers_.get("content-type", "")
|
|
405
451
|
charset = get_charset(content_type)
|
|
406
452
|
mimetype = get_mimetype(charset).lower()
|
|
407
|
-
if
|
|
453
|
+
if files is not None:
|
|
454
|
+
headers2, data = encode_multipart_data(
|
|
455
|
+
cast(None | Mapping[string, Any] | Iterable[tuple[string, Any]], data),
|
|
456
|
+
files,
|
|
457
|
+
async_=async_, # type: ignore
|
|
458
|
+
)
|
|
459
|
+
headers_.update(headers2)
|
|
460
|
+
elif data is not None:
|
|
408
461
|
if isinstance(data, Buffer):
|
|
409
462
|
pass
|
|
410
463
|
elif isinstance(data, (str, UserString)):
|
|
@@ -412,7 +465,10 @@ def normalize_request_args(
|
|
|
412
465
|
elif isinstance(data, AsyncIterable):
|
|
413
466
|
data = async_map(ensure_buffer, data)
|
|
414
467
|
elif isinstance(data, Iterator):
|
|
415
|
-
|
|
468
|
+
if async_:
|
|
469
|
+
data = async_map(ensure_buffer, data)
|
|
470
|
+
else:
|
|
471
|
+
data = map(ensure_buffer, data)
|
|
416
472
|
elif mimetype == "application/json":
|
|
417
473
|
if charset == "utf-8":
|
|
418
474
|
data = json_dumps(data, default=json_default)
|
|
@@ -429,13 +485,18 @@ def normalize_request_args(
|
|
|
429
485
|
elif json is not None:
|
|
430
486
|
if isinstance(json, Buffer):
|
|
431
487
|
data = json
|
|
432
|
-
elif isinstance(
|
|
433
|
-
data = async_map(ensure_buffer,
|
|
434
|
-
|
|
435
|
-
|
|
488
|
+
elif isinstance(json, AsyncIterable):
|
|
489
|
+
data = async_map(ensure_buffer, json)
|
|
490
|
+
elif isinstance(json, Iterator):
|
|
491
|
+
if async_:
|
|
492
|
+
data = async_map(ensure_buffer, json)
|
|
493
|
+
else:
|
|
494
|
+
data = map(ensure_buffer, json)
|
|
495
|
+
elif charset == "utf-8":
|
|
496
|
+
data = json_dumps(json, default=json_default)
|
|
436
497
|
else:
|
|
437
498
|
from json import dumps
|
|
438
|
-
data = dumps(
|
|
499
|
+
data = dumps(json, default=json_default).encode(charset)
|
|
439
500
|
if mimetype != "application/json":
|
|
440
501
|
headers_["content-type"] = "application/json; charset=" + charset
|
|
441
502
|
elif mimetype == "application/json":
|
|
File without changes
|
|
File without changes
|
|
File without changes
|