gsnet-sdk 0.1.0__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.
Files changed (59) hide show
  1. gsnet/__init__.py +32 -0
  2. gsnet/_dataclass.py +404 -0
  3. gsnet/_exceptions.py +273 -0
  4. gsnet/_file.py +300 -0
  5. gsnet/_login.py +183 -0
  6. gsnet/_session.py +319 -0
  7. gsnet/_tqdm.py +141 -0
  8. gsnet/adaptor/__init__.py +0 -0
  9. gsnet/adaptor/om_hub/__init__.py +3 -0
  10. gsnet/adaptor/om_hub/download.py +155 -0
  11. gsnet/adaptor/om_hub/file_manager.py +382 -0
  12. gsnet/adaptor/om_hub/upload.py +137 -0
  13. gsnet/adaptor/om_hub/utils.py +50 -0
  14. gsnet/api.py +820 -0
  15. gsnet/commands/__init__.py +13 -0
  16. gsnet/commands/dataset.py +222 -0
  17. gsnet/commands/dataset_deprecated.py +203 -0
  18. gsnet/commands/gsnet_cli.py +47 -0
  19. gsnet/commands/model.py +220 -0
  20. gsnet/commands/model_deprecated.py +235 -0
  21. gsnet/commands/user.py +121 -0
  22. gsnet/constants.py +59 -0
  23. gsnet/downloader.py +361 -0
  24. gsnet/log.py +72 -0
  25. gsnet/refactor/__init__.py +2 -0
  26. gsnet/refactor/api.py +0 -0
  27. gsnet/refactor/constants.py +105 -0
  28. gsnet/refactor/controlled/__init__.py +51 -0
  29. gsnet/refactor/controlled/crypto.py +145 -0
  30. gsnet/refactor/controlled/exceptions.py +41 -0
  31. gsnet/refactor/controlled/header.py +29 -0
  32. gsnet/refactor/controlled/kms_client.py +183 -0
  33. gsnet/refactor/controlled/models.py +145 -0
  34. gsnet/refactor/core/__init__.py +1 -0
  35. gsnet/refactor/core/auth.py +58 -0
  36. gsnet/refactor/core/dataclass.py +70 -0
  37. gsnet/refactor/core/router.py +324 -0
  38. gsnet/refactor/core/session.py +156 -0
  39. gsnet/refactor/plugins/__init__.py +0 -0
  40. gsnet/refactor/plugins/errors.py +211 -0
  41. gsnet/refactor/plugins/log.py +47 -0
  42. gsnet/refactor/plugins/progress.py +585 -0
  43. gsnet/refactor/sdk.py +126 -0
  44. gsnet/refactor/service/__init__.py +0 -0
  45. gsnet/refactor/service/downloader.py +809 -0
  46. gsnet/refactor/service/file_manager.py +522 -0
  47. gsnet/refactor/service/notification.py +81 -0
  48. gsnet/refactor/service/uploader.py +820 -0
  49. gsnet/refactor/service/validators.py +47 -0
  50. gsnet/refactor/utils/__init__.py +0 -0
  51. gsnet/refactor/utils/deprecate.py +18 -0
  52. gsnet/refactor/utils/utils.py +13 -0
  53. gsnet/uploader.py +340 -0
  54. gsnet/utils.py +129 -0
  55. gsnet_sdk-0.1.0.dist-info/METADATA +120 -0
  56. gsnet_sdk-0.1.0.dist-info/RECORD +59 -0
  57. gsnet_sdk-0.1.0.dist-info/WHEEL +5 -0
  58. gsnet_sdk-0.1.0.dist-info/entry_points.txt +2 -0
  59. gsnet_sdk-0.1.0.dist-info/top_level.txt +1 -0
