alpha-dc-client 0.1.23__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.
- alpha_dc_client-0.1.23/.gitignore +90 -0
- alpha_dc_client-0.1.23/PKG-INFO +6 -0
- alpha_dc_client-0.1.23/USAGE.md +438 -0
- alpha_dc_client-0.1.23/pyproject.toml +20 -0
- alpha_dc_client-0.1.23/pyproject.toml.backup +20 -0
- alpha_dc_client-0.1.23/src/dc_client/__init__.py +13 -0
- alpha_dc_client-0.1.23/src/dc_client/base.py +69 -0
- alpha_dc_client-0.1.23/src/dc_client/client.py +221 -0
- alpha_dc_client-0.1.23/src/dc_client/client.pyi +75 -0
- alpha_dc_client-0.1.23/src/dc_client/exceptions.py +26 -0
- alpha_dc_client-0.1.23/src/dc_client/run_tests.py +294 -0
- alpha_dc_client-0.1.23/src/dc_client/tests/__init__.py +0 -0
- alpha_dc_client-0.1.23/src/dc_client/tests/base.py +123 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
pip-wheel-metadata/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.coverage
|
|
43
|
+
.coverage.*
|
|
44
|
+
.cache
|
|
45
|
+
nosetests.xml
|
|
46
|
+
coverage.xml
|
|
47
|
+
*.cover
|
|
48
|
+
*.py,cover
|
|
49
|
+
.hypothesis/
|
|
50
|
+
.pytest_cache/
|
|
51
|
+
|
|
52
|
+
# Jupyter Notebook
|
|
53
|
+
.ipynb_checkpoints
|
|
54
|
+
|
|
55
|
+
# IPython
|
|
56
|
+
profile_default/
|
|
57
|
+
ipython_config.py
|
|
58
|
+
|
|
59
|
+
# pyenv
|
|
60
|
+
.python-version
|
|
61
|
+
|
|
62
|
+
# PEP 582; __pypackages__
|
|
63
|
+
__pypackages__/
|
|
64
|
+
|
|
65
|
+
# Environments
|
|
66
|
+
.env
|
|
67
|
+
.venv
|
|
68
|
+
env/
|
|
69
|
+
venv/
|
|
70
|
+
ENV/
|
|
71
|
+
env.bak/
|
|
72
|
+
venv.bak/
|
|
73
|
+
|
|
74
|
+
# mypy
|
|
75
|
+
.mypy_cache/
|
|
76
|
+
.dmypy.json
|
|
77
|
+
dmypy.json
|
|
78
|
+
|
|
79
|
+
# uv lock file
|
|
80
|
+
uv.lock
|
|
81
|
+
|
|
82
|
+
# Log files
|
|
83
|
+
logs/
|
|
84
|
+
*.log
|
|
85
|
+
|
|
86
|
+
# Data directories (runtime generated data)
|
|
87
|
+
data/
|
|
88
|
+
|
|
89
|
+
# Project specific files
|
|
90
|
+
services/worker_service/data_fetchers/StockClassifyUse_stock.xls
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
# DataCenter Client 使用指南
|
|
2
|
+
|
|
3
|
+
## 1. 🚀 安装
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install datacenter_client
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## 2. 🔑 认证设置
|
|
10
|
+
|
|
11
|
+
### 获取API Token
|
|
12
|
+
1. 联系管理员申请API Token
|
|
13
|
+
2. 或者访问数据管理后台获取访问权限
|
|
14
|
+
|
|
15
|
+
### 初始化客户端
|
|
16
|
+
```python
|
|
17
|
+
import datacenter_client as dc
|
|
18
|
+
|
|
19
|
+
# 基础初始化
|
|
20
|
+
client = dc.init(
|
|
21
|
+
token='your_api_token_here'
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# 使用环境变量
|
|
25
|
+
import os
|
|
26
|
+
client = dc.init(token=os.getenv('DATACENTER_API_TOKEN'))
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 3. 🔍 查找需要的接口
|
|
30
|
+
|
|
31
|
+
### 方法一:查看完整API列表
|
|
32
|
+
```python
|
|
33
|
+
import requests
|
|
34
|
+
|
|
35
|
+
# 获取所有API
|
|
36
|
+
response = requests.get('http://data.alphaaidig.com/api/v1/docs/json')
|
|
37
|
+
if response.status_code == 200:
|
|
38
|
+
docs = response.json()
|
|
39
|
+
print(f"总共有 {docs['total_count']} 个API")
|
|
40
|
+
for api in docs['apis']:
|
|
41
|
+
print(f"- {api['name']}: {api['description']}")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 方法二:搜索特定功能
|
|
45
|
+
```python
|
|
46
|
+
# 搜索融资融券相关接口
|
|
47
|
+
response = requests.get('http://data.alphaaidig.com/api/v1/docs/search?q=margin')
|
|
48
|
+
if response.status_code == 200:
|
|
49
|
+
results = response.json()
|
|
50
|
+
for api in results['results']:
|
|
51
|
+
print(f"- {api['name']}: {api['description']}")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 方法三:按类别查看
|
|
55
|
+
```python
|
|
56
|
+
# 获取API分类
|
|
57
|
+
response = requests.get('http://data.alphaaidig.com/api/v1/docs/categories')
|
|
58
|
+
if response.status_code == 200:
|
|
59
|
+
categories = response.json()
|
|
60
|
+
print(f"API分类: {categories['categories']}")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 4. 📋 访问接口
|
|
64
|
+
|
|
65
|
+
### 基本调用方式
|
|
66
|
+
```python
|
|
67
|
+
# 方式一:通过动态方法调用
|
|
68
|
+
result = client.hsgt_fund_page_list(page=1, page_size=20)
|
|
69
|
+
|
|
70
|
+
# 方式二:通过通用query方法
|
|
71
|
+
result = client.query('hsgt_fund_page_list', page=1, page_size=20)
|
|
72
|
+
|
|
73
|
+
# 方式三:指定返回字段
|
|
74
|
+
result = client.hsgt_fund_page_list(
|
|
75
|
+
page=1,
|
|
76
|
+
page_size=10,
|
|
77
|
+
fields='trade_date,stock_code,stock_name,hold_market_cap'
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 常用接口示例
|
|
82
|
+
```python
|
|
83
|
+
# 沪深港通数据
|
|
84
|
+
df = client.hsgt_fund_page_list(page=1, page_size=20)
|
|
85
|
+
df = client.hsgt_north_fundxx()
|
|
86
|
+
df = client.hsgt_south_fundxx()
|
|
87
|
+
|
|
88
|
+
# A股数据
|
|
89
|
+
df = client.a_stock_page_list(page=1, page_size=20)
|
|
90
|
+
df = client.a_stock_list(limit=50)
|
|
91
|
+
|
|
92
|
+
# 港股数据
|
|
93
|
+
df = client.hk_stock_page_list(page=1, page_size=20)
|
|
94
|
+
df = client.hk_stock_list(limit=50)
|
|
95
|
+
|
|
96
|
+
# 行业数据
|
|
97
|
+
df = client.hs_industry_page_list(page=1, page_size=20)
|
|
98
|
+
df = client.hs_industry_company_page_list(page=1, page_size=20)
|
|
99
|
+
df = client.sw_industry_page_list(page=1, page_size=20)
|
|
100
|
+
df = client.sw_industry_company_page_list(page=1, page_size=20, level_type='level1')
|
|
101
|
+
|
|
102
|
+
# 融资融券数据
|
|
103
|
+
df = client.margin_account_page_list(page=1, page_size=20)
|
|
104
|
+
df = client.margin_account_list(limit=50)
|
|
105
|
+
df = client.margin_analysis_page_list(page=1, page_size=20)
|
|
106
|
+
df = client.margin_analysis_list(limit=50)
|
|
107
|
+
df = client.margin_detail_page_list_by_date(page=1, page_size=20)
|
|
108
|
+
df = client.margin_detail_page_list_by_stock(page=1, page_size=20)
|
|
109
|
+
df = client.margin_detail_list_by_stock(stock_code='000001.SZ', limit=50)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 5. ❌ 错误处理
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import datacenter_client as dc
|
|
116
|
+
from datacenter_client.exceptions import (
|
|
117
|
+
DatacenterAPIError,
|
|
118
|
+
APIError,
|
|
119
|
+
AuthenticationError,
|
|
120
|
+
NotFoundError,
|
|
121
|
+
InvalidRequestError
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def safe_api_call():
|
|
125
|
+
try:
|
|
126
|
+
client = dc.init(token='your_api_token')
|
|
127
|
+
df = client.hsgt_fund_page_list(page=1, page_size=10)
|
|
128
|
+
return df
|
|
129
|
+
|
|
130
|
+
except AuthenticationError:
|
|
131
|
+
print("❌ 认证失败:请检查API token是否正确")
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
except NotFoundError:
|
|
135
|
+
print("❌ API不存在:请检查API名称是否正确")
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
except InvalidRequestError as e:
|
|
139
|
+
print(f"❌ 请求参数错误:{e}")
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
except DatacenterAPIError as e:
|
|
143
|
+
print(f"❌ API错误:{e.message}")
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
except Exception as e:
|
|
147
|
+
print(f"❌ 未知错误:{e}")
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
# 使用
|
|
151
|
+
result = safe_api_call()
|
|
152
|
+
if result is not None:
|
|
153
|
+
print(f"✅ 成功获取 {len(result)} 条数据")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 6. 📊 分页数据解析
|
|
157
|
+
|
|
158
|
+
### 识别分页数据
|
|
159
|
+
```python
|
|
160
|
+
import datacenter_client as dc
|
|
161
|
+
|
|
162
|
+
client = dc.init(token='your_api_token')
|
|
163
|
+
|
|
164
|
+
# 调用分页接口
|
|
165
|
+
result = client.hsgt_fund_page_list(page=1, page_size=20)
|
|
166
|
+
|
|
167
|
+
# 检查是否为分页数据
|
|
168
|
+
if hasattr(result, 'has_pagination') and result.has_pagination:
|
|
169
|
+
print("✅ 这是分页数据")
|
|
170
|
+
print(f"当前页: {result.current_page}")
|
|
171
|
+
print(f"每页大小: {result.page_size}")
|
|
172
|
+
print(f"总记录数: {result.total_count}")
|
|
173
|
+
print(f"总页数: {result.total_pages}")
|
|
174
|
+
else:
|
|
175
|
+
print("✅ 这是普通数据")
|
|
176
|
+
print(f"数据行数: {len(result)}")
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 遍历所有分页数据
|
|
180
|
+
```python
|
|
181
|
+
def get_all_paginated_data(client, api_method, **kwargs):
|
|
182
|
+
"""获取所有分页数据的通用函数"""
|
|
183
|
+
all_data = []
|
|
184
|
+
page = 1
|
|
185
|
+
page_size = 100 # 每页大小
|
|
186
|
+
|
|
187
|
+
while True:
|
|
188
|
+
try:
|
|
189
|
+
# 调用分页接口
|
|
190
|
+
result = api_method(page=page, page_size=page_size, **kwargs)
|
|
191
|
+
|
|
192
|
+
if hasattr(result, 'has_pagination') and result.has_pagination:
|
|
193
|
+
# 分页数据处理
|
|
194
|
+
all_data.extend(result.to_dict('records'))
|
|
195
|
+
print(f"✅ 第 {page} 页,累计 {len(all_data)} 条数据")
|
|
196
|
+
|
|
197
|
+
# 检查是否还有下一页
|
|
198
|
+
if page >= result.total_pages:
|
|
199
|
+
break
|
|
200
|
+
page += 1
|
|
201
|
+
else:
|
|
202
|
+
# 非分页数据
|
|
203
|
+
all_data.extend(result.to_dict('records'))
|
|
204
|
+
break
|
|
205
|
+
|
|
206
|
+
except Exception as e:
|
|
207
|
+
print(f"❌ 获取第 {page} 页数据失败:{e}")
|
|
208
|
+
break
|
|
209
|
+
|
|
210
|
+
return all_data
|
|
211
|
+
|
|
212
|
+
# 使用示例
|
|
213
|
+
client = dc.init(token='your_api_token')
|
|
214
|
+
all_hsgt_data = get_all_paginated_data(
|
|
215
|
+
client,
|
|
216
|
+
client.hsgt_fund_page_list
|
|
217
|
+
)
|
|
218
|
+
print(f"总共获取 {len(all_hsgt_data)} 条数据")
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## 7. 📄 非分页数据解析
|
|
222
|
+
|
|
223
|
+
### 处理普通数据
|
|
224
|
+
```python
|
|
225
|
+
import pandas as pd
|
|
226
|
+
import datacenter_client as dc
|
|
227
|
+
|
|
228
|
+
client = dc.init(token='your_api_token')
|
|
229
|
+
|
|
230
|
+
# 调用非分页接口
|
|
231
|
+
result = client.hsgt_north_fundxx()
|
|
232
|
+
|
|
233
|
+
# 检查数据类型
|
|
234
|
+
if isinstance(result, pd.DataFrame):
|
|
235
|
+
print(f"✅ 获取到DataFrame,共 {len(result)} 行")
|
|
236
|
+
print(f"列名: {list(result.columns)}")
|
|
237
|
+
print("前5行数据:")
|
|
238
|
+
print(result.head())
|
|
239
|
+
else:
|
|
240
|
+
print("✅ 获取到其他格式数据")
|
|
241
|
+
print(f"数据类型: {type(result)}")
|
|
242
|
+
print(f"数据内容: {result}")
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 指定返回字段
|
|
246
|
+
```python
|
|
247
|
+
# 只获取需要的字段
|
|
248
|
+
result = client.hsgt_fund_page_list(
|
|
249
|
+
page=1,
|
|
250
|
+
page_size=10,
|
|
251
|
+
fields='trade_date,stock_code,stock_name,hold_market_cap'
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
print("返回的字段:", result.columns.tolist())
|
|
255
|
+
print("数据示例:")
|
|
256
|
+
print(result.head())
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## 8. 🛠️ 高级用法
|
|
260
|
+
|
|
261
|
+
### 配置化客户端
|
|
262
|
+
```python
|
|
263
|
+
import os
|
|
264
|
+
from pathlib import Path
|
|
265
|
+
import json
|
|
266
|
+
|
|
267
|
+
class DataCenterConfig:
|
|
268
|
+
def __init__(self):
|
|
269
|
+
self.api_token = os.getenv('DATACENTER_API_TOKEN')
|
|
270
|
+
self.base_url = os.getenv('DATACENTER_BASE_URL', 'https://data.alphaaidig.com')
|
|
271
|
+
self.timeout = int(os.getenv('DATACENTER_TIMEOUT', '30'))
|
|
272
|
+
|
|
273
|
+
# 从配置文件读取
|
|
274
|
+
config_file = Path.home() / '.datacenter' / 'config.json'
|
|
275
|
+
if config_file.exists():
|
|
276
|
+
with open(config_file, 'r') as f:
|
|
277
|
+
config = json.load(f)
|
|
278
|
+
self.api_token = config.get('api_token', self.api_token)
|
|
279
|
+
self.base_url = config.get('base_url', self.base_url)
|
|
280
|
+
self.timeout = config.get('timeout', self.timeout)
|
|
281
|
+
|
|
282
|
+
def get_client(self):
|
|
283
|
+
if not self.api_token:
|
|
284
|
+
raise ValueError("❌ API Token未设置,请设置DATACENTER_API_TOKEN环境变量或配置文件")
|
|
285
|
+
|
|
286
|
+
return dc.init(
|
|
287
|
+
token=self.api_token,
|
|
288
|
+
base_url=self.base_url,
|
|
289
|
+
timeout=self.timeout
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
# 使用
|
|
293
|
+
config = DataCenterConfig()
|
|
294
|
+
client = config.get_client()
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 批量查询
|
|
298
|
+
```python
|
|
299
|
+
import pandas as pd
|
|
300
|
+
from typing import List
|
|
301
|
+
import time
|
|
302
|
+
|
|
303
|
+
def batch_query_stocks(stock_codes: List[str]) -> pd.DataFrame:
|
|
304
|
+
"""批量查询多只股票数据"""
|
|
305
|
+
client = dc.init(token='your_api_token')
|
|
306
|
+
all_data = []
|
|
307
|
+
|
|
308
|
+
for i, stock_code in enumerate(stock_codes):
|
|
309
|
+
try:
|
|
310
|
+
print(f"📊 查询股票 {stock_code} ({i+1}/{len(stock_codes)})")
|
|
311
|
+
|
|
312
|
+
# 这里可以根据需要调用不同的接口
|
|
313
|
+
result = client.a_stock_list(limit=1) # 示例调用
|
|
314
|
+
|
|
315
|
+
# 添加股票代码到结果中(如果接口没有返回)
|
|
316
|
+
if hasattr(result, 'to_dict'):
|
|
317
|
+
data_dict = result.to_dict()
|
|
318
|
+
if isinstance(data_dict, list):
|
|
319
|
+
all_data.extend(data_dict)
|
|
320
|
+
else:
|
|
321
|
+
all_data.append(data_dict)
|
|
322
|
+
|
|
323
|
+
# 添加延迟避免频率限制
|
|
324
|
+
time.sleep(0.1)
|
|
325
|
+
|
|
326
|
+
except Exception as e:
|
|
327
|
+
print(f"❌ 查询股票 {stock_code} 失败:{e}")
|
|
328
|
+
continue
|
|
329
|
+
|
|
330
|
+
if all_data:
|
|
331
|
+
return pd.DataFrame(all_data)
|
|
332
|
+
else:
|
|
333
|
+
return pd.DataFrame()
|
|
334
|
+
|
|
335
|
+
# 使用示例
|
|
336
|
+
stock_codes = ['000001', '000002', '600000', '600036']
|
|
337
|
+
df = batch_query_stocks(stock_codes)
|
|
338
|
+
print(f"总共获取 {len(df)} 条股票数据")
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### 动态接口调用
|
|
342
|
+
```python
|
|
343
|
+
def dynamic_api_call(client, api_name: str, **params):
|
|
344
|
+
"""动态调用任意API接口"""
|
|
345
|
+
try:
|
|
346
|
+
# 方法一:通过动态属性调用
|
|
347
|
+
api_method = getattr(client, api_name)
|
|
348
|
+
result = api_method(**params)
|
|
349
|
+
|
|
350
|
+
# 方法二:通过query方法调用
|
|
351
|
+
# result = client.query(api_name, **params)
|
|
352
|
+
|
|
353
|
+
return result
|
|
354
|
+
|
|
355
|
+
except AttributeError:
|
|
356
|
+
print(f"❌ 接口 {api_name} 不存在")
|
|
357
|
+
return None
|
|
358
|
+
except Exception as e:
|
|
359
|
+
print(f"❌ 调用接口 {api_name} 失败:{e}")
|
|
360
|
+
return None
|
|
361
|
+
|
|
362
|
+
# 使用示例
|
|
363
|
+
client = dc.init(token='your_api_token')
|
|
364
|
+
result = dynamic_api_call(client, 'hsgt_fund_page_list', page=1, page_size=10)
|
|
365
|
+
if result is not None:
|
|
366
|
+
print(f"成功获取 {len(result)} 条数据")
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## 9. ❓ 常见问题
|
|
370
|
+
|
|
371
|
+
### Q1: 如何获取API Token?
|
|
372
|
+
**A**: 请联系系统管理员或访问数据管理后台申请API访问权限。
|
|
373
|
+
|
|
374
|
+
### Q2: 支持哪些股票代码格式?
|
|
375
|
+
**A**:
|
|
376
|
+
- A股:基础格式6位数字或带后缀格式,如 "000001", "600000","000001.SZ", "600000.SH"
|
|
377
|
+
- 港股:基础格式5位数字,如 "00700", "00941", "00700.HK"
|
|
378
|
+
- 指数:通常包含后缀,如 "000300.SH", "000905.SZ"
|
|
379
|
+
|
|
380
|
+
### Q3: 如何知道某个接口是否存在?
|
|
381
|
+
**A**:
|
|
382
|
+
```python
|
|
383
|
+
# 搜索接口
|
|
384
|
+
import requests
|
|
385
|
+
response = requests.get('http://data.alphaaidig.com/api/v1/docs/search?q=接口名')
|
|
386
|
+
if response.status_code == 200:
|
|
387
|
+
results = response.json()
|
|
388
|
+
print(f"找到 {results['total_count']} 个相关接口")
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Q4: 如何处理大量数据?
|
|
392
|
+
**A**:
|
|
393
|
+
1. 每次请求适量数据
|
|
394
|
+
2. 正确处理分页信息,避免遗漏数据
|
|
395
|
+
3. 添加适当的延迟避免频率限制
|
|
396
|
+
4. 使用批量处理提高效率
|
|
397
|
+
|
|
398
|
+
### Q5: API调用失败怎么办?
|
|
399
|
+
**A**:
|
|
400
|
+
1. 检查网络连接和base_url是否正确
|
|
401
|
+
2. 验证API token是否有效
|
|
402
|
+
3. 确认接口名称和参数是否正确
|
|
403
|
+
4. 查看错误信息进行针对性处理
|
|
404
|
+
5. 使用错误处理机制捕获异常
|
|
405
|
+
|
|
406
|
+
### Q6: 返回的数据格式是什么?
|
|
407
|
+
**A**:
|
|
408
|
+
- **分页数据**: PageDataFrame,包含分页信息和数据
|
|
409
|
+
- **普通数据**: pandas DataFrame
|
|
410
|
+
- **单条记录**: pandas DataFrame(单行)
|
|
411
|
+
- **其他**: 根据具体接口可能返回不同格式
|
|
412
|
+
|
|
413
|
+
### Q7: 如何获取完整的接口文档?
|
|
414
|
+
**A**:
|
|
415
|
+
```python
|
|
416
|
+
import requests
|
|
417
|
+
|
|
418
|
+
# 获取完整文档
|
|
419
|
+
response = requests.get('http://data.alphaaidig.com/api/v1/docs/json')
|
|
420
|
+
if response.status_code == 200:
|
|
421
|
+
docs = response.json()
|
|
422
|
+
print(f"总共有 {docs['total_count']} 个接口")
|
|
423
|
+
for api in docs['apis']:
|
|
424
|
+
print(f"- {api['name']}: {api['description']}")
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Q8: IDE无法识别动态方法怎么办?
|
|
428
|
+
**A**: 现代IDE(如PyCharm、VSCode)会通过运行时学习动态方法,使用几次后就能识别。也可以:
|
|
429
|
+
1. 使用 `client.query('方法名')` 的方式调用
|
|
430
|
+
2. 添加类型提示注释
|
|
431
|
+
3. 确保导入正确的异常类
|
|
432
|
+
|
|
433
|
+
## 📞 技术支持
|
|
434
|
+
|
|
435
|
+
如果遇到问题,可以:
|
|
436
|
+
1. 查看API错误信息进行调试
|
|
437
|
+
2. 访问 http://data.alphaaidig.com/api/v1/docs 查看完整API文档
|
|
438
|
+
3. 联系技术支持团队
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "alpha-dc-client"
|
|
7
|
+
version = "0.1.23"
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "Hang GuangLiang", email = "hanguangliang@alphaaidig.com"},
|
|
10
|
+
]
|
|
11
|
+
dependencies = [
|
|
12
|
+
"httpx",
|
|
13
|
+
"dc_common==0.1.23"
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[tool.hatch.build.targets.wheel]
|
|
17
|
+
packages = ["src/dc_client"]
|
|
18
|
+
|
|
19
|
+
[tool.uv.sources]
|
|
20
|
+
dc_common = { workspace = true }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dc_client"
|
|
7
|
+
version = "0.1.23"
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "Hang GuangLiang", email = "hanguangliang@alphaaidig.com"},
|
|
10
|
+
]
|
|
11
|
+
dependencies = [
|
|
12
|
+
"httpx",
|
|
13
|
+
"dc_common==0.1.23"
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[tool.hatch.build.targets.wheel]
|
|
17
|
+
packages = ["src/dc_client"]
|
|
18
|
+
|
|
19
|
+
[tool.uv.sources]
|
|
20
|
+
dc_common = { workspace = true }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .exceptions import APIError, AuthenticationError, NotFoundError, InvalidRequestError
|
|
2
|
+
from .client import DataApi, init, PageDataFrame, DatacenterAPIError
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"DataApi",
|
|
6
|
+
"init",
|
|
7
|
+
"PageDataFrame",
|
|
8
|
+
"DatacenterAPIError",
|
|
9
|
+
"APIError",
|
|
10
|
+
"AuthenticationError",
|
|
11
|
+
"NotFoundError",
|
|
12
|
+
"InvalidRequestError",
|
|
13
|
+
]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
from typing import Optional, Dict, Any
|
|
3
|
+
|
|
4
|
+
from .exceptions import APIError, AuthenticationError, NotFoundError, InvalidRequestError
|
|
5
|
+
|
|
6
|
+
class BaseClient:
|
|
7
|
+
"""
|
|
8
|
+
A base client for making requests to the Datacenter API.
|
|
9
|
+
"""
|
|
10
|
+
def __init__(self, base_url: str, token: Optional[str] = None, timeout: int = 30):
|
|
11
|
+
"""
|
|
12
|
+
Initializes the API client.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
base_url: The base URL for the API, e.g., "http://localhost:10000".
|
|
16
|
+
token: An optional token for authentication.
|
|
17
|
+
timeout: The request timeout in seconds.
|
|
18
|
+
"""
|
|
19
|
+
self._base_url = base_url.rstrip('/')
|
|
20
|
+
self._token = token
|
|
21
|
+
self._timeout = timeout
|
|
22
|
+
|
|
23
|
+
headers = {"Content-Type": "application/json"}
|
|
24
|
+
if self._token:
|
|
25
|
+
headers["X-API-Key"] = self._token
|
|
26
|
+
|
|
27
|
+
self._http_client = httpx.Client(base_url=self._base_url, headers=headers, timeout=self._timeout)
|
|
28
|
+
|
|
29
|
+
def _request(self, method: str, endpoint: str, params: Optional[Dict[str, Any]] = None, json: Optional[Dict[str, Any]] = None) -> Any:
|
|
30
|
+
"""
|
|
31
|
+
Makes an HTTP request and handles potential errors.
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
response = self._http_client.request(method, endpoint, params=params, json=json)
|
|
35
|
+
response.raise_for_status()
|
|
36
|
+
|
|
37
|
+
response_data = response.json()
|
|
38
|
+
if response_data.get("status") == "success":
|
|
39
|
+
return response_data
|
|
40
|
+
|
|
41
|
+
raise APIError(f"API returned non-success status: {response_data.get('status', 'N/A')}", status_code=response.status_code)
|
|
42
|
+
|
|
43
|
+
except httpx.HTTPStatusError as e:
|
|
44
|
+
status_code = e.response.status_code
|
|
45
|
+
try:
|
|
46
|
+
detail = e.response.json().get("detail", e.response.text)
|
|
47
|
+
except Exception:
|
|
48
|
+
detail = e.response.text
|
|
49
|
+
|
|
50
|
+
if status_code == 404:
|
|
51
|
+
raise NotFoundError(detail) from e
|
|
52
|
+
elif status_code in [401, 403]:
|
|
53
|
+
raise AuthenticationError(detail) from e
|
|
54
|
+
elif status_code == 400:
|
|
55
|
+
raise InvalidRequestError(detail) from e
|
|
56
|
+
else:
|
|
57
|
+
raise APIError(f"HTTP Error: {detail}", status_code=status_code) from e
|
|
58
|
+
except httpx.RequestError as e:
|
|
59
|
+
raise APIError(f"Request failed: {e}") from e
|
|
60
|
+
|
|
61
|
+
def close(self):
|
|
62
|
+
"""Closes the underlying HTTP client."""
|
|
63
|
+
self._http_client.close()
|
|
64
|
+
|
|
65
|
+
def __enter__(self):
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
69
|
+
self.close()
|