tamar-file-hub-client 0.2.2__py3-none-any.whl → 0.2.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.

Potentially problematic release.


This version of tamar-file-hub-client might be problematic. Click here for more details.

@@ -0,0 +1,704 @@
1
+ Metadata-Version: 2.4
2
+ Name: tamar-file-hub-client
3
+ Version: 0.2.3
4
+ Summary: A Python SDK for gRPC-based file management system
5
+ Home-page: https://github.com/Tamar-Edge-AI/file-hub-client
6
+ Author: Oscar Ou
7
+ Author-email: oscar.ou@tamaredge.ai
8
+ License: MIT
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Topic :: Internet :: WWW/HTTP
21
+ Classifier: Topic :: Communications :: File Sharing
22
+ Classifier: Framework :: AsyncIO
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ Requires-Dist: grpcio>=1.67.1
27
+ Requires-Dist: grpcio-tools>=1.67.1
28
+ Requires-Dist: protobuf>=5.29.4
29
+ Requires-Dist: pydantic>=2.0.0
30
+ Requires-Dist: typing-extensions>=4.0.0; python_version < "3.10"
31
+ Requires-Dist: requests>=2.28.0
32
+ Requires-Dist: aiohttp>=3.8.0
33
+ Requires-Dist: aiofiles>=23.0.0
34
+ Requires-Dist: python-magic; platform_system != "Windows"
35
+ Requires-Dist: python-magic-bin~=0.4.14; platform_system == "Windows"
36
+ Dynamic: author
37
+ Dynamic: author-email
38
+ Dynamic: classifier
39
+ Dynamic: description
40
+ Dynamic: description-content-type
41
+ Dynamic: home-page
42
+ Dynamic: license
43
+ Dynamic: requires-dist
44
+ Dynamic: requires-python
45
+ Dynamic: summary
46
+
47
+ # File Hub Client
48
+
49
+ Python SDK,用于文件中心系统 - 一个支持传统文件、文件夹和电子表格(Taple)的综合文件管理系统。
50
+
51
+ ## 功能特性
52
+
53
+ - 🚀 **双模式支持**:提供异步(AsyncIO)和同步两种客户端实现
54
+ - 📁 **完整的文件管理**:上传、下载、分享、重命名、删除文件
55
+ - 📂 **文件夹管理**:创建、重命名、移动、删除分层文件夹结构
56
+ - 📊 **Taple电子表格**:类Excel的完整功能,包括工作表、行、列、单元格操作
57
+ - 🔄 **多种上传模式**:普通模式、流式模式,根据文件大小自动选择
58
+ - 🎯 **智能MIME检测**:26+种文件格式的魔术字节检测和扩展名推断
59
+ - 🤖 **AI友好**:完美支持AI模型输出(字节+MIME类型)
60
+ - 🔒 **上传保护**:支持GCS和OSS存储后端的禁止覆盖功能
61
+ - 🎨 **媒体压缩**:自动生成和管理压缩的图片/视频变体
62
+ - 📊 **批量操作**:批量状态查询和批量操作支持
63
+ - 🛡️ **健壮的错误处理**:完善的异常体系和自动重试机制
64
+ - 📝 **完整类型支持**:完整的类型提示,更好的IDE支持
65
+ - 📡 **gRPC日志**:JSON格式的请求/响应日志,可自定义级别
66
+ - 🔧 **灵活配置**:支持环境变量和程序化配置
67
+
68
+ ## 安装
69
+
70
+ ```bash
71
+ pip install file-hub-client
72
+ ```
73
+
74
+ ## 快速开始
75
+
76
+ ### 基础设置
77
+
78
+ ```python
79
+ from file_hub_client import AsyncFileHubClient, FileHubClient
80
+
81
+ # 异步客户端
82
+ async_client = AsyncFileHubClient(
83
+ host="your-file-hub-server.com",
84
+ port=50051,
85
+ use_tls=True
86
+ )
87
+
88
+ # 同步客户端
89
+ client = FileHubClient(
90
+ host="your-file-hub-server.com",
91
+ port=50051,
92
+ use_tls=True
93
+ )
94
+ ```
95
+
96
+ ### 环境变量配置
97
+
98
+ ```bash
99
+ # 服务器配置
100
+ FILE_HUB_HOST=your-file-hub-server.com
101
+ FILE_HUB_PORT=50051
102
+ FILE_HUB_USE_TLS=true
103
+
104
+ # 可选认证头
105
+ FILE_HUB_HEADER_X_ORG_ID=your-org-id
106
+ FILE_HUB_HEADER_X_USER_ID=your-user-id
107
+
108
+ # 日志配置
109
+ FILE_HUB_LOG_LEVEL=INFO
110
+ FILE_HUB_LOG_GRPC_ENABLED=true
111
+ FILE_HUB_LOG_REQUEST_PAYLOAD=false
112
+ FILE_HUB_LOG_RESPONSE_PAYLOAD=false
113
+ ```
114
+
115
+ ## 文件操作
116
+
117
+ ### 上传文件
118
+
119
+ ```python
120
+ # 简单上传
121
+ result = await async_client.blobs.upload(
122
+ file=b"Hello, World!",
123
+ file_name="hello.txt"
124
+ )
125
+ print(f"文件ID: {result.file.id}")
126
+
127
+ # 使用文件路径上传
128
+ result = await async_client.blobs.upload(
129
+ file="/path/to/local/file.pdf"
130
+ )
131
+
132
+ # 带MIME类型上传(适用于AI生成的内容)
133
+ result = await async_client.blobs.upload(
134
+ file=ai_generated_bytes,
135
+ mime_type="image/png",
136
+ file_name="generated.png"
137
+ )
138
+
139
+ # 上传到指定文件夹
140
+ result = await async_client.blobs.upload(
141
+ file="/path/to/document.docx",
142
+ folder_id="folder_123"
143
+ )
144
+
145
+ # 大文件流式上传(10MB-100MB)
146
+ result = await async_client.blobs.upload(
147
+ file=large_file_path,
148
+ mode=UploadMode.STREAM
149
+ )
150
+
151
+ # 禁止覆盖(防止重复上传)
152
+ result = await async_client.blobs.upload(
153
+ file=content,
154
+ forbid_overwrite=True # 如果文件已存在将失败
155
+ )
156
+
157
+ # 临时文件带过期时间
158
+ result = await async_client.blobs.upload(
159
+ file=temp_content,
160
+ is_temporary=True,
161
+ expire_seconds=3600 # 1小时后过期
162
+ )
163
+ ```
164
+
165
+ ### 下载文件
166
+
167
+ ```python
168
+ # 下载到文件
169
+ await async_client.blobs.download(
170
+ file_id="file_123",
171
+ save_path="/path/to/save/file.pdf"
172
+ )
173
+
174
+ # 下载到字节
175
+ file_bytes = await async_client.blobs.download_to_bytes(
176
+ file_id="file_123"
177
+ )
178
+
179
+ # 生成下载URL
180
+ url_response = await async_client.blobs.generate_download_url(
181
+ file_id="file_123"
182
+ )
183
+ download_url = url_response.download_url
184
+
185
+ # 批量生成下载URL
186
+ batch_response = await async_client.blobs.batch_generate_download_url(
187
+ file_ids=["file_1", "file_2", "file_3"]
188
+ )
189
+ for item in batch_response.items:
190
+ print(f"{item.file_id}: {item.download_url}")
191
+ ```
192
+
193
+ ### 文件分享
194
+
195
+ ```python
196
+ # 生成分享链接
197
+ share_response = await async_client.files.generate_share_link(
198
+ file_id="file_123",
199
+ expire_seconds=86400, # 24小时
200
+ password="secret123",
201
+ max_visit_count=10
202
+ )
203
+ print(f"分享URL: {share_response.share_url}")
204
+
205
+ # 访问分享的文件
206
+ file_info = await async_client.files.visit_file(
207
+ share_url="https://share.example.com/xxx",
208
+ password="secret123"
209
+ )
210
+ ```
211
+
212
+ ### 文件管理
213
+
214
+ ```python
215
+ # 获取文件信息
216
+ file_info = await async_client.files.get_file(file_id="file_123")
217
+
218
+ # 重命名文件
219
+ await async_client.files.rename_file(
220
+ file_id="file_123",
221
+ new_name="新名称.pdf"
222
+ )
223
+
224
+ # 删除文件
225
+ await async_client.files.delete_file(file_id="file_123")
226
+
227
+ # 列出文件夹中的文件
228
+ files = await async_client.files.list_files(
229
+ folder_id="folder_123",
230
+ page=1,
231
+ page_size=20
232
+ )
233
+ ```
234
+
235
+ ### 压缩和变体
236
+
237
+ ```python
238
+ # 获取压缩状态
239
+ status = await async_client.blobs.get_compression_status(
240
+ file_id="image_123"
241
+ )
242
+ print(f"压缩状态: {status.status}")
243
+
244
+ # 获取压缩变体
245
+ variants = await async_client.blobs.get_compressed_variants(
246
+ file_id="image_123"
247
+ )
248
+ for variant in variants.variants:
249
+ print(f"{variant.spec}: {variant.size} 字节")
250
+
251
+ # 生成变体下载URL
252
+ variant_url = await async_client.blobs.generate_variant_download_url(
253
+ file_id="image_123",
254
+ variant_spec="800x600"
255
+ )
256
+
257
+ # 触发重新压缩
258
+ await async_client.blobs.trigger_recompression(
259
+ file_id="image_123",
260
+ variant_specs=["1920x1080", "1280x720", "640x480"]
261
+ )
262
+ ```
263
+
264
+ ### 批量状态查询
265
+
266
+ ```python
267
+ # 批量查询文件状态
268
+ status_response = await async_client.blobs.batch_get_file_status(
269
+ file_ids=["file_1", "file_2", "file_3"]
270
+ )
271
+
272
+ for status in status_response.statuses:
273
+ print(f"文件 {status.file_id}:")
274
+ print(f" 上传状态: {status.upload_status}")
275
+ print(f" 压缩状态: {status.compression_status}")
276
+ print(f" 同步状态: {status.sync_status}")
277
+ ```
278
+
279
+ ## 文件夹操作
280
+
281
+ ```python
282
+ # 创建文件夹
283
+ folder = await async_client.folders.create_folder(
284
+ name="我的文档",
285
+ parent_folder_id="parent_123" # 可选
286
+ )
287
+
288
+ # 重命名文件夹
289
+ await async_client.folders.rename_folder(
290
+ folder_id="folder_123",
291
+ new_name="重要文档"
292
+ )
293
+
294
+ # 移动文件夹
295
+ await async_client.folders.move_folder(
296
+ folder_id="folder_123",
297
+ new_parent_folder_id="parent_456"
298
+ )
299
+
300
+ # 删除文件夹
301
+ await async_client.folders.delete_folder(
302
+ folder_id="folder_123",
303
+ force=True # 即使非空也删除
304
+ )
305
+
306
+ # 列出文件夹
307
+ folders = await async_client.folders.list_folders(
308
+ parent_folder_id="parent_123",
309
+ page=1,
310
+ page_size=20
311
+ )
312
+ ```
313
+
314
+ ## Taple(电子表格)操作
315
+
316
+ ### 表格管理
317
+
318
+ ```python
319
+ # 创建表格
320
+ table = await async_client.taples.create_table(
321
+ name="销售报告 2024",
322
+ description="年度销售数据"
323
+ )
324
+
325
+ # 获取表格信息
326
+ table_info = await async_client.taples.get_table(
327
+ table_id="table_123"
328
+ )
329
+
330
+ # 更新表格
331
+ await async_client.taples.update_table(
332
+ table_id="table_123",
333
+ name="销售报告 2024(更新版)",
334
+ description="包含第四季度更新的年度销售数据"
335
+ )
336
+
337
+ # 删除表格
338
+ await async_client.taples.delete_table(
339
+ table_id="table_123"
340
+ )
341
+ ```
342
+
343
+ ### 工作表操作
344
+
345
+ ```python
346
+ # 创建工作表
347
+ sheet = await async_client.taples.create_sheet(
348
+ table_id="table_123",
349
+ name="第一季度销售",
350
+ position=0
351
+ )
352
+
353
+ # 列出工作表
354
+ sheets = await async_client.taples.list_sheets(
355
+ table_id="table_123"
356
+ )
357
+
358
+ # 获取工作表数据
359
+ sheet_data = await async_client.taples.get_sheet_data(
360
+ sheet_id="sheet_123"
361
+ )
362
+
363
+ # 更新工作表
364
+ await async_client.taples.update_sheet(
365
+ sheet_id="sheet_123",
366
+ name="第一季度销售(修订版)"
367
+ )
368
+ ```
369
+
370
+ ### 列操作
371
+
372
+ ```python
373
+ # 创建列
374
+ column = await async_client.taples.create_column(
375
+ sheet_id="sheet_123",
376
+ name="产品名称",
377
+ data_type="string",
378
+ position=0,
379
+ width=200
380
+ )
381
+
382
+ # 更新列
383
+ await async_client.taples.update_column(
384
+ column_id="col_123",
385
+ name="产品描述",
386
+ width=300
387
+ )
388
+
389
+ # 批量编辑列
390
+ await async_client.taples.batch_edit_columns(
391
+ sheet_id="sheet_123",
392
+ operations=[
393
+ {"type": "create", "name": "价格", "data_type": "number"},
394
+ {"type": "create", "name": "数量", "data_type": "integer"},
395
+ {"type": "update", "column_id": "col_123", "width": 150}
396
+ ]
397
+ )
398
+ ```
399
+
400
+ ### 行操作
401
+
402
+ ```python
403
+ # 创建行
404
+ row = await async_client.taples.create_row(
405
+ sheet_id="sheet_123",
406
+ data={"col_1": "iPhone 15", "col_2": 6999.00, "col_3": 100},
407
+ position=0
408
+ )
409
+
410
+ # 更新行
411
+ await async_client.taples.update_row(
412
+ row_id="row_123",
413
+ data={"col_2": 6499.00, "col_3": 150}
414
+ )
415
+
416
+ # 批量编辑行
417
+ await async_client.taples.batch_edit_rows(
418
+ sheet_id="sheet_123",
419
+ operations=[
420
+ {"type": "create", "data": {"col_1": "iPad Pro"}},
421
+ {"type": "update", "row_id": "row_123", "data": {"col_3": 200}},
422
+ {"type": "delete", "row_id": "row_456"}
423
+ ]
424
+ )
425
+ ```
426
+
427
+ ### 单元格操作
428
+
429
+ ```python
430
+ # 编辑单元格
431
+ await async_client.taples.edit_cell(
432
+ sheet_id="sheet_123",
433
+ row_id="row_123",
434
+ column_id="col_456",
435
+ value="新值",
436
+ style={"bold": True, "color": "#FF0000"}
437
+ )
438
+
439
+ # 批量编辑单元格
440
+ await async_client.taples.batch_edit_cells(
441
+ sheet_id="sheet_123",
442
+ operations=[
443
+ {
444
+ "row_id": "row_1",
445
+ "column_id": "col_1",
446
+ "value": "已更新",
447
+ "style": {"italic": True}
448
+ },
449
+ {
450
+ "row_id": "row_2",
451
+ "column_id": "col_2",
452
+ "value": 123.45
453
+ }
454
+ ]
455
+ )
456
+
457
+ # 获取单元格数据
458
+ cell_data = await async_client.taples.get_cell_data(
459
+ sheet_id="sheet_123",
460
+ row_id="row_123",
461
+ column_id="col_456"
462
+ )
463
+ ```
464
+
465
+ ### 数据导入/导出
466
+
467
+ ```python
468
+ # 导出表格数据
469
+ export_result = await async_client.taples.export_table_data(
470
+ table_id="table_123",
471
+ format=ExportFormat.XLSX,
472
+ include_styles=True
473
+ )
474
+ # 使用file_id下载导出的文件
475
+ await async_client.blobs.download(
476
+ file_id=export_result.file_id,
477
+ save_path="导出的表格.xlsx"
478
+ )
479
+
480
+ # 从文件导入数据
481
+ import_result = await async_client.taples.import_table_data(
482
+ table_id="table_123",
483
+ file_id="file_789", # Excel/CSV文件
484
+ sheet_id="sheet_123", # 目标工作表
485
+ mode="append", # 或 "replace"
486
+ has_header=True
487
+ )
488
+
489
+ # 克隆表格
490
+ clone_result = await async_client.taples.clone_table_data(
491
+ source_table_id="table_123",
492
+ target_table_id="table_456",
493
+ mode="override"
494
+ )
495
+ ```
496
+
497
+ ## 同步模式使用
498
+
499
+ 所有操作也都支持同步模式:
500
+
501
+ ```python
502
+ from file_hub_client import FileHubClient
503
+
504
+ # 初始化同步客户端
505
+ client = FileHubClient(
506
+ host="your-file-hub-server.com",
507
+ port=50051
508
+ )
509
+
510
+ # 同步上传
511
+ result = client.blobs.upload(
512
+ file=b"Hello, 同步世界!",
513
+ file_name="hello_sync.txt"
514
+ )
515
+
516
+ # 同步下载
517
+ client.blobs.download(
518
+ file_id="file_123",
519
+ save_path="/path/to/save.pdf"
520
+ )
521
+
522
+ # 同步文件夹操作
523
+ folder = client.folders.create_folder(
524
+ name="同步文件夹"
525
+ )
526
+
527
+ # 同步Taple操作
528
+ table = client.taples.create_table(
529
+ name="同步表格"
530
+ )
531
+ ```
532
+
533
+ ## 日志配置
534
+
535
+ ```python
536
+ from file_hub_client.utils.logging import setup_logging
537
+
538
+ # 基础设置
539
+ setup_logging(
540
+ level="DEBUG",
541
+ enable_grpc_logging=True
542
+ )
543
+
544
+ # 高级设置带自定义处理器
545
+ import logging
546
+ custom_handler = logging.FileHandler("file_hub.log")
547
+
548
+ setup_logging(
549
+ level="INFO",
550
+ enable_grpc_logging=True,
551
+ log_request_payload=True, # 记录请求数据
552
+ log_response_payload=True, # 记录响应数据
553
+ handler=custom_handler,
554
+ use_json_format=True # JSON格式日志
555
+ )
556
+
557
+ # 自定义格式的人类可读日志
558
+ setup_logging(
559
+ level="DEBUG",
560
+ use_json_format=False,
561
+ format_string="[%(asctime)s] %(levelname)s - %(message)s"
562
+ )
563
+ ```
564
+
565
+ ## 错误处理
566
+
567
+ ```python
568
+ from file_hub_client.errors import (
569
+ FileHubError,
570
+ ValidationError,
571
+ NotFoundError,
572
+ PermissionError,
573
+ NetworkError,
574
+ ServerError
575
+ )
576
+
577
+ try:
578
+ result = await async_client.blobs.upload(
579
+ file=content,
580
+ forbid_overwrite=True
581
+ )
582
+ except ValidationError as e:
583
+ print(f"输入无效: {e}")
584
+ except NotFoundError as e:
585
+ print(f"资源未找到: {e}")
586
+ except PermissionError as e:
587
+ print(f"权限拒绝: {e}")
588
+ except NetworkError as e:
589
+ print(f"网络问题: {e}")
590
+ except ServerError as e:
591
+ print(f"服务器错误: {e}")
592
+ except FileHubError as e:
593
+ print(f"一般错误: {e}")
594
+ ```
595
+
596
+ ## 高级配置
597
+
598
+ ### 自定义元数据
599
+
600
+ ```python
601
+ # 向请求添加自定义元数据
602
+ result = await async_client.blobs.upload(
603
+ file=content,
604
+ file_name="document.pdf",
605
+ request_id="unique-request-id-123", # 用于幂等性
606
+ **{
607
+ "x-custom-header": "custom-value",
608
+ "x-trace-id": "trace-123"
609
+ }
610
+ )
611
+ ```
612
+
613
+ ### 连接池设置
614
+
615
+ ```python
616
+ # 配置连接池
617
+ client = AsyncFileHubClient(
618
+ host="server.com",
619
+ port=50051,
620
+ max_connections=100,
621
+ connection_timeout=30,
622
+ request_timeout=60,
623
+ retry_config={
624
+ "max_attempts": 3,
625
+ "initial_backoff": 1,
626
+ "max_backoff": 30,
627
+ "backoff_multiplier": 2
628
+ }
629
+ )
630
+ ```
631
+
632
+ ### 上传模式选择
633
+
634
+ SDK根据文件大小自动选择最优上传模式:
635
+
636
+ - **NORMAL** (< 10MB):直接gRPC上传
637
+ - **STREAM** (10MB - 100MB):流式上传到云存储
638
+ - **STREAM** (> 100MB):当前使用流式上传(OSS断点续传功能待完成)
639
+
640
+ 您也可以手动指定上传模式:
641
+
642
+ ```python
643
+ from file_hub_client.enums import UploadMode
644
+
645
+ # 强制使用流式模式
646
+ result = await async_client.blobs.upload(
647
+ file=small_file,
648
+ mode=UploadMode.STREAM
649
+ )
650
+ ```
651
+
652
+ ## MIME类型检测
653
+
654
+ SDK使用魔术字节自动检测以下格式的MIME类型:
655
+
656
+ **图片**:JPEG、PNG、GIF、BMP、WebP、ICO、TIFF、SVG
657
+ **视频**:MP4、AVI、MOV、WMV、FLV、WebM、MKV
658
+ **文档**:PDF、DOCX、XLSX、PPTX
659
+ **压缩包**:ZIP、RAR、7Z、TAR、GZIP
660
+ **其他**:MP3、WAV、JSON、XML、HTML
661
+
662
+ 对于AI生成的内容或已知MIME类型的情况:
663
+
664
+ ```python
665
+ # 显式设置MIME类型
666
+ result = await async_client.blobs.upload(
667
+ file=ai_generated_bytes,
668
+ mime_type="image/png" # SDK会推断出.png扩展名
669
+ )
670
+ ```
671
+
672
+ ## 存储后端支持
673
+
674
+ SDK自动处理不同的存储后端:
675
+
676
+ - **谷歌云存储(GCS)**:自动检测和头部管理
677
+ - **阿里云OSS**:自动检测和头部管理
678
+ - **自定义S3兼容存储**:可与任何S3兼容存储配合使用
679
+
680
+ 根据上传URL检测的存储类型自动应用禁止覆盖头部。
681
+
682
+ ## 最佳实践
683
+
684
+ 1. **I/O密集型操作使用异步客户端**:异步客户端在处理多个并发操作时更高效。
685
+
686
+ 2. **批量操作**:处理多个文件时使用批量方法,减少网络开销。
687
+
688
+ 3. **错误处理**:始终使用try-except块包装操作,优雅地处理潜在错误。
689
+
690
+ 4. **连接复用**:创建客户端实例一次,在整个应用程序中复用。
691
+
692
+ 5. **日志记录**:开发中启用gRPC日志,但在生产环境中考虑禁用载荷日志以提高性能。
693
+
694
+ 6. **上传保护**:在生产环境中使用`forbid_overwrite=True`防止意外文件覆盖。
695
+
696
+ 7. **请求ID**:为关键操作提供唯一的请求ID以实现幂等性。
697
+
698
+ ## 许可证
699
+
700
+ MIT许可证
701
+
702
+ ## 支持
703
+
704
+ 有关问题、疑问或贡献,请访问[GitHub仓库](https://github.com/your-org/file-hub-client)。