python-httpfile 0.0.1.2__py3-none-any.whl → 0.0.2__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 CHANGED
@@ -2,8 +2,8 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  __author__ = "ChenyangGao <https://chenyanggao.github.io>"
5
- __version__ = (0, 0, 1)
6
- __all__ = ["HTTPFileReader", "RequestsFileReader"]
5
+ __version__ = (0, 0, 2)
6
+ __all__ = ["HTTPFileReader", "AsyncHTTPFileReader"]
7
7
 
8
8
  import errno
9
9
 
@@ -19,12 +19,8 @@ from typing import Any, BinaryIO, IO, Optional, Protocol, Self, TypeVar
19
19
  from types import MappingProxyType
20
20
  from warnings import warn
21
21
 
22
- from aiohttp import ClientSession
23
- from filewrap import bio_skip_iter
24
22
  from http_response import get_filename, get_length, get_range, get_total_length, is_chunked, is_range_request
25
- from iterutils import through
26
23
  from property import funcproperty
27
- from requests import Session
28
24
  from urlopen import urlopen
29
25
 
30
26
 
@@ -107,6 +103,18 @@ class HTTPFileReader(RawIOBase, BinaryIO):
107
103
  headers["Range"] = f"bytes={start}-"
108
104
  elif start < 0:
109
105
  headers["Range"] = f"bytes={start}"
106
+ if callable(url):
107
+ geturl = url
108
+ def url():
109
+ url = geturl()
110
+ headers_extra = getattr(url, "headers")
111
+ if headers_extra:
112
+ headers.update(headers_extra)
113
+ return url
114
+ elif hasattr(url, "headers"):
115
+ headers_extra = getattr(url, "headers")
116
+ if headers_extra:
117
+ headers.update(headers_extra)
110
118
  response = urlopen(url() if callable(url) else url, headers=headers)
111
119
  if start:
112
120
  rng = get_range(response)
@@ -166,8 +174,9 @@ class HTTPFileReader(RawIOBase, BinaryIO):
166
174
  self.__dict__["start"] += delta
167
175
 
168
176
  def close(self, /):
169
- self.response.close()
170
- self.__dict__["closed"] = True
177
+ if not self.closed:
178
+ self.response.close()
179
+ self.__dict__["closed"] = True
171
180
 
172
181
  @funcproperty
173
182
  def closed(self, /):
@@ -216,7 +225,7 @@ class HTTPFileReader(RawIOBase, BinaryIO):
216
225
  def readinto(self, buffer, /) -> int:
217
226
  if self.closed:
218
227
  raise ValueError("I/O operation on closed file.")
219
- if not self.chunked and self.tell() >= self.length:
228
+ if not buffer or not self.chunked and self.tell() >= self.length:
220
229
  return 0
221
230
  if self.file.closed:
222
231
  self.reconnect()
@@ -293,8 +302,16 @@ class HTTPFileReader(RawIOBase, BinaryIO):
293
302
  old_pos = self.tell()
294
303
  if old_pos == pos:
295
304
  return pos
296
- if pos > old_pos and pos - old_pos <= self.seek_threshold:
297
- through(bio_skip_iter(self, pos - old_pos))
305
+ if pos > old_pos and (size := pos - old_pos) <= self.seek_threshold:
306
+ if size <= COPY_BUFSIZE:
307
+ self.read(size)
308
+ else:
309
+ buf = bytearray(COPY_BUFSIZE)
310
+ readinto = self.readinto
311
+ while size > COPY_BUFSIZE:
312
+ readinto(buf)
313
+ size -= COPY_BUFSIZE
314
+ self.read(size)
298
315
  else:
299
316
  self.reconnect(pos)
300
317
  return pos
@@ -369,43 +386,67 @@ class HTTPFileReader(RawIOBase, BinaryIO):
369
386
  return buffer
370
387
 
371
388
 
372
- class RequestsFileReader(HTTPFileReader):
389
+ try:
390
+ from requests import Session
391
+
392
+ class RequestsFileReader(HTTPFileReader):
393
+
394
+ def __init__(
395
+ self,
396
+ /,
397
+ url: str | Callable[[], str],
398
+ headers: Optional[Mapping] = None,
399
+ start: int = 0,
400
+ seek_threshold: int = 1 << 20,
401
+ urlopen: Callable = Session().get,
402
+ ):
403
+ def urlopen_wrapper(url: str, headers: Optional[Mapping] = headers):
404
+ resp = urlopen(url, headers=headers, stream=True)
405
+ resp.raise_for_status()
406
+ return resp
407
+ super().__init__(
408
+ url,
409
+ headers=headers,
410
+ start=start,
411
+ seek_threshold=seek_threshold,
412
+ urlopen=urlopen_wrapper,
413
+ )
373
414
 
