python-httpfile 0.0.3__py3-none-any.whl → 0.0.4.1__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.
- httpfile/__init__.py +165 -135
- {python_httpfile-0.0.3.dist-info → python_httpfile-0.0.4.1.dist-info}/METADATA +2 -2
- python_httpfile-0.0.4.1.dist-info/RECORD +7 -0
- python_httpfile-0.0.3.dist-info/RECORD +0 -7
- {python_httpfile-0.0.3.dist-info → python_httpfile-0.0.4.1.dist-info}/LICENSE +0 -0
- {python_httpfile-0.0.3.dist-info → python_httpfile-0.0.4.1.dist-info}/WHEEL +0 -0
httpfile/__init__.py
CHANGED
|
@@ -4,14 +4,15 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
__author__ = "ChenyangGao <https://chenyanggao.github.io>"
|
|
7
|
-
__version__ = (0, 0,
|
|
7
|
+
__version__ = (0, 0, 4)
|
|
8
8
|
__all__ = ["HTTPFileReader", "AsyncHTTPFileReader"]
|
|
9
9
|
|
|
10
10
|
import errno
|
|
11
11
|
|
|
12
12
|
from collections.abc import Awaitable, Callable, Mapping
|
|
13
13
|
from functools import cached_property, partial
|
|
14
|
-
from
|
|
14
|
+
from importlib.util import find_spec
|
|
15
|
+
from inspect import isawaitable
|
|
15
16
|
from io import (
|
|
16
17
|
BufferedReader, RawIOBase, TextIOWrapper, UnsupportedOperation, DEFAULT_BUFFER_SIZE,
|
|
17
18
|
)
|
|
@@ -19,7 +20,7 @@ from os import fstat, stat, PathLike
|
|
|
19
20
|
from shutil import COPY_BUFSIZE # type: ignore
|
|
20
21
|
from sys import exc_info
|
|
21
22
|
from typing import cast, overload, Any, BinaryIO, Literal, Self
|
|
22
|
-
from types import MappingProxyType
|
|
23
|
+
from types import MappingProxyType
|
|
23
24
|
from warnings import warn
|
|
24
25
|
|
|
25
26
|
from asynctools import ensure_async, run_async
|
|
@@ -102,7 +103,7 @@ class HTTPFileReader(RawIOBase, BinaryIO):
|
|
|
102
103
|
# NOTE: If the offset of the forward seek is not higher than this value,
|
|
103
104
|
# it will be directly read and discarded, default to 1 MB
|
|
104
105
|
seek_threshold: int = 1 << 20,
|
|
105
|
-
urlopen
|
|
106
|
+
urlopen = urlopen,
|
|
106
107
|
):
|
|
107
108
|
if headers:
|
|
108
109
|
headers = {**headers, "Accept-Encoding": "identity"}
|
|
@@ -112,6 +113,8 @@ class HTTPFileReader(RawIOBase, BinaryIO):
|
|
|
112
113
|
headers["Range"] = f"bytes={start}-"
|
|
113
114
|
elif start < 0:
|
|
114
115
|
headers["Range"] = f"bytes={start}"
|
|
116
|
+
if urlopen is None:
|
|
117
|
+
urlopen = globals()["urlopen"]
|
|
115
118
|
if callable(url):
|
|
116
119
|
geturl = url
|
|
117
120
|
def url():
|
|
@@ -250,7 +253,16 @@ class HTTPFileReader(RawIOBase, BinaryIO):
|
|
|
250
253
|
return 0
|
|
251
254
|
if self.file_closed:
|
|
252
255
|
self.reconnect()
|
|
253
|
-
|
|
256
|
+
try:
|
|
257
|
+
readinto = self.file.readinto
|
|
258
|
+
except AttributeError:
|
|
259
|
+
read = self.file.read
|
|
260
|
+
def readinto(buffer, /):
|
|
261
|
+
data = read(len(buffer))
|
|
262
|
+
size = len(data)
|
|
263
|
+
buffer[:size] = data
|
|
264
|
+
return data
|
|
265
|
+
size = readinto(buffer)
|
|
254
266
|
if size:
|
|
255
267
|
self._add_start(size)
|
|
256
268
|
return size
|
|
@@ -262,6 +274,7 @@ class HTTPFileReader(RawIOBase, BinaryIO):
|
|
|
262
274
|
return b""
|
|
263
275
|
if self.file_closed:
|
|
264
276
|
self.reconnect()
|
|
277
|
+
# TODO: if no readline method, give a default impl
|
|
265
278
|
if size is None or size < 0:
|
|
266
279
|
data = self.file.readline()
|
|
267
280
|
else:
|
|
@@ -277,6 +290,7 @@ class HTTPFileReader(RawIOBase, BinaryIO):
|
|
|
277
290
|
return []
|
|
278
291
|
if self.file_closed:
|
|
279
292
|
self.reconnect()
|
|
293
|
+
# TODO: if no readlines method, give a default impl
|
|
280
294
|
ls = self.file.readlines(hint)
|
|
281
295
|
if ls:
|
|
282
296
|
self._add_start(sum(map(len, ls)))
|
|
@@ -384,7 +398,7 @@ class HTTPFileReader(RawIOBase, BinaryIO):
|
|
|
384
398
|
headers: None | Mapping = None,
|
|
385
399
|
start: int = 0,
|
|
386
400
|
seek_threshold: int = 1 << 20,
|
|
387
|
-
urlopen
|
|
401
|
+
urlopen = None,
|
|
388
402
|
) -> Self | BufferedReader:
|
|
389
403
|
...
|
|
390
404
|
@overload
|
|
@@ -402,7 +416,7 @@ class HTTPFileReader(RawIOBase, BinaryIO):
|
|
|
402
416
|
headers: None | Mapping = None,
|
|
403
417
|
start: int = 0,
|
|
404
418
|
seek_threshold: int = 1 << 20,
|
|
405
|
-
urlopen
|
|
419
|
+
urlopen = None,
|
|
406
420
|
) -> TextIOWrapper:
|
|
407
421
|
...
|
|
408
422
|
@classmethod
|
|
@@ -419,7 +433,7 @@ class HTTPFileReader(RawIOBase, BinaryIO):
|
|
|
419
433
|
headers: None | Mapping = None,
|
|
420
434
|
start: int = 0,
|
|
421
435
|
seek_threshold: int = 1 << 20,
|
|
422
|
-
urlopen
|
|
436
|
+
urlopen = None,
|
|
423
437
|
) -> Self | BufferedReader | TextIOWrapper:
|
|
424
438
|
file = cls(
|
|
425
439
|
url=url,
|
|
@@ -517,9 +531,9 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
517
531
|
headers: None | Mapping = None,
|
|
518
532
|
start: int = 0,
|
|
519
533
|
seek_threshold: int = 1 << 20,
|
|
520
|
-
urlopen
|
|
534
|
+
urlopen = None,
|
|
521
535
|
):
|
|
522
|
-
run_async(self.
|
|
536
|
+
run_async(self.__ainit__(
|
|
523
537
|
url=url,
|
|
524
538
|
headers=headers,
|
|
525
539
|
start=start,
|
|
@@ -542,7 +556,7 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
542
556
|
else:
|
|
543
557
|
raise StopAsyncIteration
|
|
544
558
|
|
|
545
|
-
async def
|
|
559
|
+
async def __ainit__(
|
|
546
560
|
self,
|
|
547
561
|
/,
|
|
548
562
|
url: str | Callable[[], str] | Callable[[], Awaitable[str]],
|
|
@@ -551,8 +565,6 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
551
565
|
seek_threshold: int = 1 << 20,
|
|
552
566
|
urlopen = None,
|
|
553
567
|
):
|
|
554
|
-
if urlopen is None:
|
|
555
|
-
urlopen = signature(type(self).__init__).parameters["urlopen"].default
|
|
556
568
|
if headers:
|
|
557
569
|
headers = {**headers, "Accept-Encoding": "identity"}
|
|
558
570
|
else:
|
|
@@ -561,6 +573,8 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
561
573
|
headers["Range"] = f"bytes={start}-"
|
|
562
574
|
elif start < 0:
|
|
563
575
|
headers["Range"] = f"bytes={start}"
|
|
576
|
+
if urlopen is None:
|
|
577
|
+
urlopen = globals()["urlopen"]
|
|
564
578
|
if callable(url):
|
|
565
579
|
geturl = url
|
|
566
580
|
async def url() -> str:
|
|
@@ -628,10 +642,11 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
628
642
|
return b""
|
|
629
643
|
if self.file_closed:
|
|
630
644
|
await self.reconnect()
|
|
645
|
+
read = ensure_async(self.file.read, threaded=True)
|
|
631
646
|
if size is None or size < 0:
|
|
632
|
-
data = await
|
|
647
|
+
data = await read(-1)
|
|
633
648
|
else:
|
|
634
|
-
data = await
|
|
649
|
+
data = await read(size)
|
|
635
650
|
if data:
|
|
636
651
|
self._add_start(len(data))
|
|
637
652
|
return data
|
|
@@ -643,7 +658,16 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
643
658
|
return 0
|
|
644
659
|
if self.file_closed:
|
|
645
660
|
await self.reconnect()
|
|
646
|
-
|
|
661
|
+
try:
|
|
662
|
+
readinto = ensure_async(self.file.readinto, threaded=True)
|
|
663
|
+
except AttributeError:
|
|
664
|
+
read = ensure_async(self.file.read, threaded=True)
|
|
665
|
+
async def readinto(buffer, /):
|
|
666
|
+
data = await read(len(buffer))
|
|
667
|
+
size = len(data)
|
|
668
|
+
buffer[:size] = data
|
|
669
|
+
return size
|
|
670
|
+
size = await readinto(buffer)
|
|
647
671
|
if size:
|
|
648
672
|
self._add_start(size)
|
|
649
673
|
return size
|
|
@@ -655,6 +679,7 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
655
679
|
return b""
|
|
656
680
|
if self.file_closed:
|
|
657
681
|
await self.reconnect()
|
|
682
|
+
# TODO: if no readline method, give a default impl
|
|
658
683
|
if size is None or size < 0:
|
|
659
684
|
data = await ensure_async(self.file.readline, threaded=True)()
|
|
660
685
|
else:
|
|
@@ -670,6 +695,7 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
670
695
|
return []
|
|
671
696
|
if self.file_closed:
|
|
672
697
|
await self.reconnect()
|
|
698
|
+
# TODO: if no readlines method, give a default impl
|
|
673
699
|
ls = await ensure_async(self.file.readlines, threaded=True)(hint)
|
|
674
700
|
if ls:
|
|
675
701
|
self._add_start(sum(map(len, ls)))
|
|
@@ -749,7 +775,7 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
749
775
|
urlopen = None,
|
|
750
776
|
) -> Self: # type: ignore
|
|
751
777
|
self = cls.__new__(cls)
|
|
752
|
-
await self.
|
|
778
|
+
await self.__ainit__(
|
|
753
779
|
url=url,
|
|
754
780
|
headers=headers,
|
|
755
781
|
start=start,
|
|
@@ -773,7 +799,7 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
773
799
|
headers: None | Mapping = None,
|
|
774
800
|
start: int = 0,
|
|
775
801
|
seek_threshold: int = 1 << 20,
|
|
776
|
-
urlopen
|
|
802
|
+
urlopen = None,
|
|
777
803
|
) -> Self | AsyncBufferedReader:
|
|
778
804
|
...
|
|
779
805
|
@overload
|
|
@@ -791,7 +817,7 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
791
817
|
headers: None | Mapping = None,
|
|
792
818
|
start: int = 0,
|
|
793
819
|
seek_threshold: int = 1 << 20,
|
|
794
|
-
urlopen
|
|
820
|
+
urlopen = None,
|
|
795
821
|
) -> AsyncTextIOWrapper:
|
|
796
822
|
...
|
|
797
823
|
@classmethod
|
|
@@ -807,7 +833,7 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
807
833
|
headers: None | Mapping = None,
|
|
808
834
|
start: int = 0,
|
|
809
835
|
seek_threshold: int = 1 << 20,
|
|
810
|
-
urlopen
|
|
836
|
+
urlopen = None,
|
|
811
837
|
) -> Self | AsyncBufferedReader | AsyncTextIOWrapper:
|
|
812
838
|
file = await cls.new(
|
|
813
839
|
url=url,
|
|
@@ -895,10 +921,10 @@ class AsyncHTTPFileReader(HTTPFileReader):
|
|
|
895
921
|
return buffer
|
|
896
922
|
|
|
897
923
|
|
|
898
|
-
|
|
924
|
+
if find_spec("urllib3"):
|
|
899
925
|
from urllib.error import HTTPError
|
|
900
|
-
|
|
901
|
-
|
|
926
|
+
|
|
927
|
+
_urllib3_urlopen = None
|
|
902
928
|
|
|
903
929
|
class Urllib3FileReader(HTTPFileReader):
|
|
904
930
|
|
|
@@ -909,17 +935,28 @@ try:
|
|
|
909
935
|
headers: None | Mapping = None,
|
|
910
936
|
start: int = 0,
|
|
911
937
|
seek_threshold: int = 1 << 20,
|
|
912
|
-
urlopen =
|
|
938
|
+
urlopen = None,
|
|
913
939
|
):
|
|
940
|
+
global _urllib3_urlopen
|
|
941
|
+
from urllib3 import request
|
|
942
|
+
from urllib3.poolmanager import PoolManager
|
|
943
|
+
|
|
914
944
|
if isinstance(urlopen, PoolManager):
|
|
915
945
|
urlopen = partial(urlopen.request, "GET", preload_content=False)
|
|
946
|
+
elif urlopen is None:
|
|
947
|
+
if _urllib3_urlopen is None:
|
|
948
|
+
urlopen = _urllib3_urlopen = partial(cast(Callable, request), "GET", preload_content=False)
|
|
949
|
+
else:
|
|
950
|
+
urlopen = _urllib3_urlopen
|
|
916
951
|
else:
|
|
917
952
|
urlopen = partial(urlopen, preload_content=False)
|
|
953
|
+
|
|
918
954
|
def urlopen_wrapper(url: str, headers: None | Mapping = headers):
|
|
919
955
|
resp = urlopen(url, headers=headers)
|
|
920
956
|
if resp.status >= 400:
|
|
921
957
|
raise HTTPError(resp.url, resp.status, resp.reason, resp.headers, resp)
|
|
922
958
|
return resp
|
|
959
|
+
|
|
923
960
|
super().__init__(
|
|
924
961
|
url,
|
|
925
962
|
headers=headers,
|
|
@@ -929,15 +966,10 @@ try:
|
|
|
929
966
|
)
|
|
930
967
|
|
|
931
968
|
__all__.append("Urllib3FileReader")
|
|
932
|
-
except ImportError:
|
|
933
|
-
pass
|
|
934
969
|
|
|
935
970
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
if "__del__" not in Session.__dict__:
|
|
940
|
-
setattr(Session, "__del__", lambda self, /: self.close())
|
|
971
|
+
if find_spec("requests"):
|
|
972
|
+
_requests_urlopen = None
|
|
941
973
|
|
|
942
974
|
class RequestsFileReader(HTTPFileReader):
|
|
943
975
|
|
|
@@ -948,10 +980,19 @@ try:
|
|
|
948
980
|
headers: None | Mapping = None,
|
|
949
981
|
start: int = 0,
|
|
950
982
|
seek_threshold: int = 1 << 20,
|
|
951
|
-
urlopen =
|
|
983
|
+
urlopen = None,
|
|
952
984
|
):
|
|
985
|
+
global _requests_urlopen
|
|
986
|
+
from requests import request, Session
|
|
953
987
|
if isinstance(urlopen, Session):
|
|
954
988
|
urlopen = partial(urlopen.request, "GET", stream=True)
|
|
989
|
+
elif urlopen is None:
|
|
990
|
+
if _requests_urlopen is None:
|
|
991
|
+
if "__del__" not in Session.__dict__:
|
|
992
|
+
setattr(Session, "__del__", lambda self, /: self.close())
|
|
993
|
+
urlopen = _requests_urlopen = partial(request, "GET", stream=True)
|
|
994
|
+
else:
|
|
995
|
+
urlopen = _requests_urlopen
|
|
955
996
|
else:
|
|
956
997
|
urlopen = partial(urlopen, stream=True)
|
|
957
998
|
def urlopen_wrapper(url: str, headers: None | Mapping = headers):
|
|
@@ -971,33 +1012,16 @@ try:
|
|
|
971
1012
|
return self.response.raw
|
|
972
1013
|
|
|
973
1014
|
__all__.append("RequestsFileReader")
|
|
974
|
-
except ImportError:
|
|
975
|
-
pass
|
|
976
1015
|
|
|
977
1016
|
|
|
978
|
-
|
|
979
|
-
from
|
|
1017
|
+
if find_spec("aiohttp"):
|
|
1018
|
+
from types import MethodType
|
|
980
1019
|
|
|
981
|
-
|
|
1020
|
+
_aiohttp_urlopen = None
|
|
982
1021
|
|
|
983
|
-
|
|
984
|
-
self,
|
|
985
|
-
/,
|
|
986
|
-
url: str | Callable[[], str] | Callable[[], Awaitable[str]],
|
|
987
|
-
headers: None | Mapping = None,
|
|
988
|
-
start: int = 0,
|
|
989
|
-
seek_threshold: int = 1 << 20,
|
|
990
|
-
urlopen = partial(aiohttp_request, "GET"),
|
|
991
|
-
):
|
|
992
|
-
super().__init__(
|
|
993
|
-
url=url,
|
|
994
|
-
headers=headers,
|
|
995
|
-
start=start,
|
|
996
|
-
seek_threshold=seek_threshold,
|
|
997
|
-
urlopen=urlopen,
|
|
998
|
-
)
|
|
1022
|
+
class AiohttpFileReader(AsyncHTTPFileReader):
|
|
999
1023
|
|
|
1000
|
-
async def
|
|
1024
|
+
async def __ainit__(
|
|
1001
1025
|
self,
|
|
1002
1026
|
/,
|
|
1003
1027
|
url: str | Callable[[], str] | Callable[[], Awaitable[str]],
|
|
@@ -1006,17 +1030,26 @@ try:
|
|
|
1006
1030
|
seek_threshold: int = 1 << 20,
|
|
1007
1031
|
urlopen = None,
|
|
1008
1032
|
):
|
|
1009
|
-
|
|
1010
|
-
|
|
1033
|
+
global _aiohttp_urlopen
|
|
1034
|
+
from aiohttp import request, ClientSession
|
|
1035
|
+
|
|
1011
1036
|
close_session = True
|
|
1012
1037
|
if isinstance(urlopen, ClientSession):
|
|
1013
1038
|
urlopen = urlopen.get
|
|
1014
|
-
|
|
1015
|
-
if
|
|
1039
|
+
close_session = False
|
|
1040
|
+
if urlopen is None:
|
|
1041
|
+
if _aiohttp_urlopen is None:
|
|
1042
|
+
urlopen = _aiohttp_urlopen = partial(request, "GET")
|
|
1043
|
+
else:
|
|
1044
|
+
urlopen = _aiohttp_urlopen
|
|
1045
|
+
else:
|
|
1016
1046
|
func = urlopen
|
|
1017
1047
|
if isinstance(func, partial):
|
|
1018
1048
|
func = func.func
|
|
1019
|
-
close_session = not (
|
|
1049
|
+
close_session = not (
|
|
1050
|
+
isinstance(func, MethodType) and
|
|
1051
|
+
isinstance(func.__self__, ClientSession)
|
|
1052
|
+
)
|
|
1020
1053
|
async def urlopen_wrapper(url: str, headers: None | Mapping = headers):
|
|
1021
1054
|
resp = await urlopen(url, headers=headers).__aenter__()
|
|
1022
1055
|
async def aclose():
|
|
@@ -1029,7 +1062,7 @@ try:
|
|
|
1029
1062
|
resp.aclose = aclose
|
|
1030
1063
|
resp.raise_for_status()
|
|
1031
1064
|
return resp
|
|
1032
|
-
await super().
|
|
1065
|
+
await super().__ainit__(
|
|
1033
1066
|
url=url,
|
|
1034
1067
|
headers=headers,
|
|
1035
1068
|
start=start,
|
|
@@ -1046,60 +1079,13 @@ try:
|
|
|
1046
1079
|
return self.response.closed
|
|
1047
1080
|
|
|
1048
1081
|
__all__.append("AiohttpFileReader")
|
|
1049
|
-
except ImportError:
|
|
1050
|
-
pass
|
|
1051
1082
|
|
|
1052
1083
|
|
|
1053
|
-
|
|
1054
|
-
from contextlib import asynccontextmanager
|
|
1084
|
+
if find_spec("httpx"):
|
|
1055
1085
|
from filewrap import bytes_iter_to_reader, bytes_iter_to_async_reader
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
setattr(Client, "__del__", lambda self: self.close())
|
|
1060
|
-
if "__del__" not in AsyncClient.__dict__:
|
|
1061
|
-
setattr(AsyncClient, "__del__", lambda self: run_async(self.aclose()))
|
|
1062
|
-
|
|
1063
|
-
def async_stream(
|
|
1064
|
-
method,
|
|
1065
|
-
url,
|
|
1066
|
-
params = None,
|
|
1067
|
-
content = None,
|
|
1068
|
-
data = None,
|
|
1069
|
-
files = None,
|
|
1070
|
-
json = None,
|
|
1071
|
-
headers = None,
|
|
1072
|
-
cookies = None,
|
|
1073
|
-
auth = None,
|
|
1074
|
-
proxy = None,
|
|
1075
|
-
proxies = None,
|
|
1076
|
-
timeout = 5.0,
|
|
1077
|
-
follow_redirects = False,
|
|
1078
|
-
verify = True,
|
|
1079
|
-
cert = None,
|
|
1080
|
-
trust_env = True,
|
|
1081
|
-
):
|
|
1082
|
-
client = AsyncClient(
|
|
1083
|
-
cookies=cookies,
|
|
1084
|
-
proxy=proxy,
|
|
1085
|
-
proxies=proxies,
|
|
1086
|
-
cert=cert,
|
|
1087
|
-
verify=verify,
|
|
1088
|
-
timeout=timeout,
|
|
1089
|
-
trust_env=trust_env,
|
|
1090
|
-
)
|
|
1091
|
-
return client.stream(
|
|
1092
|
-
method=method,
|
|
1093
|
-
url=url,
|
|
1094
|
-
content=content,
|
|
1095
|
-
data=data,
|
|
1096
|
-
files=files,
|
|
1097
|
-
json=json,
|
|
1098
|
-
params=params,
|
|
1099
|
-
headers=headers,
|
|
1100
|
-
auth=auth,
|
|
1101
|
-
follow_redirects=follow_redirects,
|
|
1102
|
-
)
|
|
1086
|
+
|
|
1087
|
+
_httpx_urlopen = None
|
|
1088
|
+
_httpx_urlopen_async = None
|
|
1103
1089
|
|
|
1104
1090
|
class HttpxFileReader(HTTPFileReader):
|
|
1105
1091
|
|
|
@@ -1110,10 +1096,21 @@ try:
|
|
|
1110
1096
|
headers: None | Mapping = None,
|
|
1111
1097
|
start: int = 0,
|
|
1112
1098
|
seek_threshold: int = 1 << 20,
|
|
1113
|
-
urlopen =
|
|
1099
|
+
urlopen = None,
|
|
1114
1100
|
):
|
|
1101
|
+
global _httpx_urlopen
|
|
1102
|
+
from httpx import stream, Client
|
|
1103
|
+
|
|
1115
1104
|
if isinstance(urlopen, Client):
|
|
1116
1105
|
urlopen = partial(urlopen.stream, "GET")
|
|
1106
|
+
elif urlopen is None:
|
|
1107
|
+
if _httpx_urlopen is None:
|
|
1108
|
+
if "__del__" not in Client.__dict__:
|
|
1109
|
+
setattr(Client, "__del__", lambda self: self.close())
|
|
1110
|
+
urlopen = _httpx_urlopen = partial(stream, "GET")
|
|
1111
|
+
else:
|
|
1112
|
+
urlopen = _httpx_urlopen
|
|
1113
|
+
|
|
1117
1114
|
def urlopen_wrapper(url: str, headers: None | Mapping = headers):
|
|
1118
1115
|
context = urlopen(url, headers=headers)
|
|
1119
1116
|
resp = context.__enter__()
|
|
@@ -1122,6 +1119,7 @@ try:
|
|
|
1122
1119
|
file = bytes_iter_to_reader(resp.iter_raw())
|
|
1123
1120
|
self.__dict__["file"] = file
|
|
1124
1121
|
return resp
|
|
1122
|
+
|
|
1125
1123
|
super().__init__(
|
|
1126
1124
|
url,
|
|
1127
1125
|
headers=headers,
|
|
@@ -1136,24 +1134,7 @@ try:
|
|
|
1136
1134
|
|
|
1137
1135
|
class AsyncHttpxFileReader(AsyncHTTPFileReader):
|
|
1138
1136
|
|
|
1139
|
-
def
|
|
1140
|
-
self,
|
|
1141
|
-
/,
|
|
1142
|
-
url: str | Callable[[], str] | Callable[[], Awaitable[str]],
|
|
1143
|
-
headers: None | Mapping = None,
|
|
1144
|
-
start: int = 0,
|
|
1145
|
-
seek_threshold: int = 1 << 20,
|
|
1146
|
-
urlopen = partial(async_stream, "GET"),
|
|
1147
|
-
):
|
|
1148
|
-
super().__init__(
|
|
1149
|
-
url=url,
|
|
1150
|
-
headers=headers,
|
|
1151
|
-
start=start,
|
|
1152
|
-
seek_threshold=seek_threshold,
|
|
1153
|
-
urlopen=urlopen,
|
|
1154
|
-
)
|
|
1155
|
-
|
|
1156
|
-
async def _init(
|
|
1137
|
+
async def __ainit__(
|
|
1157
1138
|
self,
|
|
1158
1139
|
/,
|
|
1159
1140
|
url: str | Callable[[], str] | Callable[[], Awaitable[str]],
|
|
@@ -1162,10 +1143,59 @@ try:
|
|
|
1162
1143
|
seek_threshold: int = 1 << 20,
|
|
1163
1144
|
urlopen = None,
|
|
1164
1145
|
):
|
|
1165
|
-
|
|
1166
|
-
|
|
1146
|
+
global _httpx_urlopen_async
|
|
1147
|
+
from httpx import AsyncClient
|
|
1148
|
+
|
|
1167
1149
|
if isinstance(urlopen, AsyncClient):
|
|
1168
1150
|
urlopen = partial(urlopen.stream, "GET")
|
|
1151
|
+
elif urlopen is None:
|
|
1152
|
+
if _httpx_urlopen_async is None:
|
|
1153
|
+
if "__del__" not in AsyncClient.__dict__:
|
|
1154
|
+
setattr(AsyncClient, "__del__", lambda self: run_async(self.aclose()))
|
|
1155
|
+
def async_stream(
|
|
1156
|
+
method,
|
|
1157
|
+
url,
|
|
1158
|
+
params = None,
|
|
1159
|
+
content = None,
|
|
1160
|
+
data = None,
|
|
1161
|
+
files = None,
|
|
1162
|
+
json = None,
|
|
1163
|
+
headers = None,
|
|
1164
|
+
cookies = None,
|
|
1165
|
+
auth = None,
|
|
1166
|
+
proxy = None,
|
|
1167
|
+
proxies = None,
|
|
1168
|
+
timeout = 5.0,
|
|
1169
|
+
follow_redirects = False,
|
|
1170
|
+
verify = True,
|
|
1171
|
+
cert = None,
|
|
1172
|
+
trust_env = True,
|
|
1173
|
+
):
|
|
1174
|
+
client = AsyncClient(
|
|
1175
|
+
cookies=cookies,
|
|
1176
|
+
proxy=proxy,
|
|
1177
|
+
proxies=proxies,
|
|
1178
|
+
cert=cert,
|
|
1179
|
+
verify=verify,
|
|
1180
|
+
timeout=timeout,
|
|
1181
|
+
trust_env=trust_env,
|
|
1182
|
+
)
|
|
1183
|
+
return client.stream(
|
|
1184
|
+
method=method,
|
|
1185
|
+
url=url,
|
|
1186
|
+
content=content,
|
|
1187
|
+
data=data,
|
|
1188
|
+
files=files,
|
|
1189
|
+
json=json,
|
|
1190
|
+
params=params,
|
|
1191
|
+
headers=headers,
|
|
1192
|
+
auth=auth,
|
|
1193
|
+
follow_redirects=follow_redirects,
|
|
1194
|
+
)
|
|
1195
|
+
urlopen = _httpx_urlopen_async = partial(async_stream, "GET")
|
|
1196
|
+
else:
|
|
1197
|
+
urlopen = _httpx_urlopen_async
|
|
1198
|
+
|
|
1169
1199
|
async def urlopen_wrapper(url: str, headers: None | Mapping = headers):
|
|
1170
1200
|
context = urlopen(url, headers=headers)
|
|
1171
1201
|
resp = await context.__aenter__()
|
|
@@ -1174,7 +1204,8 @@ try:
|
|
|
1174
1204
|
file = bytes_iter_to_async_reader(resp.aiter_raw())
|
|
1175
1205
|
self.__dict__["file"] = file
|
|
1176
1206
|
return resp
|
|
1177
|
-
|
|
1207
|
+
|
|
1208
|
+
await super().__ainit__(
|
|
1178
1209
|
url=url,
|
|
1179
1210
|
headers=headers,
|
|
1180
1211
|
start=start,
|
|
@@ -1188,7 +1219,6 @@ try:
|
|
|
1188
1219
|
|
|
1189
1220
|
__all__.append("HttpxFileReader")
|
|
1190
1221
|
__all__.append("AsyncHttpxFileReader")
|
|
1191
|
-
except ImportError:
|
|
1192
|
-
pass
|
|
1193
1222
|
|
|
1223
|
+
# TODO: 增加 blacksheep 的 HTTPFileReader
|
|
1194
1224
|
# TODO: 设计实现一个 HTTPFileWriter,用于实现上传,关闭后视为上传完成
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-httpfile
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4.1
|
|
4
4
|
Summary: Python httpfile.
|
|
5
5
|
Home-page: https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-httpfile
|
|
6
6
|
License: MIT
|
|
@@ -25,7 +25,7 @@ Requires-Dist: http_response
|
|
|
25
25
|
Requires-Dist: python-asynctools (>=0.0.5)
|
|
26
26
|
Requires-Dist: python-filewrap (>=0.2.1)
|
|
27
27
|
Requires-Dist: python-property (>=0.0.2)
|
|
28
|
-
Requires-Dist: python-urlopen (>=0.0.7)
|
|
28
|
+
Requires-Dist: python-urlopen (>=0.0.7.1)
|
|
29
29
|
Project-URL: Repository, https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-httpfile
|
|
30
30
|
Description-Content-Type: text/markdown
|
|
31
31
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
|
|
2
|
+
httpfile/__init__.py,sha256=ffww3j6Gk2dFLSy18a1PlRlT-yez5V857HbZp080Bxs,39533
|
|
3
|
+
httpfile/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
python_httpfile-0.0.4.1.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
|
|
5
|
+
python_httpfile-0.0.4.1.dist-info/METADATA,sha256=XreyhqBNvwXua7uaRsVBHkf88xLuhhi2Vmd4UAe5eEk,1522
|
|
6
|
+
python_httpfile-0.0.4.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
7
|
+
python_httpfile-0.0.4.1.dist-info/RECORD,,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
|
|
2
|
-
httpfile/__init__.py,sha256=Cp1mdmn7hLNIUsvScclByZZC0hNZh-ggljiYFH1PLVU,37815
|
|
3
|
-
httpfile/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
python_httpfile-0.0.3.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
|
|
5
|
-
python_httpfile-0.0.3.dist-info/METADATA,sha256=5a1WYcujAY1_K8zdnseHhqzSjrUSPaw_a8sc78kR3lM,1518
|
|
6
|
-
python_httpfile-0.0.3.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
7
|
-
python_httpfile-0.0.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|