gsnet/__init__.py ADDED
@@ -0,0 +1,32 @@
1
+ import asyncio
2
+ import os
3
+ import sys
4
+
5
+ from gsnet._login import login, logout, whoami
6
+ from gsnet.refactor.constants import BOLD, DIM, RESET
7
+ from gsnet.refactor.core import GSnetRouter
8
+ from gsnet.refactor.plugins.log import setup_logging
9
+ from gsnet.refactor.sdk import notice, gsnet_download_file, gsnet_upload_file
10
+
11
+ from .downloader import download_file, download_model, download_model_file
12
+ from .uploader import upload_file, upload_model, upload_model_file
13
+
14
+ setup_logging()
15
+
16
+ # if windows machine, do not set uvloop
17
+ if os.name == "nt":
18
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
19
+ else:
20
+ try:
21
+ import uvloop
22
+ except ImportError:
23
+ import subprocess
24
+
25
+ print(f"{DIM}Module {BOLD}`uvloop`{RESET} {DIM}undetected, installing...{RESET}")
26
+ subprocess.check_call(
27
+ [sys.executable, "-m", "pip", "install", "-qq", "uvloop"],
28
+ stdout=subprocess.DEVNULL,
29
+ stderr=subprocess.DEVNULL,
30
+ )
31
+ import uvloop
32
+ asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
gsnet/_dataclass.py ADDED
@@ -0,0 +1,404 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import asdict, dataclass, field
4
+ from datetime import datetime
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from .utils import parse_time
8
+
9
+
10
+ @dataclass
11
+ class UserInfo:
12
+ """
13
+ User Info Dataclass
14
+
15
+ Attributes:
16
+ username (str):
17
+ username for GSnet links and repo_id
18
+ id (int):
19
+ unique number id of user
20
+ login (str):
21
+ username used for login purpose
22
+ subject_name (str):
23
+ self-defined name for display
24
+ email (str):
25
+ registered email address
26
+ avatar_url (str):
27
+ user avatar url
28
+ language (str):
29
+ user default language
30
+ is_admin (bool):
31
+ whether the user is admin or not
32
+ is_active (bool):
33
+ whether the user is active or not
34
+ last_login (str):
35
+ last login time
36
+ created (str):
37
+ created time
38
+ """
39
+
40
+ username: str
41
+ id: Optional[int]
42
+ login: Optional[str]
43
+ subject_name: Optional[str]
44
+ email: Optional[str]
45
+ avatar_url: Optional[str]
46
+ language: Optional[str]
47
+ is_admin: Optional[bool]
48
+ is_active: Optional[bool]
49
+ last_login: Optional[str]
50
+ created: Optional[str]
51
+
52
+
53
+ @dataclass
54
+ class RepoPermission:
55
+ """
56
+ Permission Info Dataclass
57
+
58
+ Attributes:
59
+ admin (bool):
60
+ whether the user is admin or not
61
+ push (bool):
62
+ whether the user can push to the repository or not
63
+ pull (bool):
64
+ whether the user can pull from the repository or not
65
+ """
66
+
67
+ admin: bool
68
+ push: bool
69
+ pull: bool
70
+
71
+
72
+ @dataclass
73
+ class RepoInfo:
74
+ """
75
+ Repo Info Dataclass
76
+
77
+ Attributes:
78
+ id (int):
79
+ repo id
80
+ owner (UserInfo):
81
+ owner info
82
+ name (str):
83
+ repo name
84
+ repo_id (str):
85
+ repo id in `Username/Reponame` format
86
+ size (int):
87
+ repo size
88
+ html_url (str):
89
+ repo url
90
+ permissions (RepoPermission):
91
+ repo permissions
92
+ created_at (str):
93
+ created time
94
+ updated_at (str):
95
+ updated time
96
+ """
97
+
98
+ id: int
99
+ owner: UserInfo
100
+ name: str
101
+ repo_id: str
102
+ size: Optional[int]
103
+ html_url: Optional[str]
104
+ permissions: Optional[RepoPermission]
105
+ created_at: Optional[datetime]
106
+ updated_at: Optional[datetime]
107
+
108
+ def __init__(self, **kwargs):
109
+ self.id = kwargs.pop("id")
110
+ self.owner = UserInfo(**kwargs.pop("owner"))
111
+ self.name = kwargs.pop("name")
112
+ self.repo_id = kwargs.pop("subject_name")
113
+
114
+ self.size = kwargs.pop("size", None)
115
+ self.html_url = kwargs.pop("html_url", None)
116
+ permissions = kwargs.pop("permissions", None)
117
+ self.permissions = RepoPermission(**permissions) if permissions else None
118
+
119
+ created_at = kwargs.pop("created_at", None)
120
+ self.created_at = parse_time(created_at) if created_at else None
121
+ updated_at = kwargs.pop("updated_at", None)
122
+ self.updated_at = parse_time(updated_at) if updated_at else None
123
+
124
+
125
+ @dataclass
126
+ class DatasetFile:
127
+ """TODO"""
128
+
129
+ uuid: str
130
+ name: str
131
+ size: int
132
+ type: int
133
+ id: int
134
+ datasetId: int
135
+ repo_id: str
136
+ uploaderId: Optional[int]
137
+ isPrivate: Optional[bool]
138
+ decompressState: Optional[int]
139
+
140
+ def __init__(self, **kwargs):
141
+ self.uuid = kwargs.pop("uuid")
142
+ self.name = kwargs.pop("name")
143
+ self.size = kwargs.pop("size")
144
+ self.type = kwargs.pop("type")
145
+ self.id = kwargs.pop("id")
146
+ self.datasetId = kwargs.pop("datasetId")
147
+ self.repo_id = kwargs.pop("repo_id")
148
+
149
+ self.uploaderId = kwargs.pop("uploaderId", None)
150
+ self.isPrivate = kwargs.pop("isPrivate", None)
151
+ self.decompressState = kwargs.pop("decompressState", None)
152
+
153
+
154
+ @dataclass
155
+ class DatasetInfo:
156
+ """TODO"""
157
+
158
+ id: str
159
+ userId: int
160
+ repoId: int
161
+ title: str
162
+ repo_id: str
163
+ attachments: Optional[List[DatasetFile]]
164
+ status: Optional[int]
165
+
166
+ def __init__(self, **kwargs):
167
+ self.id = kwargs.pop("id")
168
+ self.userId = kwargs.pop("userId")
169
+ self.repoId = kwargs.pop("repoId")
170
+ self.title = kwargs.pop("title")
171
+ self.repo_id = kwargs.pop("repo_id")
172
+
173
+ attachments = kwargs.pop("attachments", [])
174
+ if attachments:
175
+ for data in attachments:
176
+ data.update({"repo_id": self.repo_id})
177
+ self.attachments = [DatasetFile(**data) for data in attachments]
178
+ else:
179
+ self.attachments = None
180
+
181
+ self.status = kwargs.pop("status", None)
182
+ self.recommend = kwargs.pop("recommend", None)
183
+
184
+
185
+ @dataclass
186
+ class FileChunkInfo:
187
+ """
188
+ File Chunk Info Dataclass
189
+
190
+ API Response (dict):
191
+ - dataset "/attachments/get_chunks"
192
+ "uuid": fileChunk.UUID,
193
+ "uploaded": strconv.Itoa(fileChunk.IsUploaded),
194
+ "uploadID": fileChunk.UploadID,
195
+ "chunks": string(chunks),
196
+ "attachID": "0",
197
+ "datasetID": "0",
198
+ "fileName": "",
199
+ "datasetName": "",
200
+
201
+ - model "/attachments/model/get_chunks"
202
+ "uuid": fileChunk.UUID,
203
+ "uploaded": strconv.Itoa(fileChunk.IsUploaded),
204
+ "uploadID": fileChunk.UploadID,
205
+ "chunks": string(chunks),
206
+ "attachID": "0",
207
+ "modeluuid": modeluuid,
208
+ "datasetID": "0",
209
+ "fileName": "",
210
+ "modelName": "",
211
+
212
+ - error response
213
+ "result_code": "-1",
214
+ "msg": errStr,
215
+
216
+ Attributes:
217
+ result_code (int):
218
+ return 0 when success, otherwise return -1 with error message
219
+ msg (str):
220
+ return plain string error message, return "success" when None
221
+ uploaded (Optional[bool]):
222
+ whether the file is uploaded or not
223
+ attachID (Optional[int]):
224
+ attachment id
225
+ uploaded_chunks (Optional[list]):
226
+ list of uploaded chunks
227
+ uploadID (Optional[str]):
228
+ upload id
229
+ uuid (Optional[str]):
230
+ file uuid
231
+ repo_id (Optional[str]):
232
+ repo id in `Username/Reponame` format
233
+ dataset_or_model_name (Optional[str]):
234
+ dataset or model name
235
+ """
236
+
237
+ result_code: int
238
+ msg: str
239
+ uploaded: Optional[bool]
240
+ md5: Optional[str]
241
+ fileName: Optional[str]
242
+ attachID: Optional[int]
243
+ uploaded_chunks: Optional[list]
244
+ uploadID: Optional[str]
245
+ uuid: Optional[str]
246
+ repo_id: Optional[str]
247
+ dataset_or_model_name: Optional[str]
248
+ realName: Optional[str]
249
+ datasetID: Optional[str]
250
+ upload_mode: Optional[str]
251
+
252
+ def __init__(self, **kwargs):
253
+ result_code = kwargs.pop("result_code", 0)
254
+ self.result_code = int(result_code)
255
+ self.msg = kwargs.pop("msg", "success")
256
+
257
+ uploaded = kwargs.pop("uploaded", "")
258
+ self.uploaded = True if uploaded == "1" else False
259
+ self.attachID = kwargs.pop("attachID", None)
260
+
261
+ raw_chunks = kwargs.pop("chunks", "")
262
+ uploaded_chunks = [i for i in raw_chunks.split(",") if i != ""]
263
+ self.uploaded_chunks = uploaded_chunks
264
+
265
+ uploadID = kwargs.pop("uploadID", "")
266
+ self.uploadID = uploadID if uploadID != "" else None
267
+ uuid = kwargs.pop("uuid", "")
268
+ self.uuid = uuid if uuid != "" else None
269
+
270
+ repo = kwargs.pop("repoName", None)
271
+ owner = kwargs.pop("repoOwner", None)
272
+ self.repo_id = owner + "/" + repo if owner and repo else None
273
+
274
+ if kwargs.pop("upload_mode") == "dataset":
275
+ self.dataset_or_model_name = kwargs.pop("datasetName", "")
276
+ else:
277
+ self.dataset_or_model_name = kwargs.pop("modelName", "")
278
+
279
+ self.fileName = kwargs.pop("fileName", "")
280
+ self.realName = self.fileName
281
+ self.datasetID = kwargs.pop("datasetID", "")
282
+ self.md5 = kwargs.pop("md5", None)
283
+ self.upload_mode = kwargs.pop("upload_mode", None)
284
+
285
+
286
+ @dataclass
287
+ class NewMultipart:
288
+ """TODO"""
289
+
290
+ result_code: int
291
+ msg: str
292
+ uuid: Optional[str]
293
+ uploadID: Optional[str]
294
+
295
+ def __init__(self, **kwargs):
296
+ result_code = kwargs.pop("result_code", 0)
297
+ self.result_code = int(result_code)
298
+ self.msg = kwargs.pop("msg", "success")
299
+ self.uuid = kwargs.pop("uuid", None)
300
+ self.uploadID = kwargs.pop("uploadID", None)
301
+
302
+
303
+ @dataclass
304
+ class MultipartUrl:
305
+ """TODO"""
306
+
307
+ url: Optional[str] = None
308
+ msg: Optional[str] = None
309
+
310
+
311
+ @dataclass
312
+ class ModelFile:
313
+ FileName: Optional[str]
314
+ ModTime: Optional[str]
315
+ IsDir: Optional[bool]
316
+ Size: Optional[int]
317
+ ParenDir: Optional[str]
318
+ UUID: Optional[str]
319
+ RelativePath: Optional[str]
320
+ repo_id: Optional[str]
321
+ model_id: Optional[str]
322
+ IsSupportPreview: Optional[str] = ""
323
+
324
+
325
+ @dataclass
326
+ class ModelInfo:
327
+ id: Optional[str]
328
+ name: Optional[str]
329
+ size: Optional[int]
330
+ path: Optional[str]
331
+ repo_id: Optional[str]
332
+ repoId: Optional[int]
333
+ userId: Optional[int]
334
+ userName: Optional[str]
335
+ isCanOper: Optional[bool]
336
+ isCanDelete: Optional[bool]
337
+ isCanDownload: Optional[bool]
338
+ repoName: Optional[str]
339
+ repoOwnerName: Optional[str]
340
+ modelFileList: Optional[List[ModelFile]]
341
+ modelType: Optional[int]
342
+
343
+ def __init__(self, **kwargs):
344
+ self.id = kwargs.pop("id", None)
345
+ self.name = kwargs.pop("name", None)
346
+ self.size = kwargs.pop("size", None)
347
+ self.path = kwargs.pop("path", None)
348
+ self.repo_id = kwargs.pop("repo_id", None)
349
+ self.repoId = kwargs.pop("repoId", None)
350
+ self.userId = kwargs.pop("userId", None)
351
+ self.userName = kwargs.pop("userName", None)
352
+ self.isCanOper = kwargs.pop("isCanOper", None)
353
+ self.isCanDelete = kwargs.pop("isCanDelete", None)
354
+ self.isCanDownload = kwargs.pop("isCanDownload", None)
355
+ self.repoName = kwargs.pop("repoName", None)
356
+ self.repoOwnerName = kwargs.pop("repoOwnerName", None)
357
+
358
+ modelFileList = kwargs.pop("modelFileList", [])
359
+ if modelFileList:
360
+ for data in modelFileList:
361
+ data.update({"repo_id": self.repo_id, "model_id": self.id})
362
+ self.modelFileList = [ModelFile(**data) for data in modelFileList]
363
+ else:
364
+ self.modelFileList = None
365
+
366
+ self.modelType = kwargs.pop("modelType", None)
367
+
368
+
369
+ @dataclass
370
+ class ModelCreate:
371
+ code: str
372
+ msg: Optional[str] = None
373
+ id: Optional[int] = None
374
+
375
+
376
+ @dataclass
377
+ class BasicResp:
378
+ code: int
379
+ msg: str
380
+ data: any
381
+
382
+
383
+ @dataclass
384
+ class CreateRepoOption:
385
+ name: str
386
+ alias: Optional[str] = None
387
+ description: Optional[str] = None
388
+ private: bool = False
389
+ issue_labels: Optional[str] = None
390
+ auto_init: bool = False
391
+ gitignores: Optional[str] = None
392
+ license: Optional[str] = None
393
+ readme: Optional[str] = None
394
+ default_branch: Optional[str] = None
395
+
396
+ def __post_init__(self):
397
+ if len(self.name) > 100:
398
+ raise ValueError("Name must be at most 100 characters long")
399
+ if self.alias and len(self.alias) > 100:
400
+ raise ValueError("Alias must be at most 100 characters long")
401
+ if self.description and len(self.description) > 255:
402
+ raise ValueError("Description must be at most 255 characters long")
403
+ if self.default_branch and len(self.default_branch) > 100:
404
+ raise ValueError("Default branch must be at most 100 characters long")
gsnet/_exceptions.py ADDED
@@ -0,0 +1,273 @@
1
+ import logging
2
+ import re
3
+ from functools import wraps
4
+ from inspect import signature
5
+ from pathlib import Path
6
+ from typing import Callable, Type, TypeVar
7
+
8
+ from gsnet.refactor.constants import REPO_ID_REGEX
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class TokenNotFoundWarn(Warning):
14
+ def __init__(self):
15
+ self.message = (
16
+ "未找到本地 token;若遇到提示 PageNotFound 或 UnauthorizedError,"
17
+ "则需要使用 `login` 保存GSnet账户 token 到本地以获取授权。"
18
+ )
19
+
20
+ def __str__(self):
21
+ return repr(self.message)
22
+
23
+
24
+ class GSnetError(BaseException):
25
+ def __init__(self, msg):
26
+ self.msg = msg
27
+
28
+ def __str__(self):
29
+ return "❌ " + self.msg
30
+
31
+ def __repr__(self):
32
+ return "❌ " + self.msg
33
+
34
+
35
+ class ServerError(GSnetError):
36
+ def __init__(self, status_code: int):
37
+ self.msg = f"{status_code} GSnet服务器暂时不可用,请联系社区管理员或稍后再试"
38
+
39
+
40
+ class HttpProxyError(GSnetError):
41
+ def __init__(self):
42
+ self.msg = "无法发送请求,请检查网络代理"
43
+
44
+
45
+ class HttpConnectionError(GSnetError):
46
+ def __init__(self):
47
+ self.msg = "无法连接网络,请检查网络设置"
48
+
49
+
50
+ class InvalidTokenError(GSnetError):
51
+ def __init__(self):
52
+ self.msg = f"Invalid or broken GSnet token."
53
+
54
+
55
+ class TokenNotFoundError(GSnetError):
56
+ def __init__(self):
57
+ token_help_doc_url = "https://gsnet.pcl.ac.cn/docs/index.html#/api/token"
58
+ self.msg = f"未找到本地 token;请先使用 `gsnet login` 保存GSnet账户 token 到本地以获取授权。具体使用方法请参考: {token_help_doc_url}"
59
+
60
+
61
+ class UnauthorizedError(GSnetError):
62
+ def __init__(self, status_code: int = 401):
63
+ self.msg = f"{status_code} 您无权建立此连接。请确保您拥有对应的权限。"
64
+
65
+
66
+ class PageNotFound(GSnetError):
67
+ def __init__(self):
68
+ self.msg = "无效请求,请确保仓库路径填写正确并且您拥有对应的权限"
69
+
70
+
71
+ class ParamsTypeError(GSnetError):
72
+ def __init__(
73
+ self,
74
+ arg_name: str,
75
+ arg_value: any,
76
+ accepted_type: Type[any],
77
+ ):
78
+ self.msg = f"`{arg_name}` 参数类型错误 {type(arg_value)}: `{arg_value}`. " f"正确的参数类型为 {accepted_type}"
79
+
80
+
81
+ class RepoIdError(GSnetError):
82
+ def __init__(self, repo_id):
83
+ self.msg = f"`{repo_id}` 参数格式错误. 正确的 `repo_id` 参数格式应为: `用户名/仓库名`"
84
+
85
+
86
+ class RepoNotFoundError(GSnetError):
87
+ def __init__(self, repo_id):
88
+ self.msg = f"仓库不存在: `{repo_id}`"
89
+
90
+
91
+ class RepoExistsError(GSnetError):
92
+ def __init__(self, repo_id):
93
+ self.msg = f"仓库已存在: `{repo_id}`,请勿重复创建"
94
+
95
+
96
+ class KeyboardInterruptError(GSnetError):
97
+ def __init__(self, msg):
98
+ self.msg = f"用户中断操作; {msg}"
99
+
100
+
101
+ class DatasetNotFound(GSnetError):
102
+ def __init__(self, repo_id, dataset_url):
103
+ self.msg = f"`{repo_id}` 仓库尚未创建数据集: {dataset_url}"
104
+
105
+
106
+ class EmptyDataset(GSnetError):
107
+ def __init__(self, repo_id, dataset_url):
108
+ self.msg = f"`{repo_id}` 仓库数据集内未找到任何文件: {dataset_url}"
109
+
110
+
111
+ class ModelCreateError(GSnetError):
112
+ def __init__(self, model_name, msg):
113
+ self.msg = f" `{model_name}` 模型创建失败: {msg}"
114
+
115
+
116
+ class ModelNotFoundError(GSnetError):
117
+ def __init__(self, model_name, model_list_url):
118
+ self.msg = f"模型不存在 `{model_name}`; 请在网页端查看正确模型名称: {model_list_url}"
119
+
120
+
121
+ class ServerFileExistsError(GSnetError):
122
+ def __init__(
123
+ self,
124
+ filename: str,
125
+ existing_filename: str,
126
+ existing_repo_id: str = None,
127
+ ):
128
+ if existing_repo_id:
129
+ self.msg = (
130
+ f"`{filename}` 该文件已被上传为 {existing_repo_id} 仓库中的 `{existing_filename}` 文件, 无法重复上传"
131
+ )
132
+ else:
133
+ self.msg = f"`{filename}` 文件已上传, 无法重复上传"
134
+
135
+
136
+ class ServerFileNotFoundError(GSnetError):
137
+ def __init__(self, msg):
138
+ self.msg = msg
139
+
140
+
141
+ class EmptyFolderError(GSnetError):
142
+ def __init__(self, local_dir: Path):
143
+ self.msg = f"空目录,未能找到任何本地文件: {local_dir.absolute()}"
144
+
145
+
146
+ class LocalPathNotFound(GSnetError):
147
+ def __init__(self, filepath: Path):
148
+ self.msg = f"本地文件或目录不存在: {filepath.absolute()}"
149
+
150
+
151
+ class LocalDirNotFound(GSnetError):
152
+ def __init__(self, local_dir: Path):
153
+ self.msg = f"本地目录不存在: {local_dir.absolute()}"
154
+
155
+
156
+ class FileTypeError(GSnetError):
157
+ def __init__(self, filepath: Path):
158
+ self.msg = f"非压缩文件(`.zip` 或 `.tar.gz`): {filepath.absolute()}"
159
+
160
+
161
+ class FileSizeError(GSnetError):
162
+ def __init__(self, msg):
163
+ self.msg = msg
164
+
165
+
166
+ class PutUploadError(GSnetError):
167
+ def __init__(self, msg):
168
+ self.msg = msg
169
+
170
+
171
+ class UploadError(GSnetError):
172
+ def __init__(self, msg):
173
+ self.msg = msg
174
+
175
+
176
+ CallableT = TypeVar("CallableT", bound=Callable)
177
+
178
+
179
+ def validate_gsnet_args(fn: CallableT) -> CallableT:
180
+ """Decorator that retrieves and prints all input arguments of a function.
181
+
182
+ Args:
183
+ fn: The function to be decorated.
184
+
185
+ Returns:
186
+ A wrapper function that prints arguments and calls the original function.
187
+ """
188
+
189
+ @wraps(fn)
190
+ def _inner_fn(*args, **kwargs):
191
+ params = signature(fn).parameters
192
+ arg_names = [param.name for param in params.values()]
193
+
194
+ _kwargs = dict()
195
+
196
+ for i, arg_name in enumerate(arg_names):
197
+ if i < len(args):
198
+ value = args[i]
199
+ else:
200
+ value = kwargs.get(arg_name, None)
201
+ _kwargs.update({arg_name: value})
202
+
203
+ repo_id = _kwargs.get("repo_id", None)
204
+ if not repo_id or not isinstance(repo_id, str):
205
+ raise ParamsTypeError(
206
+ arg_name="repo_id",
207
+ arg_value=repo_id,
208
+ accepted_type=str,
209
+ )
210
+ if not re.match(REPO_ID_REGEX, repo_id):
211
+ raise RepoIdError(
212
+ repo_id=repo_id,
213
+ )
214
+
215
+ filename = _kwargs.get("file", None)
216
+ if filename and not isinstance(filename, (Path, str)):
217
+ raise ParamsTypeError(
218
+ arg_name="file",
219
+ arg_value=filename,
220
+ accepted_type="either a pathlib.Path() object or str",
221
+ )
222
+
223
+ cluster = _kwargs.get("cluster", None)
224
+ if cluster and (not isinstance(cluster, str) or cluster.lower() not in ["gpu", "npu"]):
225
+ raise ParamsTypeError(
226
+ arg_name="cluster",
227
+ arg_value=cluster,
228
+ accepted_type="['gpu', 'npu'] case insensitive",
229
+ )
230
+
231
+ save_path = _kwargs.get("save_path", None)
232
+ if save_path and not isinstance(save_path, (Path, str)):
233
+ raise ParamsTypeError(
234
+ arg_name="save_path",
235
+ arg_value=save_path,
236
+ accepted_type="either a pathlib.Path() object or str",
237
+ )
238
+
239
+ force = _kwargs.get("force", None)
240
+ if force and not isinstance(force, bool):
241
+ raise ParamsTypeError(
242
+ arg_name="force",
243
+ arg_value=force,
244
+ accepted_type=bool,
245
+ )
246
+
247
+ model_name = _kwargs.get("model_name", None)
248
+ if model_name and not isinstance(model_name, str):
249
+ raise ParamsTypeError(
250
+ arg_name="model_name",
251
+ arg_value=model_name,
252
+ accepted_type=str,
253
+ )
254
+
255
+ upload_name = _kwargs.get("upload_name", None)
256
+ if upload_name and not isinstance(upload_name, str):
257
+ raise ParamsTypeError(
258
+ arg_name="upload_name",
259
+ arg_value=upload_name,
260
+ accepted_type=str,
261
+ )
262
+
263
+ folder = _kwargs.get("folder", None)
264
+ if folder and not isinstance(folder, (Path, str)):
265
+ raise ParamsTypeError(
266
+ arg_name="folder",
267
+ arg_value=folder,
268
+ accepted_type=str,
269
+ )
270
+
271
+ return fn(*args, **kwargs)
272
+
273
+ return _inner_fn