python-urlopen 0.0.5__tar.gz → 0.0.5.1__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_urlopen-0.0.5 → python_urlopen-0.0.5.1}/PKG-INFO +3 -1
- {python_urlopen-0.0.5 → python_urlopen-0.0.5.1}/pyproject.toml +3 -1
- {python_urlopen-0.0.5 → python_urlopen-0.0.5.1}/urlopen/__init__.py +52 -12
- {python_urlopen-0.0.5 → python_urlopen-0.0.5.1}/LICENSE +0 -0
- {python_urlopen-0.0.5 → python_urlopen-0.0.5.1}/readme.md +0 -0
- {python_urlopen-0.0.5 → python_urlopen-0.0.5.1}/urlopen/__main__.py +0 -0
- {python_urlopen-0.0.5 → python_urlopen-0.0.5.1}/urlopen/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-urlopen
|
|
3
|
-
Version: 0.0.5
|
|
3
|
+
Version: 0.0.5.1
|
|
4
4
|
Summary: Python urlopen wrapper.
|
|
5
5
|
Home-page: https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-urlopen
|
|
6
6
|
License: MIT
|
|
@@ -21,9 +21,11 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
21
21
|
Classifier: Topic :: Software Development
|
|
22
22
|
Classifier: Topic :: Software Development :: Libraries
|
|
23
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Requires-Dist: brotli
|
|
24
25
|
Requires-Dist: http_response
|
|
25
26
|
Requires-Dist: python-argtools
|
|
26
27
|
Requires-Dist: python-filewrap
|
|
28
|
+
Requires-Dist: zstandard
|
|
27
29
|
Project-URL: Repository, https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-urlopen
|
|
28
30
|
Description-Content-Type: text/markdown
|
|
29
31
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-urlopen"
|
|
3
|
-
version = "0.0.5"
|
|
3
|
+
version = "0.0.5.1"
|
|
4
4
|
description = "Python urlopen wrapper."
|
|
5
5
|
authors = ["ChenyangGao <wosiwujm@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -27,9 +27,11 @@ include = [
|
|
|
27
27
|
|
|
28
28
|
[tool.poetry.dependencies]
|
|
29
29
|
python = "^3.10"
|
|
30
|
+
brotli = "*"
|
|
30
31
|
http_response = "*"
|
|
31
32
|
python-argtools = "*"
|
|
32
33
|
python-filewrap = "*"
|
|
34
|
+
zstandard = "*"
|
|
33
35
|
|
|
34
36
|
[tool.poetry.scripts]
|
|
35
37
|
python-urlopen = "urlopen.__main__:main"
|
|
@@ -9,6 +9,7 @@ import errno
|
|
|
9
9
|
|
|
10
10
|
from collections.abc import Callable, Generator, Iterable, Mapping, Sequence
|
|
11
11
|
from copy import copy
|
|
12
|
+
from gzip import decompress as decompress_gzip
|
|
12
13
|
from http.client import HTTPResponse
|
|
13
14
|
from http.cookiejar import CookieJar
|
|
14
15
|
from inspect import isgenerator
|
|
@@ -22,10 +23,13 @@ from typing import cast, Any
|
|
|
22
23
|
from urllib.error import HTTPError
|
|
23
24
|
from urllib.parse import urlencode, urlsplit
|
|
24
25
|
from urllib.request import build_opener, HTTPCookieProcessor, HTTPSHandler, OpenerDirector, Request
|
|
26
|
+
from zlib import compressobj, DEF_MEM_LEVEL, DEFLATED, MAX_WBITS
|
|
25
27
|
|
|
26
28
|
from argtools import argcount
|
|
29
|
+
from brotli import decompress as decompress_br # type: ignore
|
|
27
30
|
from filewrap import bio_skip_iter, SupportsRead, SupportsWrite
|
|
28
31
|
from http_response import get_filename, get_length, is_chunked, is_range_request
|
|
32
|
+
from zstandard import decompress as decompress_zstd
|
|
29
33
|
|
|
30
34
|
|
|
31
35
|
if "__del__" not in HTTPResponse.__dict__:
|
|
@@ -34,6 +38,43 @@ if "__del__" not in HTTPResponse.__dict__:
|
|
|
34
38
|
CRE_search_charset = re_compile(r"\bcharset=(?P<charset>[^ ;]+)").search
|
|
35
39
|
|
|
36
40
|
|
|
41
|
+
def decompress_deflate(data, compresslevel=9):
|
|
42
|
+
# Fork from: https://stackoverflow.com/questions/1089662/python-inflate-and-deflate-implementations#answer-1089787
|
|
43
|
+
compress = compressobj(
|
|
44
|
+
compresslevel, # level: 0-9
|
|
45
|
+
DEFLATED, # method: must be DEFLATED
|
|
46
|
+
-MAX_WBITS, # window size in bits:
|
|
47
|
+
# -15..-8: negate, suppress header
|
|
48
|
+
# 8..15: normal
|
|
49
|
+
# 16..30: subtract 16, gzip header
|
|
50
|
+
DEF_MEM_LEVEL, # mem level: 1..8/9
|
|
51
|
+
0 # strategy:
|
|
52
|
+
# 0 = Z_DEFAULT_STRATEGY
|
|
53
|
+
# 1 = Z_FILTERED
|
|
54
|
+
# 2 = Z_HUFFMAN_ONLY
|
|
55
|
+
# 3 = Z_RLE
|
|
56
|
+
# 4 = Z_FIXED
|
|
57
|
+
)
|
|
58
|
+
deflated = compress.compress(data)
|
|
59
|
+
deflated += compress.flush()
|
|
60
|
+
return deflated
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def decompress_response(resp: HTTPResponse) -> bytes:
|
|
64
|
+
data = resp.read()
|
|
65
|
+
content_encoding = resp.headers.get("Content-Encoding")
|
|
66
|
+
match content_encoding:
|
|
67
|
+
case "gzip":
|
|
68
|
+
data = decompress_gzip(data)
|
|
69
|
+
case "deflate":
|
|
70
|
+
data = decompress_deflate(data)
|
|
71
|
+
case "br":
|
|
72
|
+
data = decompress_br(data)
|
|
73
|
+
case "zstd":
|
|
74
|
+
data = decompress_zstd(data)
|
|
75
|
+
return data
|
|
76
|
+
|
|
77
|
+
|
|
37
78
|
def urlopen(
|
|
38
79
|
url: str | Request,
|
|
39
80
|
method: str = "GET",
|
|
@@ -136,17 +177,16 @@ def request(
|
|
|
136
177
|
if parse is None:
|
|
137
178
|
return resp
|
|
138
179
|
with resp:
|
|
139
|
-
if parse
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return data.decode(get_charset(content_type))
|
|
180
|
+
if isinstance(parse, bool):
|
|
181
|
+
data = decompress_response(resp)
|
|
182
|
+
if parse is True:
|
|
183
|
+
content_type = resp.headers.get("Content-Type", "")
|
|
184
|
+
if content_type == "application/json":
|
|
185
|
+
return loads(data)
|
|
186
|
+
elif content_type.startswith("application/json;"):
|
|
187
|
+
return loads(data.decode(get_charset(content_type)))
|
|
188
|
+
elif content_type.startswith("text/"):
|
|
189
|
+
return data.decode(get_charset(content_type))
|
|
150
190
|
return data
|
|
151
191
|
else:
|
|
152
192
|
ac = argcount(parse)
|
|
@@ -154,7 +194,7 @@ def request(
|
|
|
154
194
|
if ac == 1:
|
|
155
195
|
return parse(resp)
|
|
156
196
|
else:
|
|
157
|
-
return parse(resp, resp
|
|
197
|
+
return parse(resp, decompress_response(resp))
|
|
158
198
|
|
|
159
199
|
|
|
160
200
|
def download(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|