honghu-data-collection 0.1.1__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.
- honghu_data_collection-0.1.1/PKG-INFO +6 -0
- honghu_data_collection-0.1.1/data_collection_tool.py +224 -0
- honghu_data_collection-0.1.1/honghu_data_collection.egg-info/PKG-INFO +6 -0
- honghu_data_collection-0.1.1/honghu_data_collection.egg-info/SOURCES.txt +7 -0
- honghu_data_collection-0.1.1/honghu_data_collection.egg-info/dependency_links.txt +1 -0
- honghu_data_collection-0.1.1/honghu_data_collection.egg-info/requires.txt +1 -0
- honghu_data_collection-0.1.1/honghu_data_collection.egg-info/top_level.txt +1 -0
- honghu_data_collection-0.1.1/setup.cfg +4 -0
- honghu_data_collection-0.1.1/setup.py +13 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import hmac
|
|
3
|
+
import hashlib
|
|
4
|
+
import time
|
|
5
|
+
import random
|
|
6
|
+
import os
|
|
7
|
+
from typing import Optional
|
|
8
|
+
from urllib.parse import urlencode
|
|
9
|
+
import platform
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
class DataCollectionClient:
|
|
13
|
+
def __init__(self, base_url: str, access_key: str, secret_key: str):
|
|
14
|
+
"""
|
|
15
|
+
初始化客户端
|
|
16
|
+
|
|
17
|
+
:param base_url: API基础URL
|
|
18
|
+
:param access_key: 访问密钥
|
|
19
|
+
:param secret_key: 安全密钥
|
|
20
|
+
"""
|
|
21
|
+
self.base_url = base_url.rstrip('/')
|
|
22
|
+
self.access_key = access_key
|
|
23
|
+
self.secret_key = secret_key
|
|
24
|
+
self.session = requests.Session()
|
|
25
|
+
self.access_token = self._get_access_token()
|
|
26
|
+
def _generate_signature(self, params: dict, timestamp: str, nonce: str) -> str:
|
|
27
|
+
"""
|
|
28
|
+
生成签名
|
|
29
|
+
|
|
30
|
+
:param params: 请求参数
|
|
31
|
+
:param timestamp: 时间戳
|
|
32
|
+
:return: 签名
|
|
33
|
+
"""
|
|
34
|
+
# 添加访问密钥和时间戳到参数中
|
|
35
|
+
sign_params = params.copy()
|
|
36
|
+
sign_params['access_key'] = self.access_key
|
|
37
|
+
sign_params['timestamp'] = timestamp
|
|
38
|
+
sign_params['nonce'] = nonce
|
|
39
|
+
|
|
40
|
+
# 按键排序并拼接参数
|
|
41
|
+
sorted_params = sorted(sign_params.items())
|
|
42
|
+
query_string = urlencode(sorted_params)
|
|
43
|
+
|
|
44
|
+
# 使用 HMAC-SHA256 生成签名
|
|
45
|
+
signature = hmac.new(
|
|
46
|
+
self.secret_key.encode('utf-8'),
|
|
47
|
+
query_string.encode('utf-8'),
|
|
48
|
+
hashlib.sha256
|
|
49
|
+
).hexdigest()
|
|
50
|
+
|
|
51
|
+
return signature
|
|
52
|
+
|
|
53
|
+
def _make_request(self, method: str, url: str, params: Optional[dict] = None) -> dict:
|
|
54
|
+
"""
|
|
55
|
+
发起带签名的请求
|
|
56
|
+
|
|
57
|
+
:param method: HTTP方法
|
|
58
|
+
:param url: 请求URL
|
|
59
|
+
:param params: 请求参数
|
|
60
|
+
:return: 响应数据
|
|
61
|
+
"""
|
|
62
|
+
headers = {'Authorization': f'Bearer {self.access_token["access_token"]}'}
|
|
63
|
+
# 发起请求
|
|
64
|
+
if method.upper() == 'GET':
|
|
65
|
+
response = self.session.get(url, params=params, headers=headers)
|
|
66
|
+
else:
|
|
67
|
+
response = self.session.post(url, json=params, headers=headers)
|
|
68
|
+
|
|
69
|
+
response.raise_for_status()
|
|
70
|
+
return response.json()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _get_access_token(self) -> dict:
|
|
74
|
+
"""
|
|
75
|
+
获取访问令牌
|
|
76
|
+
:return: 包含访问令牌的字典
|
|
77
|
+
"""
|
|
78
|
+
params = {}
|
|
79
|
+
# 获取当前时间戳
|
|
80
|
+
timestamp = str(int(time.time()))
|
|
81
|
+
nonce = str(random.randint(10000000, 99999999))
|
|
82
|
+
# 生成签名
|
|
83
|
+
signature = self._generate_signature(params, timestamp, nonce)
|
|
84
|
+
|
|
85
|
+
# 添加认证信息到参数中
|
|
86
|
+
params['access_key'] = self.access_key
|
|
87
|
+
params['timestamp'] = timestamp
|
|
88
|
+
params['nonce'] = nonce
|
|
89
|
+
params['sign'] = signature
|
|
90
|
+
|
|
91
|
+
url = f"{self.base_url}/api/v1/system/auth/access_token"
|
|
92
|
+
response = self.session.post(url, json=params)
|
|
93
|
+
response.raise_for_status()
|
|
94
|
+
token = response.json()
|
|
95
|
+
if token["code"] != 0:
|
|
96
|
+
raise Exception(f"获取访问令牌失败: {token['msg']}")
|
|
97
|
+
|
|
98
|
+
return token["data"]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def get_download_url(self, collection_id: int, parent_id: int, version_id: int) -> str:
|
|
102
|
+
"""
|
|
103
|
+
根据数据集ID、父目录ID和版本ID获取数据下载链接
|
|
104
|
+
|
|
105
|
+
:param collection_id: 数据集ID
|
|
106
|
+
:param parent_id: 父目录ID
|
|
107
|
+
:param version_id: 版本ID
|
|
108
|
+
:return: 下载链接
|
|
109
|
+
"""
|
|
110
|
+
url = f"{self.base_url}/api/v1/dataset/fs/resource/pkg_download_path"
|
|
111
|
+
|
|
112
|
+
params = {
|
|
113
|
+
'collection_id': collection_id,
|
|
114
|
+
'parent_id': parent_id,
|
|
115
|
+
'version_id': version_id
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
result = self._make_request('POST', url, params)
|
|
119
|
+
return result['data']
|
|
120
|
+
|
|
121
|
+
def download_file(self, download_url: str, save_path: str) -> str:
|
|
122
|
+
"""
|
|
123
|
+
根据下载链接下载文件
|
|
124
|
+
|
|
125
|
+
:param download_url: 下载链接
|
|
126
|
+
:param save_path: 保存路径
|
|
127
|
+
:return: 保存文件的路径
|
|
128
|
+
"""
|
|
129
|
+
# 创建保存目录(如果不存在)
|
|
130
|
+
save_dir = os.path.dirname(save_path)
|
|
131
|
+
if save_dir and not os.path.exists(save_dir):
|
|
132
|
+
os.makedirs(save_dir)
|
|
133
|
+
|
|
134
|
+
# 下载文件
|
|
135
|
+
response = self.session.get(download_url, stream=True)
|
|
136
|
+
response.raise_for_status()
|
|
137
|
+
|
|
138
|
+
# 保存文件
|
|
139
|
+
with open(save_path, 'wb') as f:
|
|
140
|
+
for chunk in response.iter_content(chunk_size=8192):
|
|
141
|
+
if chunk:
|
|
142
|
+
f.write(chunk)
|
|
143
|
+
|
|
144
|
+
return save_path
|
|
145
|
+
|
|
146
|
+
def _get_default_download_path(self,collection_name: str, version_name: str) -> str:
|
|
147
|
+
"""根据操作系统获取默认下载路径"""
|
|
148
|
+
system = platform.system()
|
|
149
|
+
|
|
150
|
+
if system == "Windows":
|
|
151
|
+
# Windows 系统通常使用用户目录下的 Downloads
|
|
152
|
+
download_dir = Path.home() / "Downloads"
|
|
153
|
+
elif system == "Darwin": # macOS
|
|
154
|
+
download_dir = Path.home() / "Downloads"
|
|
155
|
+
else: # Linux 和其他 Unix 系统
|
|
156
|
+
# 检查 XDG_DOWNLOAD_DIR 环境变量
|
|
157
|
+
xdg_download = os.environ.get('XDG_DOWNLOAD_DIR')
|
|
158
|
+
if xdg_download:
|
|
159
|
+
download_dir = Path(xdg_download)
|
|
160
|
+
else:
|
|
161
|
+
download_dir = Path.home() / "Downloads"
|
|
162
|
+
|
|
163
|
+
# 确保目录存在
|
|
164
|
+
download_dir.mkdir(parents=True, exist_ok=True)
|
|
165
|
+
|
|
166
|
+
return str(download_dir / f"{collection_name}_{version_name}.zip")
|
|
167
|
+
|
|
168
|
+
def _is_directory_path(self, path: str) -> bool:
|
|
169
|
+
"""
|
|
170
|
+
使用 os.path 判断路径是否为目录路径
|
|
171
|
+
"""
|
|
172
|
+
# 如果路径以分隔符结尾,明确表示是目录
|
|
173
|
+
if path.endswith(os.sep) or path.endswith('/'):
|
|
174
|
+
return True
|
|
175
|
+
|
|
176
|
+
# 如果路径存在,检查是否为目录
|
|
177
|
+
if os.path.exists(path):
|
|
178
|
+
return os.path.isdir(path)
|
|
179
|
+
|
|
180
|
+
# 如果路径不存在,通过扩展名判断
|
|
181
|
+
_, ext = os.path.splitext(path)
|
|
182
|
+
return ext == '' # 没有扩展名通常表示目录
|
|
183
|
+
|
|
184
|
+
# 下载数据集合
|
|
185
|
+
def download_collection(self, collection_name: str,version_name: str, save_path: str = None) :
|
|
186
|
+
|
|
187
|
+
if not collection_name or not version_name:
|
|
188
|
+
raise ValueError("数据集合名称或者数据集版本名称不能为空")
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
# 根据数据集合名称和数据集和版本名称获取下载URL
|
|
192
|
+
url = f"{self.base_url}/api/v1/dataset/fs/resource/collection_download_path"
|
|
193
|
+
params = {
|
|
194
|
+
'collection_name': collection_name,
|
|
195
|
+
'version_name': version_name
|
|
196
|
+
}
|
|
197
|
+
result = self._make_request('POST', url, params)
|
|
198
|
+
|
|
199
|
+
if result['code'] != 0:
|
|
200
|
+
raise Exception(f"获取下载链接失败: {result['msg']}")
|
|
201
|
+
download_url = result['data']
|
|
202
|
+
# 下载文件到指定目录
|
|
203
|
+
|
|
204
|
+
if not save_path:
|
|
205
|
+
# 如果没有指定保存路径,则使用系统临时目录
|
|
206
|
+
save_path = self._get_default_download_path(collection_name = collection_name, version_name = version_name)
|
|
207
|
+
else:
|
|
208
|
+
if self._is_directory_path(save_path):
|
|
209
|
+
save_path = os.path.join(save_path, f"{collection_name}_{version_name}.zip")
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# 下载文件
|
|
215
|
+
response = self.session.get(download_url, stream=True)
|
|
216
|
+
response.raise_for_status()
|
|
217
|
+
|
|
218
|
+
# 保存文件
|
|
219
|
+
with open(save_path, 'wb') as f:
|
|
220
|
+
for chunk in response.iter_content(chunk_size=8192):
|
|
221
|
+
if chunk:
|
|
222
|
+
f.write(chunk)
|
|
223
|
+
|
|
224
|
+
return save_path
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
data_collection_tool.py
|
|
2
|
+
setup.py
|
|
3
|
+
honghu_data_collection.egg-info/PKG-INFO
|
|
4
|
+
honghu_data_collection.egg-info/SOURCES.txt
|
|
5
|
+
honghu_data_collection.egg-info/dependency_links.txt
|
|
6
|
+
honghu_data_collection.egg-info/requires.txt
|
|
7
|
+
honghu_data_collection.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.25.1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
data_collection_tool
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name='honghu_data_collection',
|
|
5
|
+
version='0.1.1',
|
|
6
|
+
author='xuzhaocai',
|
|
7
|
+
description='红湖·数据汇聚管理平台PYTHON SDK',
|
|
8
|
+
py_modules=['data_collection_tool'],
|
|
9
|
+
install_requires=[
|
|
10
|
+
'requests>=2.25.1',
|
|
11
|
+
],
|
|
12
|
+
python_requires='>=3.6',
|
|
13
|
+
)
|