xiaoshiai-hub 1.1.1__py3-none-any.whl → 1.1.3__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.
xiaoshiai_hub/upload.py CHANGED
@@ -12,7 +12,7 @@ from typing import List, Optional, Union, Dict
12
12
  import requests
13
13
 
14
14
  from xiaoshiai_hub.client import DEFAULT_BASE_URL, HubClient
15
- from xiaoshiai_hub.envelope_crypto import DataKey, envelope_enc_file
15
+ from xiaoshiai_hub.envelope_crypto import Algorithm, DataKey, envelope_enc_file
16
16
  from .exceptions import HubException, AuthenticationError, RepositoryNotFoundError
17
17
 
18
18
 
@@ -70,61 +70,98 @@ def _calculate_file_sha256(file_path: Path) -> str:
70
70
  return sha256_hash.hexdigest()
71
71
 
72
72
 
73
- class _TqdmUploadWrapper:
74
- """Wrapper to add tqdm progress bar to file upload."""
73
+ class _ProgressFileReader:
74
+ """
75
+ 文件读取器,跟踪实际网络上传进度。
76
+
77
+ 通过分块读取文件并在每次 read() 调用后更新进度条,
78
+ 配合 requests 的流式上传,确保进度条反映实际网络传输进度。
79
+ """
75
80
 
76
- def __init__(self, file_obj, total_size, desc=None):
77
- self.file_obj = file_obj
78
- self.total_size = total_size
81
+ def __init__(self, file_path: Path, chunk_size: int = 8192, desc: Optional[str] = None):
82
+ self.file_path = file_path
83
+ self.file_size = file_path.stat().st_size
84
+ self.chunk_size = chunk_size
85
+ self.file_obj = open(file_path, 'rb')
86
+ self.bytes_read = 0
79
87
  self.pbar = None
80
88
  if tqdm:
81
89
  self.pbar = tqdm(
82
- total=total_size,
90
+ total=self.file_size,
83
91
  unit='B',
84
92
  unit_scale=True,
85
93
  unit_divisor=1024,
86
94
  desc=desc,
87
95
  )
88
96
 
89
- def read(self, size=-1):
90
- """Read data and update progress bar."""
97
+ def read(self, size: int = -1) -> bytes:
98
+ """读取数据并更新进度条。"""
99
+ if size == -1:
100
+ size = self.chunk_size
91
101
  data = self.file_obj.read(size)
92
- if self.pbar is not None and data:
93
- self.pbar.update(len(data))
102
+ if data:
103
+ self.bytes_read += len(data)
104
+ if self.pbar is not None:
105
+ self.pbar.update(len(data))
94
106
  return data
95
107
 
96
- def __enter__(self):
108
+ def __len__(self) -> int:
109
+ """返回文件大小,供 requests 设置 Content-Length。"""
110
+ return self.file_size
111
+
112
+ def __iter__(self):
113
+ """迭代器,用于流式上传。"""
97
114
  return self
98
115
 
99
- def __exit__(self, exc_type, exc_val, exc_tb): # type: ignore[no-untyped-def]
100
- del exc_type, exc_val, exc_tb # Unused but required by context manager protocol
116
+ def __next__(self) -> bytes:
117
+ data = self.read(self.chunk_size)
118
+ if data:
119
+ return data
120
+ raise StopIteration
121
+
122
+ def close(self):
101
123
  if self.pbar is not None:
102
124
  self.pbar.close()
103
125
  self.file_obj.close()
104
126
 
127
+ def __enter__(self):
128
+ return self
129
+
130
+ def __exit__(self, exc_type, exc_val, exc_tb):
131
+ del exc_type, exc_val, exc_tb
132
+ self.close()
133
+
105
134
 
106
135
  def _upload_file_with_progress(
107
136
  upload_url: str,
108
137
  file_path: Path,
109
138
  desc: Optional[str] = None,
139
+ chunk_size: int = 1024 * 1024, # 1MB chunks
110
140
  ) -> None:
