multibucket 0.1.2__cp313-cp313-win_amd64.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.
@@ -0,0 +1,4 @@
1
+ from multibucket.ucloud import UCloudFileClient
2
+
3
+ __version__ = '0.1.2'
4
+ __all__ = ["UCloudFileClient"]
Binary file
multibucket/ucloud.pyi ADDED
@@ -0,0 +1,268 @@
1
+ import requests
2
+ from _typeshed import Incomplete
3
+ from typing import BinaryIO, Callable
4
+
5
+ class UCloudFileClient:
6
+ """
7
+ UCloud UFile 文件管理客户端
8
+
9
+ 参考文档:
10
+ - 签名算法: https://docs.ucloud.cn/ufile/api/authorization
11
+ - 上传文件: https://docs.ucloud.cn/api/ufile-api/put_file
12
+ - 删除文件: https://docs.ucloud.cn/api/ufile-api/delete_file
13
+ - 查询文件: https://docs.ucloud.cn/api/ufile-api/head_file
14
+ - 初始化分片: https://docs.ucloud.cn/api/ufile-api/initiate_multipart_upload
15
+ - 上传分片: https://docs.ucloud.cn/api/ufile-api/upload_part
16
+ - 完成分片: https://docs.ucloud.cn/api/ufile-api/finish_multipart_upload
17
+ - 放弃分片: https://docs.ucloud.cn/api/ufile-api/abort_multipart_upload
18
+ """
19
+ public_key: Incomplete
20
+ private_key: Incomplete
21
+ bucket: Incomplete
22
+ region: Incomplete
23
+ internal: Incomplete
24
+ external_url: Incomplete
25
+ intranet_url: Incomplete
26
+ host: Incomplete
27
+ domain_url: Incomplete
28
+ def __init__(self, public_key: str, private_key: str, bucket: str, region: str = 'cn-bj', internal: bool = False, domain_url: str | None = None) -> None:
29
+ """
30
+ :param public_key: UCloud 公钥
31
+ :param private_key: UCloud 私钥
32
+ :param bucket: 存储空间名称
33
+ :param region: 地域标识,如 cn-bj、cn-sh2、cn-wlcb 等
34
+ :param internal: 是否使用内网访问,默认 False(外网)
35
+ 内网域名格式: {bucket}.internal-{region}.ufileos.com
36
+ 外网域名格式: {bucket}.{region}.ufileos.com
37
+ :param domain_url: 自定义域名 URL,如 CDN 域名。若不指定则使用默认的 host
38
+ """
39
+ def key_sort(self, params: dict) -> dict:
40
+ """
41
+ 对字典按 key 排序
42
+ """
43
+ def canonicalized_resource(self, key: str, query_params: dict[str, str] | None = None) -> str:
44
+ """
45
+ 构造规范化资源路径
46
+
47
+ :param key: 文件 key
48
+ :param query_params: 查询参数字典,会拼接到资源路径后用于签名
49
+ """
50
+ def canonicalized_ucloud_headers(self, headers: dict[str, str]) -> str:
51
+ """
52
+ 只取 X-UCloud 开头的 header
53
+ """
54
+ def sign(self, string_to_sign: str) -> str:
55
+ """
56
+ HMAC-SHA1 + Base64
57
+ """
58
+ def make_authorization(self, key: str, expires: str, method: str = 'GET', content_md5: str = '', content_type: str = '', headers: dict[str, str] | None = None, query_params: dict[str, str] | None = None) -> str:
59
+ '''
60
+ 生成签名
61
+
62
+ StringToSign = HTTP-Verb + "
63
+ " +
64
+ Content-MD5 + "
65
+ " +
66
+ Content-Type + "
67
+ " +
68
+ Date + "
69
+ " +
70
+ CanonicalizedUCloudHeaders +
71
+ CanonicalizedResource
72
+
73
+ :param key: 文件 key
74
+ :param expires: 时间戳(秒)
75
+ :param method: HTTP 方法
76
+ :param content_md5: Content-MD5 值
77
+ :param content_type: Content-Type 值
78
+ :param headers: 请求头字典
79
+ :param query_params: 查询参数字典,参与签名
80
+ :return: Base64 编码的签名字符串
81
+ '''
82
+ def get_path_url(self, key: str) -> str:
83
+ """
84
+ 获取文件的完整访问 URL(使用自定义域名或默认域名)
85
+
86
+ :param key: 文件在 UFile 中的 key
87
+ :return: 完整的文件访问 URL
88
+ """
89
+ def get_shared_url(self, key: str, expire_time: int = 1200) -> str:
90
+ """
91
+ 生成带签名的分享 URL(查询字符串身份验证)
92
+
93
+ 适用于分享私有空间文件给第三方访问,无需代理请求。
94
+ 默认使用外网地址,除非显式指定了自定义域名。
95
+ 参考文档: https://docs.ucloud.cn/ufile/api/authorization?id=查询字符串请求身份验证替代项
96
+
97
+ :param key: 文件在 UFile 中的 key
98
+ :param expire_time: 过期时间(秒),默认 1200 秒(20 分钟)
99
+ :return: 带签名的完整访问 URL
100
+ """
101
+ def put(self, key: str, data: bytes | str | BinaryIO, content_type: str | None = None, content_md5: str | None = None, headers: dict[str, str] | None = None, timeout: float | tuple | None = None) -> requests.Response:
102
+ """
103
+ 上传文件 (PutFile)
104
+
105
+ PUT /<object_name>
106
+ Host: <bucket_name>.<region>.ufileos.com
107
+
108
+ :param key: 文件在 UFile 中的 key(object_name)
109
+ :param data: 文件内容(bytes / str / 文件对象)
110
+ :param content_type: MIME 类型,如 image/jpg、application/octet-stream
111
+ :param content_md5: 文件内容的 MD5 摘要,用于完整性校验
112
+ :param headers: 额外的请求头(如 X-Ufile-Storage-Class、X-Ufile-Meta-* 等)
113
+ :param timeout: 超时时间(秒),可以是 float 或 (connect_timeout, read_timeout) 元组
114
+ :return: requests.Response(成功返回 200,无 body)
115
+ """
116
+ def put_with_retry(self, key: str, data: bytes | str | BinaryIO, content_type: str | None = None, content_md5: str | None = None, headers: dict[str, str] | None = None, timeout: float | tuple | None = None, retries: int = 3) -> bool:
117
+ """
118
+ 带重试机制的上传文件
119
+
120
+ 通过 put 方法上传,状态码为 200 表示上传成功。
121
+ 如果上传失败会自动重试,直到达到指定重试次数。
122
+
123
+ 注意: 如果 data 是文件对象,会自动读取到内存以支持重试。
124
+ 对于大文件,建议直接使用 put 方法或分片上传。
125
+
126
+ :param key: 文件在 UFile 中的 key(object_name)
127
+ :param data: 文件内容(bytes / str / 文件对象)
128
+ :param content_type: MIME 类型,如 image/jpg、application/octet-stream
129
+ :param content_md5: 文件内容的 MD5 摘要,用于完整性校验
130
+ :param headers: 额外的请求头(如 X-Ufile-Storage-Class、X-Ufile-Meta-* 等)
131
+ :param timeout: 超时时间(秒),可以是 float 或 (connect_timeout, read_timeout) 元组
132
+ :param retries: 最大重试次数,默认 3 次
133
+ :return: True 表示上传成功,False 表示上传失败
134
+ """
135
+ def get(self, key: str, headers: dict[str, str] | None = None) -> requests.Response:
136
+ """
137
+ 下载文件 (GetFile)
138
+
139
+ GET /<object_name>
140
+ Host: <bucket_name>.<region>.ufileos.com
141
+
142
+ :param key: 文件在 UFile 中的 key
143
+ :param headers: 额外的请求头
144
+ :return: requests.Response(response.content 为文件内容)
145
+ """
146
+ def head(self, key: str, headers: dict[str, str] | None = None) -> requests.Response:
147
+ """
148
+ 查询文件基本信息 (HeadFile)
149
+
150
+ HEAD /<object_name>
151
+ Host: <bucket_name>.<region>.ufileos.com
152
+
153
+ 响应头包含:
154
+ - Content-Type: 文件类型
155
+ - Content-Length: 文件长度
156
+ - ETag: 文件在 US3 的哈希值
157
+ - Last-Modified: 最后修改日期
158
+ - X-Ufile-Meta-*: 用户自定义元数据
159
+ - X-Ufile-Storage-Class: 存储类型
160
+
161
+ :param key: 文件在 UFile 中的 key
162
+ :param headers: 额外的请求头
163
+ :return: requests.Response(无 body,信息在 response.headers 中)
164
+ """
165
+ def exists(self, key: str) -> bool:
166
+ """
167
+ 判断文件是否存在
168
+
169
+ :param key: 文件在 UFile 中的 key
170
+ :return: True 表示文件存在,False 表示不存在
171
+ """
172
+ def delete(self, key: str, headers: dict[str, str] | None = None) -> requests.Response:
173
+ """
174
+ 删除文件 (DeleteFile)
175
+
176
+ DELETE /<object_name>
177
+ Host: <bucket_name>.<region>.ufileos.com
178
+
179
+ :param key: 文件在 UFile 中的 key
180
+ :param headers: 额外的请求头
181
+ :return: requests.Response(成功返回 204 No Content)
182
+ """
183
+ def list(self, prefix: str = '', marker: str = '', limit: int = 20, headers: dict[str, str] | None = None) -> requests.Response:
184
+ """
185
+ 列出文件 (GetFileList)
186
+
187
+ GET /?prefix=<prefix>&marker=<marker>&limit=<limit>
188
+ Host: <bucket_name>.<region>.ufileos.com
189
+
190
+ :param prefix: 文件名前缀过滤
191
+ :param marker: 分页标记,首次传空,后续用返回值中的 NextMarker
192
+ :param limit: 每次返回最大条数,默认 20
193
+ :param headers: 额外的请求头
194
+ :return: requests.Response(JSON 格式,包含 DataSet / NextMarker / TotalCount)
195
+ """
196
+ def initiate_multipart_upload(self, key: str, content_type: str | None = None, headers: dict[str, str] | None = None) -> requests.Response:
197
+ """
198
+ 初始化分片上传 (InitiateMultipartUpload)
199
+
200
+ POST /<object_name>?uploads
201
+ Host: <bucket_name>.<region>.ufileos.com
202
+
203
+ :param key: 文件在 UFile 中的 key
204
+ :param content_type: MIME 类型
205
+ :param headers: 额外的请求头(如 X-Ufile-Storage-Class、X-Ufile-Meta-* 等)
206
+ :return: requests.Response(JSON 包含 UploadId / BlkSize / Bucket / Key)
207
+ """
208
+ def upload_part(self, key: str, upload_id: str, part_number: int, data: bytes, content_type: str = 'application/octet-stream', headers: dict[str, str] | None = None) -> requests.Response:
209
+ """
210
+ 上传分片 (UploadPart)
211
+
212
+ PUT /<object_name>?uploadId=<upload_id>&partNumber=<part_number>
213
+ Host: <bucket_name>.<region>.ufileos.com
214
+
215
+ :param key: 文件在 UFile 中的 key
216
+ :param upload_id: 初始化分片返回的 UploadId
217
+ :param part_number: 分片序号(从 0 开始)
218
+ :param data: 分片数据(bytes)
219
+ :param content_type: MIME 类型,默认 application/octet-stream
220
+ :param headers: 额外的请求头
221
+ :return: requests.Response(JSON 包含 PartNumber,响应头包含 ETag)
222
+ """
223
+ def finish_multipart_upload(self, key: str, upload_id: str, etags: list[str], new_object: str | None = None, headers: dict[str, str] | None = None) -> requests.Response:
224
+ """
225
+ 完成分片上传 (FinishMultipartUpload)
226
+
227
+ POST /<object_name>?uploadId=<upload_id>[&newObject=<new_object>]
228
+ Host: <bucket_name>.<region>.ufileos.com
229
+
230
+ 请求 body 为所有分片 ETag 用逗号拼接的字符串
231
+
232
+ :param key: 文件在 UFile 中的 key
233
+ :param upload_id: 初始化分片返回的 UploadId
234
+ :param etags: 各分片 ETag 列表(按 partNumber 顺序)
235
+ :param new_object: 可选,最终文件名,若不指定则使用原 key
236
+ :param headers: 额外的请求头
237
+ :return: requests.Response(JSON 包含 Bucket / Key / FileSize)
238
+ """
239
+ def abort_multipart_upload(self, key: str, upload_id: str, headers: dict[str, str] | None = None) -> requests.Response:
240
+ """
241
+ 放弃分片上传 (AbortMultipartUpload)
242
+
243
+ DELETE /<object_name>?uploadId=<upload_id>
244
+ Host: <bucket_name>.<region>.ufileos.com
245
+
246
+ 放弃后不能再使用该 upload_id,已上传的分片数据也会被删除
247
+
248
+ :param key: 文件在 UFile 中的 key
249
+ :param upload_id: 初始化分片返回的 UploadId
250
+ :param headers: 额外的请求头
251
+ :return: requests.Response
252
+ """
253
+ def multipart_upload(self, key: str, file_path: str, content_type: str | None = None, part_size: int | None = None, headers: dict[str, str] | None = None, callback: Callable[[int, int, int, int], None] | None = None) -> dict:
254
+ """
255
+ 分片上传高级封装:自动分片、上传、完成
256
+
257
+ 流程: 初始化分片 -> 循环上传分片 -> 完成分片
258
+ 如果中途失败会自动调用 abort_multipart_upload 放弃上传
259
+
260
+ :param key: 文件在 UFile 中的 key
261
+ :param file_path: 本地文件路径
262
+ :param content_type: MIME 类型,默认 application/octet-stream
263
+ :param part_size: 分片大小(字节),默认 4MB(4 * 1024 * 1024)
264
+ :param headers: 额外的请求头
265
+ :param callback: 上传进度回调 callback(part_number, total_parts, uploaded_bytes, total_bytes)
266
+ :return: dict,包含 upload_id / etags / result
267
+ :raises: Exception 上传失败时抛出异常
268
+ """
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.1
2
+ Name: multibucket
3
+ Version: 0.1.2
4
+ Summary: 多对象存储桶 SDK, 支持 UCloud UFile 等
5
+ Home-page:
6
+ Author: zhenzi0322
7
+ Author-email: zhenzi0322 <82131529@qq.com>
8
+ License: MIT
9
+ Requires-Python: >=3.8
10
+ description-content-type: text/markdown
11
+ Description:
12
+ # Multibucket
13
+
14
+ 多对象存储桶 SDK,支持 UCloud UFile 等云存储服务。
15
+
16
+ ## 运行条件
17
+
18
+ - Python >= 3.8
19
+ - requests
20
+
21
+ ## 安装
22
+
23
+ ```bash
24
+ pip install multibucket
25
+ ```
26
+
27
+ ## 快速开始
28
+
29
+ ```python
30
+ from multibucket import UCloudFileClient
31
+
32
+ # 初始化客户端
33
+ ufile = UCloudFileClient(
34
+ public_key="your_public_key",
35
+ private_key="your_private_key",
36
+ bucket="your-bucket",
37
+ region="cn-bj"
38
+ )
39
+
40
+ # 上传文件
41
+ with open("image.jpg", "rb") as f:
42
+ resp = ufile.put("photos/image.jpg", f.read(), content_type="image/jpg")
43
+ print(resp.status_code) # 200
44
+
45
+ # 带重试的上传(默认重试 3 次)
46
+ success = ufile.put_with_retry("backup/data.zip", data, retries=3)
47
+ print(success) # True/False
48
+
49
+ # 获取文件 URL
50
+ url = ufile.get_path_url("photos/image.jpg")
51
+ print(url) # https://your-bucket.cn-bj.ufileos.com/photos/image.jpg
52
+
53
+ # 生成分享链接(私有空间,默认 20 分钟有效)
54
+ share_url = ufile.get_shared_url("photos/image.jpg", expire_time=3600)
55
+ print(share_url)
56
+
57
+ # 判断文件是否存在
58
+ exists = ufile.exists("photos/image.jpg")
59
+ print(exists) # True/False
60
+
61
+ # 下载文件
62
+ resp = ufile.get("photos/image.jpg")
63
+ with open("downloaded.jpg", "wb") as f:
64
+ f.write(resp.content)
65
+
66
+ # 查询文件信息
67
+ resp = ufile.head("photos/image.jpg")
68
+ print(resp.headers["Content-Length"])
69
+
70
+ # 列出文件
71
+ resp = ufile.list(prefix="photos/", limit=50)
72
+ files = resp.json()["DataSet"]
73
+
74
+ # 删除文件
75
+ resp = ufile.delete("photos/image.jpg")
76
+ print(resp.status_code) # 204
77
+ ```
78
+
79
+ ## 高级功能
80
+
81
+ ### 自定义域名(CDN)
82
+
83
+ ```python
84
+ ufile = UCloudFileClient(
85
+ public_key="your_public_key",
86
+ private_key="your_private_key",
87
+ bucket="your-bucket",
88
+ region="cn-bj",
89
+ domain_url="https://cdn.example.com" # 自定义 CDN 域名
90
+ )
91
+ ```
92
+
93
+ ### 内网访问
94
+
95
+ ```python
96
+ ufile = UCloudFileClient(
97
+ public_key="your_public_key",
98
+ private_key="your_private_key",
99
+ bucket="your-bucket",
100
+ region="cn-wlcb",
101
+ internal=True # 使用内网访问
102
+ )
103
+ ```
104
+
105
+ ### 分片上传(大文件)
106
+
107
+ ```python
108
+ # 自动分片上传,支持进度回调
109
+ def progress_callback(part_number, total_parts, uploaded, total):
110
+ print(f"进度: {part_number + 1}/{total_parts}")
111
+
112
+ result = ufile.multipart_upload(
113
+ key="videos/large.mp4",
114
+ file_path="/path/to/large.mp4",
115
+ content_type="video/mp4",
116
+ callback=progress_callback
117
+ )
118
+ ```
119
+
120
+
121
+ Requires-Dist: requests
@@ -0,0 +1,6 @@
1
+ multibucket/ucloud.cp313-win_amd64.pyd,sha256=ypDDATdT8wBFqU-N-WFxz6iqzUCHQvJxkkDSKvIw4vQ,154624
2
+ multibucket/ucloud.pyi,sha256=acmnIq7iEuLjAv16faLdAGtzyI8xl4QpSvsV_mIdDRM,12954
3
+ multibucket/__init__.py,sha256=lfMf-Ui4-n7AUqLQc0scjrnPBO-6HhbGe2ysrlKjQfo,106
4
+ multibucket-0.1.2.dist-info/METADATA,sha256=r86kVm05U-ydwlekGbE5uL_IGBoYlP3KtiRMrRsZUEc,2888
5
+ multibucket-0.1.2.dist-info/WHEEL,sha256=dn77BUfjMOPRkZt-Pyb_fdAFpXI4sKyN3v0I_j_INQ0,114
6
+ multibucket-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: multibucket-protected-builder
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-win_amd64