374
- def __init__(
375
- self,
376
- /,
377
- url: str | Callable[[], str],
378
- headers: Optional[Mapping] = None,
379
- start: int = 0,
380
- seek_threshold: int = 1 << 20,
381
- urlopen: Callable = Session().get,
382
- ):
383
- def urlopen_wrapper(url: str, headers: Optional[Mapping] = headers):
384
- resp = urlopen(url, headers=headers, stream=True)
385
- resp.raise_for_status()
386
- return resp
387
- super().__init__(
388
- url,
389
- headers=headers,
390
- start=start,
391
- seek_threshold=seek_threshold,
392
- urlopen=urlopen_wrapper,
393
- )
415
+ def _add_start(self, delta: int, /):
416
+ pass
394
417
 
395
- def _add_start(self, delta: int, /):
396
- pass
418
+ @funcproperty
419
+ def file(self, /) -> BinaryIO:
420
+ return self.response.raw
397
421
 
398
- @funcproperty
399
- def file(self, /) -> BinaryIO:
400
- return self.response.raw
422
+ def tell(self, /) -> int:
423
+ start = self.start
424
+ if start >= self.length:
425
+ return start
426
+ return start + self.file.tell()
401
427
 
402
- def tell(self, /) -> int:
403
- start = self.start
404
- if start >= self.length:
405
- return start
406
- return start + self.file.tell()
428
+ __all__.append("RequestsFileReader")
429
+ except ImportError:
430
+ pass
431
+
432
+
433
+ try:
434
+ from aiohttp import ClientSession
435
+
436
+ ...
437
+ except ImportError:
438
+ pass
439
+
440
+
441
+ try:
442
+ from httpx import Client, AsyncClient
443
+
444
+ ...
445
+ except ImportError:
446
+ pass
407
447
 
408
448
 
449
+ # TODO: 实现 AsyncHTTPFileReader
409
450
  # TODO: 支持异步文件,使用 aiohttp,参考 aiofiles 的接口实现
410
451
  # TODO: 设计实现一个 HTTPFileWriter,用于实现上传,关闭后视为上传完成
411
452
 
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-httpfile
3
- Version: 0.0.1.2
4
- Summary: Python httpfile classes.
3
+ Version: 0.0.2
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
7
7
  Keywords: http,file,wrapper
@@ -21,17 +21,13 @@ 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: aiohttp
25
24
  Requires-Dist: http_response
26
- Requires-Dist: python-filewrap
27
- Requires-Dist: python-iterutils
28
25
  Requires-Dist: python-property
29
26
  Requires-Dist: python-urlopen
30
- Requires-Dist: requests
31
27
  Project-URL: Repository, https://github.com/ChenyangGao/web-mount-packs/tree/main/python-module/python-httpfile
32
28
  Description-Content-Type: text/markdown
33
29
 
34
- # Python httpfile classes.
30
+ # Python httpfile.
35
31
 
36
32
  ## Installation
37
33
 
@@ -0,0 +1,7 @@
1
+ LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
2
+ httpfile/__init__.py,sha256=cZZjfftX2nWqEZQ0jjDnrTOW2NLbfnQy8ZEnP52y_tY,13427
3
+ httpfile/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ python_httpfile-0.0.2.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
5
+ python_httpfile-0.0.2.dist-info/METADATA,sha256=-hanQvHDGCiX4-fYjubZmioS7o3nAnGPtSkF47eEXr0,1414
6
+ python_httpfile-0.0.2.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
7
+ python_httpfile-0.0.2.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
2
- httpfile/__init__.py,sha256=QMeil_PlioH8MCXWfK4Pty5hJEPFryrkjXTAy_t2anE,12317
3
- httpfile/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- python_httpfile-0.0.1.2.dist-info/LICENSE,sha256=o5242_N2TgDsWwFhPn7yr8YJNF7XsJM5NxUMtcT97bc,1100
5
- python_httpfile-0.0.1.2.dist-info/METADATA,sha256=mRCnDifm57cPKclZ4pF9B7g2Xc1naxBCfJzeU0sZF3Q,1542
6
- python_httpfile-0.0.1.2.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
7
- python_httpfile-0.0.1.2.dist-info/RECORD,,