111
- """Upload file to URL with progress bar."""
141
+ """
142
+ 上传文件到 URL 并显示真实的网络传输进度。
143
+
144
+ 使用分块流式上传,进度条反映实际发送到服务器的字节数。
145
+ """
112
146
  file_size = file_path.stat().st_size
113
147
 
114
- with open(file_path, 'rb') as f:
115
- with _TqdmUploadWrapper(f, file_size, desc=desc) as wrapped_file:
116
- upload_response = requests.put(
117
- upload_url,
118
- data=wrapped_file,
119
- headers={'Content-Type': 'application/octet-stream'}
120
- )
121
- upload_response.raise_for_status()
148
+ with _ProgressFileReader(file_path, chunk_size=chunk_size, desc=desc) as reader:
149
+ upload_response = requests.put(
150
+ upload_url,
151
+ data=reader,
152
+ headers={
153
+ 'Content-Type': 'application/octet-stream',
154
+ 'Content-Length': str(file_size),
155
+ }
156
+ )
157
+ upload_response.raise_for_status()
122
158
 
123
159
 
124
160
  def _encrypt_file_if_needed(
125
161
  file_path: Path,
126
162
  encryption_password: Optional[str] = None,
127
163
  data_key: Optional[DataKey] = None,
164
+ algorithm: Optional[Algorithm] = None,
128
165
  ) -> tuple[Optional[Path], Optional[Path]]:
129
166
  """
130
167
  Encrypt file if encryption_password is provided, file is large enough, and file extension is encryptable.
@@ -133,6 +170,7 @@ def _encrypt_file_if_needed(
133
170
  file_path: Path to the file to encrypt
134
171
  encryption_password: Password for encryption
135
172
  data_key: DataKey for encryption (required if encryption_password is provided)
173
+ algorithm: Encryption algorithm (default: AES-256-CTR)
136
174
 
137
175
  Returns:
138
176
  Tuple of (encrypted_file_path, temp_dir_path)
@@ -154,13 +192,15 @@ def _encrypt_file_if_needed(
154
192
  encrypted_file = temp_dir / file_path.name
155
193
 
156
194
  # Encrypt the file
157
- envelope_enc_file(
158
- source=file_path,
159
- password=encryption_password,
160
- data_key=data_key,
161
- dest=encrypted_file,
162
- chunked=True,
163
- )
195
+ enc_kwargs = {
196
+ "source": file_path,
197
+ "data_key": data_key,
198
+ "dest": encrypted_file,
199
+ "chunked": True,
200
+ }
201
+ if algorithm:
202
+ enc_kwargs["algorithm"] = algorithm
203
+ envelope_enc_file(**enc_kwargs)
164
204
  print(f"Encrypted file path: {encrypted_file}")
165
205
 
166
206
  return encrypted_file, temp_dir
@@ -295,6 +335,7 @@ def upload_folder(
295
335
  encryption_password: Optional[str] = None,
296
336
  ignore_patterns: Optional[List[str]] = None,
297
337
  temp_dir: Optional[Union[str, Path]] = None,
338
+ algorithm: Optional[str] = None,
298
339
  ) -> Dict:
299
340
  """
300
341
  Upload a folder to a repository using HTTP API.
