quantdb-sdk 0.4.6__tar.gz → 0.4.7__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.
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/CHANGELOG.md +14 -0
- {quantdb_sdk-0.4.6/quantdb_sdk.egg-info → quantdb_sdk-0.4.7}/PKG-INFO +1 -1
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/pyproject.toml +1 -1
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/async_client.py +5 -6
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/client.py +11 -17
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7/quantdb_sdk.egg-info}/PKG-INFO +1 -1
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/LICENSE +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/MANIFEST.in +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/README.md +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/__init__.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/__main__.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/_utils.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/errors.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/examples/__init__.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/examples/demo_01_connect_basics.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/examples/demo_02_kline_v2_daily.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/examples/demo_03_sync_full_market.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/examples/demo_04_duckdb_warehouse.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/examples/demo_05_read_local_data.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/examples/demo_06_tick_and_factors.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/examples/demo_07_data_hub.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/hub.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/layout.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/mcp_download.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk/py.typed +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk.egg-info/SOURCES.txt +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk.egg-info/dependency_links.txt +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk.egg-info/entry_points.txt +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk.egg-info/requires.txt +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/quantdb_sdk.egg-info/top_level.txt +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/setup.cfg +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/tests/test_async_client.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/tests/test_client.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/tests/test_data_hub.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/tests/test_hub_models.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/tests/test_layout.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/tests/test_mcp_download.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/tests/test_technical_indicators.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/tests/test_update_pipeline.py +0 -0
- {quantdb_sdk-0.4.6 → quantdb_sdk-0.4.7}/tests/test_utils.py +0 -0
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
所有 notable 变更都会记录在此文件。格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
|
4
4
|
版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
|
|
5
5
|
|
|
6
|
+
## \[0.4.7] - 2026-10-27
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **适配下载 302 单跳直连**:服务端已取消「一次性下载令牌 + `/api/v1/data/cdn-bridge` 中转」链路,`/api/v1/data/download` 预扣成功后直接 302 到 CDN 签名 URL(单跳)。同步/异步客户端原有的两跳跟随假设已相应调整:
|
|
11
|
+
- 新增 **CDN 专用裸会话**(`QuantDBClient._cdn_session`):直连 CDN 时**不携带 API Key / JWT**,避免鉴权头泄露到 CDN 域;同一会话跨文件复用 TLS 连接,避免逐文件新建连接反复握手。
|
|
12
|
+
- 手动跟随重定向并保留每跳的 connect timeout 重试,网络抖动不会中断整个同步。
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- 直连 CDN 模式**签发即按对象大小计费、不再退款**(服务端无法观测直连传输的真实字节,退款只能依赖客户端自报,不可信)。需要按真实传输计费、断点续传可退款的用户,应在请求头发送 `X-QuantDB-Delivery: proxy` 走网关代理模式(网关可观测字节并按未发送部分退款)。
|
|
17
|
+
|
|
18
|
+
> 兼容性:0.4.7 对接 2026-10-27 上线的服务端版本;旧服务端(两跳 cdn-bridge)仍可正常同步,无需回退。
|
|
19
|
+
|
|
6
20
|
## \[0.4.6] - 2026-10-27
|
|
7
21
|
|
|
8
22
|
### Fixed
|
|
@@ -28,7 +28,7 @@ from .errors import (
|
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
# 维护提示:每次发版必须与 pyproject.toml 版本号同步
|
|
31
|
-
_USER_AGENT = "QuantDB-Python-SDK/0.4.
|
|
31
|
+
_USER_AGENT = "QuantDB-Python-SDK/0.4.7"
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
def _etag_hex(value: Optional[str]) -> Optional[str]:
|
|
@@ -139,8 +139,8 @@ class AsyncQuantDBClient:
|
|
|
139
139
|
裸客户端直连 Location,鉴权头不会泄露给 CDN 域。
|
|
140
140
|
|
|
141
141
|
重定向链路(CDN 直连模式):
|
|
142
|
-
/download 302→
|
|
143
|
-
|
|
142
|
+
/download 302→ https://cdn.xxx/key?sign=...(单跳)
|
|
143
|
+
手动跟随,每跳带重试(connect timeout 网络抖动容错)。
|
|
144
144
|
"""
|
|
145
145
|
async with self.client.stream(
|
|
146
146
|
"GET", f"{self.api_host}/api/v1/data/download", params=params, headers=headers
|
|
@@ -166,9 +166,8 @@ class AsyncQuantDBClient:
|
|
|
166
166
|
) -> httpx.Response:
|
|
167
167
|
"""手动跟随 302 重定向链路,每跳带重试。
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
sync 中断。
|
|
169
|
+
CDN 直连请求通过此方法,connect timeout 网络抖动时自动重试,避免
|
|
170
|
+
单次抖动导致整个 sync 中断。
|
|
172
171
|
|
|
173
172
|
返回已进入 stream 模式的 httpx.Response,调用方需用 async with 管理。
|
|
174
173
|
"""
|
|
@@ -32,7 +32,7 @@ from .errors import (
|
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
# 维护提示:每次发版必须与 pyproject.toml 版本号同步
|
|
35
|
-
_USER_AGENT = "QuantDB-Python-SDK/0.4.
|
|
35
|
+
_USER_AGENT = "QuantDB-Python-SDK/0.4.7"
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
def _etag_hex(value: Optional[str]) -> Optional[str]:
|
|
@@ -75,6 +75,9 @@ class QuantDBClient:
|
|
|
75
75
|
self.headers: Dict[str, str] = {}
|
|
76
76
|
self.session = requests.Session()
|
|
77
77
|
self.session.headers.update({"User-Agent": _USER_AGENT})
|
|
78
|
+
# CDN 直连专用会话:不携带 API Key / JWT,且跨文件复用 TLS 连接(逐文件新建连接会反复握手)。
|
|
79
|
+
self._cdn_session = requests.Session()
|
|
80
|
+
self._cdn_session.headers.update({"User-Agent": _USER_AGENT})
|
|
78
81
|
|
|
79
82
|
if api_key:
|
|
80
83
|
self.headers = {"X-API-Key": api_key}
|
|
@@ -168,13 +171,10 @@ class QuantDBClient:
|
|
|
168
171
|
def _download_stream(self, params: dict, headers: Optional[dict] = None) -> requests.Response:
|
|
169
172
|
"""下载专用流式请求:手动处理服务端 302 CDN 直连跳转。
|
|
170
173
|
|
|
171
|
-
服务端开启 CDN 直连后,/api/v1/data/download
|
|
172
|
-
302 -> CDN 签名 URL
|
|
173
|
-
透传给 CDN
|
|
174
|
-
|
|
175
|
-
重定向链路(CDN 直连模式):
|
|
176
|
-
/download 302→ /cdn-bridge?token=xxx 302→ https://cdn.xxx/key?sign=...
|
|
177
|
-
两跳均手动跟随,每跳带重试(connect timeout 网络抖动容错)。
|
|
174
|
+
服务端开启 CDN 直连后,/api/v1/data/download 预扣流量成功时直接返回
|
|
175
|
+
302 -> CDN 签名 URL(单跳)。requests 自动跟随会把自定义 X-API-Key 头
|
|
176
|
+
透传给 CDN 域,故禁用自动跟随,改用不带鉴权头的 CDN 专用会话直连。
|
|
177
|
+
每跳带重试(connect timeout 网络抖动容错)。
|
|
178
178
|
"""
|
|
179
179
|
resp = self._request(
|
|
180
180
|
"GET", "/api/v1/data/download", params=params, stream=True,
|
|
@@ -200,21 +200,15 @@ class QuantDBClient:
|
|
|
200
200
|
) -> requests.Response:
|
|
201
201
|
"""手动跟随 302 重定向链路,每跳带重试。
|
|
202
202
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
sync 中断。
|
|
203
|
+
CDN 直连请求通过此方法,connect timeout 网络抖动时自动重试,避免
|
|
204
|
+
单次抖动导致整个 sync 中断。
|
|
206
205
|
"""
|
|
207
206
|
current_etag = etag
|
|
208
207
|
for _ in range(max_hops):
|
|
209
208
|
last_exc = None
|
|
210
209
|
for attempt in range(retries + 1):
|
|
211
210
|
try:
|
|
212
|
-
cdn_resp =
|
|
213
|
-
url,
|
|
214
|
-
stream=True,
|
|
215
|
-
timeout=self.timeout,
|
|
216
|
-
headers={"User-Agent": _USER_AGENT},
|
|
217
|
-
)
|
|
211
|
+
cdn_resp = self._cdn_session.get(url, stream=True, timeout=self.timeout)
|
|
218
212
|
break
|
|
219
213
|
except (requests.ConnectionError, requests.Timeout) as exc:
|
|
220
214
|
last_exc = exc
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|