p115client 0.0.5.8.2__tar.gz → 0.0.5.8.4__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.
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/PKG-INFO +2 -2
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/_upload.py +75 -51
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/client.py +332 -204
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/download.py +180 -41
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/pyproject.toml +2 -2
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/LICENSE +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/__init__.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/const.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/exception.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/py.typed +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/__init__.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/edit.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/export_dir.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/fs_files.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/iterdir.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/life.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/pool.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/request.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/upload.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/tool/xys.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/p115client/type.py +0 -0
- {p115client-0.0.5.8.2 → p115client-0.0.5.8.4}/readme.md +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: p115client
|
3
|
-
Version: 0.0.5.8.
|
3
|
+
Version: 0.0.5.8.4
|
4
4
|
Summary: Python 115 webdisk client.
|
5
5
|
Home-page: https://github.com/ChenyangGao/p115client
|
6
6
|
License: MIT
|
@@ -40,7 +40,7 @@ Requires-Dist: python-filewrap (>=0.2.8)
|
|
40
40
|
Requires-Dist: python-hashtools (>=0.0.3.3)
|
41
41
|
Requires-Dist: python-http_request (>=0.0.6)
|
42
42
|
Requires-Dist: python-httpfile (>=0.0.5.2)
|
43
|
-
Requires-Dist: python-iterutils (>=0.1.
|
43
|
+
Requires-Dist: python-iterutils (>=0.1.10)
|
44
44
|
Requires-Dist: python-property (>=0.0.3)
|
45
45
|
Requires-Dist: python-startfile (>=0.0.2)
|
46
46
|
Requires-Dist: python-undefined (>=0.0.3)
|
@@ -10,8 +10,8 @@ __all__ = [
|
|
10
10
|
|
11
11
|
from base64 import b64encode
|
12
12
|
from collections.abc import (
|
13
|
-
AsyncGenerator, AsyncIterable, AsyncIterator, Awaitable,
|
14
|
-
ItemsView, Iterable, Iterator, Mapping, Sequence, Sized,
|
13
|
+
AsyncGenerator, AsyncIterable, AsyncIterator, Awaitable, Buffer, Callable,
|
14
|
+
Coroutine, Generator, ItemsView, Iterable, Iterator, Mapping, Sequence, Sized,
|
15
15
|
)
|
16
16
|
from datetime import datetime
|
17
17
|
from email.utils import formatdate
|
@@ -25,7 +25,7 @@ from xml.etree.ElementTree import fromstring
|
|
25
25
|
|
26
26
|
from asynctools import ensure_aiter, ensure_async
|
27
27
|
from filewrap import (
|
28
|
-
|
28
|
+
SupportsRead, buffer_length,
|
29
29
|
bio_chunk_iter, bio_chunk_async_iter,
|
30
30
|
bio_skip_iter, bio_skip_async_iter,
|
31
31
|
bytes_iter_to_async_reader, bytes_iter_to_reader,
|
@@ -41,20 +41,13 @@ from .exception import MultipartUploadAbort
|
|
41
41
|
from .type import MultipartResumeData
|
42
42
|
|
43
43
|
|
44
|
-
def
|
45
|
-
if isinstance(b, Sized):
|
46
|
-
return len(b)
|
47
|
-
else:
|
48
|
-
return len(memoryview(b))
|
49
|
-
|
50
|
-
|
51
|
-
def to_base64(s: bytes | str, /) -> str:
|
44
|
+
def to_base64(s: Buffer | str, /) -> str:
|
52
45
|
if isinstance(s, str):
|
53
46
|
s = bytes(s, "utf-8")
|
54
47
|
return str(b64encode(s), "ascii")
|
55
48
|
|
56
49
|
|
57
|
-
def
|
50
|
+
def maybe_integer(n: int | str, /) -> int | str:
|
58
51
|
if isinstance(n, str) and n.isdecimal():
|
59
52
|
n = int(n)
|
60
53
|
return n
|
@@ -155,19 +148,19 @@ def oss_upload_sign(
|
|
155
148
|
# "replicationProgress", "requestPayment", "requesterQosInfo", "resourceGroup", "resourcePool",
|
156
149
|
# "resourcePoolBuckets", "resourcePoolInfo", "response-cache-control", "response-content-disposition",
|
157
150
|
# "response-content-encoding", "response-content-language", "response-content-type", "response-expires",
|
158
|
-
# "restore", "security-token", "sequential", "startTime", "stat", "status", "style", "styleName",
|
159
|
-
# "tagging", "transferAcceleration", "uploadId", "uploads", "versionId", "versioning",
|
160
|
-
# "website", "worm", "wormExtend", "wormId", "x-oss-ac-forward-allow",
|
161
|
-
# "x-oss-ac-
|
162
|
-
# "x-oss-
|
163
|
-
# "x-oss-traffic-limit", "x-oss-write-get-object-response",
|
151
|
+
# "restore", "security-token", "sequential", "startTime", "stat", "status", "style", "styleName",
|
152
|
+
# "symlink", "tagging", "transferAcceleration", "uploadId", "uploads", "versionId", "versioning",
|
153
|
+
# "versions", "vod", "website", "worm", "wormExtend", "wormId", "x-oss-ac-forward-allow",
|
154
|
+
# "x-oss-ac-source-ip", "x-oss-ac-subnet-mask", "x-oss-ac-vpc-id", "x-oss-access-point-name",
|
155
|
+
# "x-oss-async-process", "x-oss-process", "x-oss-redundancy-transition-taskid", "x-oss-request-payer",
|
156
|
+
# "x-oss-target-redundancy-type", "x-oss-traffic-limit", "x-oss-write-get-object-response",
|
164
157
|
# )
|
165
158
|
date = formatdate(usegmt=True)
|
166
159
|
if params is None:
|
167
160
|
params = ""
|
168
161
|
elif not isinstance(params, str):
|
169
162
|
params = urlencode(params)
|
170
|
-
if params:
|
163
|
+
if params and not params.startswith("?"):
|
171
164
|
params = "?" + params
|
172
165
|
if headers:
|
173
166
|
if isinstance(headers, Mapping):
|
@@ -183,7 +176,7 @@ def oss_upload_sign(
|
|
183
176
|
headers_str = ""
|
184
177
|
content_md5 = headers.setdefault("content-md5", "")
|
185
178
|
content_type = headers.setdefault("content-type", "")
|
186
|
-
date = headers.get("x-oss-date") or headers.get("date"
|
179
|
+
date = headers.get("x-oss-date") or headers.get("date") or ""
|
187
180
|
if not date:
|
188
181
|
date = headers["date"] = formatdate(usegmt=True)
|
189
182
|
signature_data = f"""\
|
@@ -269,13 +262,16 @@ def oss_multipart_part_iter(
|
|
269
262
|
) -> Iterator[dict] | AsyncIterator[dict]:
|
270
263
|
"""罗列某个分块上传任务,已经上传的分块
|
271
264
|
"""
|
265
|
+
request_kwargs.update(
|
266
|
+
method="GET",
|
267
|
+
params={"uploadId": upload_id},
|
268
|
+
headers={"x-oss-security-token": token["SecurityToken"]},
|
269
|
+
)
|
270
|
+
request_kwargs.setdefault("parse", lambda _, content: fromstring(content))
|
272
271
|
def gen_step():
|
273
|
-
request_kwargs["
|
274
|
-
request_kwargs["headers"] = {"x-oss-security-token": token["SecurityToken"]}
|
275
|
-
request_kwargs["params"] = params = {"uploadId": upload_id}
|
276
|
-
request_kwargs.setdefault("parse", False)
|
272
|
+
params = request_kwargs["params"]
|
277
273
|
while True:
|
278
|
-
|
274
|
+
etree = yield oss_upload_request(
|
279
275
|
request,
|
280
276
|
url=url,
|
281
277
|
bucket=bucket,
|
@@ -284,12 +280,11 @@ def oss_multipart_part_iter(
|
|
284
280
|
async_=async_,
|
285
281
|
**request_kwargs,
|
286
282
|
)
|
287
|
-
etree = fromstring(content)
|
288
283
|
for el in etree.iterfind("Part"):
|
289
|
-
yield Yield({sel.tag:
|
290
|
-
if etree.find("IsTruncated")
|
284
|
+
yield Yield({sel.tag: maybe_integer(sel.text) for sel in el}, identity=True)
|
285
|
+
if getattr(etree.find("IsTruncated"), "text") == "false":
|
291
286
|
break
|
292
|
-
params["part-number-marker"] = etree.find("NextPartNumberMarker")
|
287
|
+
params["part-number-marker"] = getattr(etree.find("NextPartNumberMarker"), "text")
|
293
288
|
return run_gen_step_iter(gen_step, async_=async_)
|
294
289
|
|
295
290
|
|
@@ -327,12 +322,14 @@ def oss_multipart_upload_init(
|
|
327
322
|
async_: Literal[False, True] = False,
|
328
323
|
**request_kwargs,
|
329
324
|
) -> str | Coroutine[Any, Any, str]:
|
330
|
-
"""
|
325
|
+
"""分块上传的初始化,获取 upload_id
|
331
326
|
"""
|
327
|
+
request_kwargs.update(
|
328
|
+
method="POST",
|
329
|
+
params={"sequential": "1", "uploads": "1"},
|
330
|
+
headers={"x-oss-security-token": token["SecurityToken"]},
|
331
|
+
)
|
332
332
|
request_kwargs.setdefault("parse", parse_upload_id)
|
333
|
-
request_kwargs["method"] = "POST"
|
334
|
-
request_kwargs["params"] = {"sequential": "1", "uploads": "1"}
|
335
|
-
request_kwargs["headers"] = {"x-oss-security-token": token["SecurityToken"]}
|
336
333
|
return oss_upload_request(
|
337
334
|
request,
|
338
335
|
url=url,
|
@@ -387,20 +384,26 @@ def oss_multipart_upload_complete(
|
|
387
384
|
async_: Literal[False, True] = False,
|
388
385
|
**request_kwargs,
|
389
386
|
) -> dict | Coroutine[Any, Any, dict]:
|
390
|
-
"""
|
387
|
+
"""完成分块上传任务,会在请求头中包含回调数据,请求体中包含分块信息
|
391
388
|
"""
|
392
|
-
request_kwargs
|
393
|
-
|
394
|
-
|
395
|
-
"
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
389
|
+
request_kwargs.update(
|
390
|
+
method="POST",
|
391
|
+
params={"uploadId": upload_id},
|
392
|
+
data=b"".join((
|
393
|
+
b"<CompleteMultipartUpload>",
|
394
|
+
*map(
|
395
|
+
b"<Part><PartNumber>%d</PartNumber><ETag>%s</ETag></Part>".__mod__,
|
396
|
+
((part["PartNumber"], bytes(part["ETag"], "ascii")) for part in parts),
|
397
|
+
),
|
398
|
+
b"</CompleteMultipartUpload>",
|
399
|
+
)),
|
400
|
+
headers={
|
401
|
+
"x-oss-security-token": token["SecurityToken"],
|
402
|
+
"x-oss-callback": to_base64(callback["callback"]),
|
403
|
+
"x-oss-callback-var": to_base64(callback["callback_var"]),
|
404
|
+
"content-type": "text/xml",
|
405
|
+
},
|
406
|
+
)
|
404
407
|
return oss_upload_request(
|
405
408
|
request,
|
406
409
|
url=url,
|
@@ -449,12 +452,14 @@ def oss_multipart_upload_cancel(
|
|
449
452
|
async_: Literal[False, True] = False,
|
450
453
|
**request_kwargs,
|
451
454
|
) -> bool | Coroutine[Any, Any, bool]:
|
452
|
-
"""
|
455
|
+
"""取消分块上传任务,返回成功与否
|
453
456
|
"""
|
457
|
+
request_kwargs.update(
|
458
|
+
method="DELETE",
|
459
|
+
params={"uploadId": upload_id},
|
460
|
+
headers={"x-oss-security-token": token["SecurityToken"]},
|
461
|
+
)
|
454
462
|
request_kwargs.setdefault("parse", lambda resp: 200 <= resp.status_code < 300 or resp.status_code == 404)
|
455
|
-
request_kwargs["method"] = "DELETE"
|
456
|
-
request_kwargs["params"] = {"uploadId": upload_id}
|
457
|
-
request_kwargs["headers"] = {"x-oss-security-token": token["SecurityToken"]}
|
458
463
|
return oss_upload_request(
|
459
464
|
request,
|
460
465
|
url=url,
|
@@ -520,7 +525,7 @@ def oss_multipart_upload_part(
|
|
520
525
|
) -> dict | Coroutine[Any, Any, dict]:
|
521
526
|
"""上传一个分片,返回一个字典,包含如下字段:
|
522
527
|
|
523
|
-
.. python
|
528
|
+
.. code:: python
|
524
529
|
|
525
530
|
{
|
526
531
|
"PartNumber": int, # 分块序号,从 1 开始计数
|
@@ -924,3 +929,22 @@ def oss_multipart_upload(
|
|
924
929
|
yield close_reporthook
|
925
930
|
return run_gen_step(gen_step, async_=async_)
|
926
931
|
|
932
|
+
|
933
|
+
# class MultipartUploader:
|
934
|
+
# def __init__
|
935
|
+
# def __del__
|
936
|
+
# async def __aiter__
|
937
|
+
# def __iter__
|
938
|
+
# async def __aenter__
|
939
|
+
# async def __aexit__
|
940
|
+
# def __enter__
|
941
|
+
# def __exit__
|
942
|
+
# # 0. 应该设计 1 个类,支持同步和异步,实例化不会进行初始化(为了对异步进行适配)
|
943
|
+
# # 1. 可以作为上下文管理器或者迭代器使用
|
944
|
+
# # 2. 上下文管理器也返回迭代器(迭代器迭代时,如果未打开文件或者没有上传信息,则会初始化以获取)
|
945
|
+
# # 3. 中途可以暂停或取消
|
946
|
+
# # 4. seekable: path, url (支持 range request), file reader (seekable)
|
947
|
+
# # 5. 支持进度条
|
948
|
+
# # 6. 设计一个工具函数,放到 p115client.tool.upload 模块中
|
949
|
+
# ...
|
950
|
+
|