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.
@@ -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 is False:
140
- return resp.read()
141
- elif parse is True:
142
- data = resp.read()
143
- content_type = resp.headers.get("Content-Type", "")
144
- if content_type == "application/json":
145
- return loads(data)
146
- elif content_type.startswith("application/json;"):
147
- return loads(data.decode(get_charset(content_type)))
148
- elif content_type.startswith("text/"):
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.read())
197
+ return parse(resp, decompress_response(resp))
158
198
 
159
199
 
160
200
  def download(
File without changes