@@ -313,6 +354,7 @@ def upload_folder(
313
354
  encryption_password: Password for file encryption (optional)
314
355
  ignore_patterns: List of patterns to ignore
315
356
  temp_dir: Temporary directory for encrypted files (optional, auto-created if not specified)
357
+ algorithm: Encryption algorithm ("AES-256-CTR" or "SM4-CTR", default: AES-256-CTR)
316
358
 
317
359
  Returns:
318
360
  Upload response
@@ -361,7 +403,7 @@ def upload_folder(
361
403
  # Auto-create temp directory
362
404
  temp_dir_path = Path(tempfile.mkdtemp())
363
405
  # Generate data key for encryption
364
- data_key = client.generate_data_key(encryption_password)
406
+ data_key = client.generate_data_key(algorithm,encryption_password)
365
407
 
366
408
  try:
367
409
  # Create session and API URL
@@ -409,13 +451,16 @@ def upload_folder(
409
451
  # Preserve directory structure in temp dir
410
452
  encrypted_file = temp_dir_path / rel_file_path
411
453
  encrypted_file.parent.mkdir(parents=True, exist_ok=True)
412
- envelope_enc_file(
413
- source=local_file,
414
- password=encryption_password,
415
- data_key=data_key,
416
- dest=encrypted_file,
417
- chunked=True,
418
- )
454
+ # Build encryption kwargs
455
+ enc_kwargs = {
456
+ "source": local_file,
457
+ "data_key": data_key,
458
+ "dest": encrypted_file,
459
+ "chunked": True,
460
+ }
461
+ if algorithm:
462
+ enc_kwargs["algorithm"] = Algorithm(algorithm)
463
+ envelope_enc_file(**enc_kwargs)
419
464
  print(f"Encrypted file path: {encrypted_file}")
420
465
  # 加密后重新计算大小,避免被huggingface下载的时候大小一致性检查不通过
421
466
  file_size = encrypted_file.stat().st_size
@@ -512,6 +557,7 @@ def upload_file(
512
557
  password: Optional[str] = None,
513
558
  token: Optional[str] = None,
514
559
  encryption_password: Optional[str] = None,
560
+ algorithm: Optional[str] = None,
515
561
  ) -> Dict:
516
562
  """
517
563
  Upload a single file to a repository using HTTP API.
@@ -529,6 +575,7 @@ def upload_file(
529
575
  password: Password for authentication
530
576
  token: Token for authentication (preferred)
531
577
  encryption_password: Password for file encryption (optional)
578
+ algorithm: Encryption algorithm ("AES" or "SM4", default: AES)
532
579
 
533
580
  Returns:
534
581
  Upload response
@@ -561,10 +608,11 @@ def upload_file(
561
608
  # Generate data key if encryption is needed
562
609
  data_key: Optional[DataKey] = None
563
610
  if encryption_password:
564
- data_key = client.generate_data_key(encryption_password)
611
+ data_key = client.generate_data_key(algorithm,encryption_password)
565
612
 
566
613
  # Encrypt file if needed
567
- encrypted_file, temp_dir = _encrypt_file_if_needed(path_file, encryption_password, data_key)
614
+ algo = Algorithm(algorithm) if algorithm else None
615
+ encrypted_file, temp_dir = _encrypt_file_if_needed(path_file, encryption_password, data_key, algo)
568
616
  actual_file = encrypted_file if encrypted_file else path_file
569
617
  file_was_encrypted = encrypted_file is not None
570
618
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xiaoshiai-hub
3
- Version: 1.1.1
3
+ Version: 1.1.3
4
4
  Summary: Python SDK for XiaoShi AI Hub - Upload, download, and manage AI models and datasets with xpai-enc encryption support
5
5
  Home-page: https://github.com/poxiaoyun/moha-sdk
6
6
  Author: XiaoShi AI
@@ -244,25 +244,65 @@ client = HubClient(
244
244
  password="your-password",
245
245
  )
246
246
 
247
+ # 创建仓库
248
+ repo = client.create_repository(
249
+ organization="demo",
250
+ repo_type="models",
251
+ repo_name="my-model",
252
+ description="我的模型",
253
+ visibility="internal",
254
+ metadata={
255
+ "license": ["apache-2.0"],
256
+ "frameworks": ["transformers"],
257
+ },
258
+ )
259
+ print(f"仓库已创建: {repo.name}")
260
+
247
261
  # 获取仓库信息
248
262
  repo_info = client.get_repository_info("demo", "models", "my-model")
249
263
  print(f"仓库名称: {repo_info.name}")
250
264
  print(f"组织: {repo_info.organization}")
265
+ print(f"所有者: {repo_info.owner}")
266
+ print(f"可见性: {repo_info.visibility}")
267
+
268
+ # 更新仓库
269
+ client.update_repository(
270
+ organization="demo",
271
+ repo_type="models",
272
+ repo_name="my-model",
273
+ description="更新后的描述",
274
+ )
251
275
 
252
276
  # 列出分支
253
- branches = client.list_branches("demo", "models", "my-model")
254
- for branch in branches:
255
- print(f"分支: {branch.name} (commit: {branch.commit_sha})")
277
+ refs = client.get_repository_refs("demo", "models", "my-model")
278
+ for ref in refs:
279
+ print(f"分支: {ref.name} (commit: {ref.hash[:8]})")
280
+
281
+ # 创建分支(幂等操作,已存在则直接返回)
282
+ client.create_branch("demo", "models", "my-model", "dev", "main")
283
+
284
+ # 删除分支(幂等操作,不存在则直接返回)
285
+ client.delete_branch("demo", "models", "my-model", "dev")
256
286
 
257
287
  # 浏览仓库内容
258
288
  content = client.get_repository_content("demo", "models", "my-model", "main")
259
289
  for entry in content.entries:
260
290
  print(f"{entry.type}: {entry.name}")
291
+
292
+ # 删除仓库
293
+ client.delete_repository("demo", "models", "my-model")
261
294
  ```
262
295
 
263
296
  ## 🔐 加密功能
264
297
 
265
- SDK 提供了智能加密功能,使用 AES-256-CTR 算法对大型模型文件进行加密。
298
+ SDK 提供了智能加密功能,支持 **AES** 和 **SM4** 两种加密算法对大型模型文件进行加密。
299
+
300
+ ### 支持的加密算法
301
+
302
+ | 算法 | 说明 |
303
+ |------|------|
304
+ | `AES` | AES-256-CTR 模式,国际通用标准(默认) |
305
+ | `SM4` | SM4-CTR 模式,国密标准 |
266
306
 
267
307
  ### 自动加密规则
268
308
 
@@ -278,11 +318,21 @@ SDK 提供了智能加密功能,使用 AES-256-CTR 算法对大型模型文件
278
318
  ```python
279
319
  from xiaoshiai_hub import upload_folder
280
320
 
281
- # 上传文件夹,自动加密大型模型文件
321
+ # 上传文件夹,使用 AES 加密(默认)
282
322
  result = upload_folder(
283
323
  folder_path="./llama-7b",
284
324
  repo_id="demo/llama-7b",
285
- encryption_password="my-secure-password-123", # 设置加密密码
325
+ encryption_password="my-secure-password-123",
326
+ username="your-username",
327
+ password="your-password",
328
+ )
329
+
330
+ # 使用 SM4 国密算法加密
331
+ result = upload_folder(
332
+ folder_path="./llama-7b",
333
+ repo_id="demo/llama-7b",
334
+ encryption_password="my-secure-password-123",
335
+ algorithm="SM4", # 使用 SM4 加密
286
336
  username="your-username",
287
337
  password="your-password",
288
338
  )
@@ -326,7 +376,7 @@ export MOHA_ENCRYPTION_PASSWORD="your-encryption-password"
326
376
 
327
377
  ## 🖥️ 命令行工具 (CLI)
328
378
 
329
- SDK 提供了 `moha` 命令行工具,支持常见的上传下载操作。
379
+ SDK 提供了 `moha` 命令行工具,支持登录认证、仓库管理、分支管理、上传下载等操作。
330
380
 
331
381
  ### 基本用法
332
382
 
@@ -334,6 +384,75 @@ SDK 提供了 `moha` 命令行工具,支持常见的上传下载操作。
334
384
  moha --help
335
385
  ```
336
386
 
387
+ ### 登录认证
388
+
389
+ ```bash
390
+ # 登录(交互式输入用户名和密码)
391
+ moha login
392
+
393
+ # 直接指定用户名和密码
394
+ moha login --username your-username --password your-password
395
+
396
+ # 查看当前登录状态
397
+ moha whoami
398
+
399
+ # 退出登录
400
+ moha logout
401
+ ```
402
+
403
+ 登录后,Token 会保存到 `~/.moha/token.json`,后续命令无需重复输入认证信息。
404
+
405
+ ### 仓库管理
406
+
407
+ ```bash
408
+ # 创建仓库
409
+ moha repo-create org/my-model \
410
+ --description "我的模型" \
411
+ --visibility internal \
412
+ --license apache-2.0 \
413
+ --tasks text-generation \
414
+ --frameworks transformers
415
+
416
+ # 创建数据集仓库
417
+ moha repo-create org/my-dataset \
418
+ --repo-type datasets \
419
+ --description "我的数据集" \
420
+ --visibility private
421
+
422
+ # 查看仓库信息
423
+ moha repo-info org/my-model
424
+
425
+ # 更新仓库信息
426
+ moha repo-update org/my-model \
427
+ --description "更新后的描述" \
428
+ --tags production
429
+
430
+ # 删除仓库(需要确认)
431
+ moha repo-delete org/my-model
432
+
433
+ # 跳过确认直接删除
434
+ moha repo-delete org/my-model -y
435
+ ```
436
+
437
+ ### 分支管理
438
+
439
+ ```bash
440
+ # 列出仓库的所有分支
441
+ moha branch-list org/my-model
442
+
443
+ # 创建分支(基于 main 分支)
444
+ moha branch-create org/my-model dev
445
+
446
+ # 创建分支(基于指定分支)
447
+ moha branch-create org/my-model feature --from dev
448
+
449
+ # 删除分支
450
+ moha branch-delete org/my-model dev
451
+
452
+ # 跳过确认直接删除
453
+ moha branch-delete org/my-model dev -y
454
+ ```
455
+
337
456
  ### 上传文件夹
338
457
 
339
458
  ```bash
@@ -353,10 +472,18 @@ moha upload ./my_model org/my-model \
353
472
  --username your-username \
354
473
  --password your-password
355
474
 
356
- # 启用加密
475
+ # 启用加密(默认使用 AES)
476
+ moha upload ./my_model org/my-model \
477
+ --encrypt \
478
+ --encryption-password "your-secret" \
479
+ --username your-username \
480
+ --password your-password
481
+
482
+ # 使用 SM4 国密算法加密
357
483
  moha upload ./my_model org/my-model \
358
484
  --encrypt \
359
485
  --encryption-password "your-secret" \
486
+ --algorithm SM4 \
360
487
  --username your-username \
361
488
  --password your-password
362
489
  ```
@@ -419,26 +546,75 @@ moha download-file org/my-model model.safetensors \
419
546
  --password your-password
420
547
  ```
421
548
 
549
+ ### CLI 命令列表
550
+
551
+ | 命令 | 说明 |
552
+ |------|------|
553
+ | `moha login` | 登录并保存 Token |
554
+ | `moha logout` | 退出登录并删除 Token |
555
+ | `moha whoami` | 查看当前登录状态 |
556
+ | `moha repo-create` | 创建仓库 |
557
+ | `moha repo-update` | 更新仓库 |
558
+ | `moha repo-delete` | 删除仓库 |
559
+ | `moha repo-info` | 查看仓库信息 |
560
+ | `moha branch-create` | 创建分支 |
561
+ | `moha branch-delete` | 删除分支 |
562
+ | `moha branch-list` | 列出仓库的所有分支 |
563
+ | `moha upload` | 上传文件夹到仓库 |
564
+ | `moha upload-file` | 上传单个文件到仓库 |
565
+ | `moha download` | 下载整个仓库 |
566
+ | `moha download-file` | 从仓库下载单个文件 |
567
+
422
568
  ### CLI 参数说明
423
569
 
570
+ #### 通用参数
571
+
424
572
  | 参数 | 说明 | 适用命令 |
425
573
  |------|------|----------|
426
- | `--repo-type, -t` | 仓库类型:`models` 或 `datasets`(默认:models) | 所有 |
427
- | `--revision, -r` | 分支/标签/提交(默认:main) | 所有 |
574
+ | `--repo-type, -t` | 仓库类型:`models` 或 `datasets`(默认:models) | 大部分命令 |
428
575
  | `--base-url` | API 基础 URL(默认:环境变量 MOHA_ENDPOINT) | 所有 |
429
576
  | `--token` | 认证令牌 | 所有 |
430
577
  | `--username` | 用户名 | 所有 |
431
578
  | `--password` | 密码 | 所有 |
579
+
580
+ #### 上传/下载参数
581
+
582
+ | 参数 | 说明 | 适用命令 |
583
+ |------|------|----------|
584
+ | `--revision, -r` | 分支/标签/提交(默认:main) | upload, download |
432
585
  | `--message, -m` | 提交消息 | upload, upload-file |
433
586
  | `--ignore, -i` | 忽略模式(可多次使用) | upload, download |
434
587
  | `--include` | 包含模式(可多次使用) | download |
435
588
  | `--encrypt, -e` | 启用加密 | upload, upload-file |
436
589
  | `--encryption-password` | 加密密码 | upload, upload-file |
590
+ | `--algorithm, -a` | 加密算法:`AES` 或 `SM4`(默认:AES) | upload, upload-file |
437
591
  | `--path-in-repo, -p` | 仓库中的文件路径 | upload-file |
438
592
  | `--temp-dir` | 加密临时目录 | upload |
439
593
  | `--local-dir, -o` | 本地保存目录 | download, download-file |
440
594
  | `--quiet, -q` | 禁用进度条 | download, download-file |
441
595
 
596
+ #### 仓库管理参数
597
+
598
+ | 参数 | 说明 | 适用命令 |
599
+ |------|------|----------|
600
+ | `--description, -d` | 仓库描述 | repo-create, repo-update |
601
+ | `--visibility, -v` | 可见性:`public`、`internal`、`private` | repo-create, repo-update |
602
+ | `--license` | 许可证(可多次使用) | repo-create, repo-update |
603
+ | `--tasks` | 任务类型(可多次使用) | repo-create, repo-update |
604
+ | `--languages` | 语言(可多次使用) | repo-create, repo-update |
605
+ | `--tags` | 标签(可多次使用) | repo-create, repo-update |
606
+ | `--frameworks` | 框架(可多次使用) | repo-create, repo-update |
607
+ | `--base-model` | 基础模型(可多次使用) | repo-create, repo-update |
608
+ | `--relationship` | 与基础模型的关系 | repo-create, repo-update |
609
+ | `--yes, -y` | 跳过确认提示 | repo-delete, branch-delete |
610
+
611
+ #### 分支管理参数
612
+
613
+ | 参数 | 说明 | 适用命令 |
614
+ |------|------|----------|
615
+ | `--from, -f` | 基于哪个分支创建(默认:main) | branch-create |
616
+ | `--yes, -y` | 跳过确认提示 | branch-delete |
617
+
442
618
  ### 使用环境变量
443
619
 
444
620
  可以通过环境变量设置认证信息,避免每次输入:
@@ -0,0 +1,15 @@
1
+ xiaoshiai_hub/__init__.py,sha256=2hnhTGad1GPTzRstfwZhAF2204Pl2VF8YHD8HQkAYGY,1469
2
+ xiaoshiai_hub/auth.py,sha256=Pv0P6f76flOefYmALyehuMu2Klyc-u_gtXlJYJR4eMY,4105
3
+ xiaoshiai_hub/cli.py,sha256=E2xWvybOz6Tr8bSk8pp-QZVHoCyQfnmCYg7442aq4-Y,29790
4
+ xiaoshiai_hub/client.py,sha256=3ASE_KuV-S0CmDvutvmMpY3GU2Hdrui2WAfwHs3iEkw,18775
5
+ xiaoshiai_hub/download.py,sha256=9Uido7cJjGVd6ERDKu_xNMPliarPdZVVb8hkLgYfFcU,13613
6
+ xiaoshiai_hub/envelope_crypto.py,sha256=zjrt5fc3ya86Y4N7_4OI5_NnmFpQ5HiHgoP31ioJRmw,8235
7
+ xiaoshiai_hub/exceptions.py,sha256=24QzgHWq_4bes07UkC3vGi2oT8SMH6Xu4FNlKt52QHo,672
8
+ xiaoshiai_hub/types.py,sha256=-h8EctZo_bRJALufjSTaxIWf2bqHz2ZDCy3SCPfucHs,2004
9
+ xiaoshiai_hub/upload.py,sha256=GKlnsxsIVuLhCWpymupya74TNgTP0s8T-gKTOR-RMgw,22371
10
+ xiaoshiai_hub-1.1.3.dist-info/licenses/LICENSE,sha256=tS28u6VpvqNisRWGeufp-XYQc6p194vOGARl3OIjidA,9110
11
+ xiaoshiai_hub-1.1.3.dist-info/METADATA,sha256=RCvKnYGmiU5upd5HXYkK0RzitGZT-Wsjvw_6CDoBa8M,21630
12
+ xiaoshiai_hub-1.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
+ xiaoshiai_hub-1.1.3.dist-info/entry_points.txt,sha256=fVh_IA1mbRWl7LEd4-RhENMaspSBa4Hxbsg8_HDWc6Y,48
14
+ xiaoshiai_hub-1.1.3.dist-info/top_level.txt,sha256=9AQDFb5Xn7RLQPdbk1aA0QpntbKhlhlT6Z_g-zUBtlM,14
15
+ xiaoshiai_hub-1.1.3.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- xiaoshiai_hub/__init__.py,sha256=ZDZEGKBbv8zEDO9GkKPy0uiTva9gPPEMIU9_A_MzCZA,1339
2
- xiaoshiai_hub/auth.py,sha256=Pv0P6f76flOefYmALyehuMu2Klyc-u_gtXlJYJR4eMY,4105
3
- xiaoshiai_hub/cli.py,sha256=IKuHYGyk-Kg57BUquWyZFMK6rPfLMmwEOWGZq8E7LJs,14885
4
- xiaoshiai_hub/client.py,sha256=OQyyKD5kyDaPlI81-js1Uj9gYjVPkS60UicZAtokDVw,11914
5
- xiaoshiai_hub/download.py,sha256=9Uido7cJjGVd6ERDKu_xNMPliarPdZVVb8hkLgYfFcU,13613
6
- xiaoshiai_hub/envelope_crypto.py,sha256=PWZrVCkgQckFQO6putRDlZXkQoEYOkq5O0PPltdBDE4,7161
7
- xiaoshiai_hub/exceptions.py,sha256=24QzgHWq_4bes07UkC3vGi2oT8SMH6Xu4FNlKt52QHo,672
8
- xiaoshiai_hub/types.py,sha256=ZC5elxqles8_ODl-fCSssOzm9q8_KjA9mGpiGgObgls,1915
9
- xiaoshiai_hub/upload.py,sha256=cYKCvaxfO5wOmjCmWp_rgbTOdEr73MN2EoBUCwyqqvE,20713
10
- xiaoshiai_hub-1.1.1.dist-info/licenses/LICENSE,sha256=tS28u6VpvqNisRWGeufp-XYQc6p194vOGARl3OIjidA,9110
11
- xiaoshiai_hub-1.1.1.dist-info/METADATA,sha256=0zbLRQQGJbyp5nAcmloTSvoRe9LEXuB8pKGBWNgUudo,16689
12
- xiaoshiai_hub-1.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
- xiaoshiai_hub-1.1.1.dist-info/entry_points.txt,sha256=fVh_IA1mbRWl7LEd4-RhENMaspSBa4Hxbsg8_HDWc6Y,48
14
- xiaoshiai_hub-1.1.1.dist-info/top_level.txt,sha256=9AQDFb5Xn7RLQPdbk1aA0QpntbKhlhlT6Z_g-zUBtlM,14
15
- xiaoshiai_hub-1.1.1.dist-info/RECORD,,