quantdb-sdk 0.2.0__tar.gz → 0.2.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.
Files changed (23) hide show
  1. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/CHANGELOG.md +6 -0
  2. {quantdb_sdk-0.2.0/quantdb_sdk.egg-info → quantdb_sdk-0.2.1}/PKG-INFO +1 -1
  3. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/pyproject.toml +1 -1
  4. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk/__init__.py +1 -1
  5. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk/async_client.py +7 -2
  6. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk/client.py +7 -2
  7. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1/quantdb_sdk.egg-info}/PKG-INFO +1 -1
  8. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/tests/test_async_client.py +1 -1
  9. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/tests/test_client.py +1 -1
  10. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/LICENSE +0 -0
  11. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/MANIFEST.in +0 -0
  12. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/README.md +0 -0
  13. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk/__main__.py +0 -0
  14. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk/_utils.py +0 -0
  15. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk/errors.py +0 -0
  16. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk/py.typed +0 -0
  17. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk.egg-info/SOURCES.txt +0 -0
  18. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk.egg-info/dependency_links.txt +0 -0
  19. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk.egg-info/entry_points.txt +0 -0
  20. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk.egg-info/requires.txt +0 -0
  21. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/quantdb_sdk.egg-info/top_level.txt +0 -0
  22. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/setup.cfg +0 -0
  23. {quantdb_sdk-0.2.0 → quantdb_sdk-0.2.1}/tests/test_technical_indicators.py +0 -0
@@ -3,6 +3,12 @@
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.2.1] - 2026-07-26
7
+
8
+ ### Fixed
9
+ - **历史发布清单兼容**:同步客户端自动归一化旧 release manifest 遗留的 `v2/` 前缀,并可下载 release patch 对象。
10
+ - **布局回退**:服务端以 COS Manifest 为可用性权威,V2 元数据缺失时可正确回退 V1,而非将数据误判为不可下载。
11
+
6
12
  ## [0.2.0] - 2026-07-26
7
13
 
8
14
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantdb-sdk
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: QuantDB 量化数据平台官方 Python SDK
5
5
  Author: QuantDB Team
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "quantdb-sdk"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "QuantDB 量化数据平台官方 Python SDK"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -5,7 +5,7 @@ try:
5
5
  # 注意:此处用 PyPI 包名(连字符)查找版本号,不是模块名(下划线)
6
6
  __version__ = version("quantdb-sdk")
7
7
  except ImportError:
8
- __version__ = "0.2.0"
8
+ __version__ = "0.2.1"
9
9
 
10
10
  from .async_client import AsyncQuantDBClient
11
11
  from .client import DuckDBWarehouse, QuantDBClient
@@ -37,7 +37,7 @@ class AsyncQuantDBClient:
37
37
  ):
38
38
  self.api_host = api_host.rstrip("/")
39
39
  self.timeout = timeout
40
- headers = {"User-Agent": "QuantDB-Python-SDK/0.2.0"}
40
+ headers = {"User-Agent": "QuantDB-Python-SDK/0.2.1"}
41
41
  if api_key:
42
42
  headers["X-API-Key"] = api_key
43
43
  elif token:
@@ -66,6 +66,10 @@ class AsyncQuantDBClient:
66
66
  raise ValidationError("layout 仅支持 auto、v1 或 v2")
67
67
  return layout # type: ignore[return-value]
68
68
 
69
+ @staticmethod
70
+ def _normalise_release_key(key: str) -> str:
71
+ return key.strip().lstrip("/").removeprefix("v2/")
72
+
69
73
  @staticmethod
70
74
  def _normalise_kline(df: pd.DataFrame, start_date: Optional[str], end_date: Optional[str], fields: str, limit: Optional[int]) -> pd.DataFrame:
71
75
  if "time" in df.columns:
@@ -544,7 +548,8 @@ class AsyncQuantDBClient:
544
548
  if releases:
545
549
  for release in releases:
546
550
  for obj in release.get("objects", []):
547
- key, target = obj["key"], os.path.join(root, *obj["key"].split("/"))
551
+ key = self._normalise_release_key(obj["key"])
552
+ target = os.path.join(root, *key.split("/"))
548
553
  old = state.execute("SELECT etag,sha256,path FROM objects WHERE key=?", (key,)).fetchone()
549
554
  if old and old[0] == obj.get("etag") and old[1] == obj.get("sha256") and os.path.exists(old[2]): continue
550
555
  os.makedirs(os.path.dirname(target), exist_ok=True)
@@ -48,7 +48,7 @@ class QuantDBClient:
48
48
  self.session = requests.Session()
49
49
  # User-Agent 中的版本与 pyproject.toml 同步,用于服务端日志归因
50
50
  # 维护提示:每次版本号变化必须同步改这里(init 里的 __version__ 走 metadata 自动同步)
51
- self.session.headers.update({"User-Agent": "QuantDB-Python-SDK/0.2.0"})
51
+ self.session.headers.update({"User-Agent": "QuantDB-Python-SDK/0.2.1"})
52
52
 
53
53
  if api_key:
54
54
  self.headers = {"X-API-Key": api_key}
@@ -164,6 +164,11 @@ class QuantDBClient:
164
164
  raise ValidationError("layout 仅支持 auto、v1 或 v2")
165
165
  return layout # type: ignore[return-value]
166
166
 
167
+ @staticmethod
168
+ def _normalise_release_key(key: str) -> str:
169
+ """兼容历史 release manifest 遗留的 ``v2/`` 对象前缀。"""
170
+ return key.strip().lstrip("/").removeprefix("v2/")
171
+
167
172
  @staticmethod
168
173
  def _normalise_kline(df: pd.DataFrame, start_date: Optional[str], end_date: Optional[str], fields: str, limit: Optional[int]) -> pd.DataFrame:
169
174
  """统一 V1/V2 日线结果并在客户端按标的、日期与字段过滤。"""
@@ -641,7 +646,7 @@ class QuantDBClient:
641
646
  for release in releases:
642
647
  release_id = release["release_id"]
643
648
  for obj in release.get("objects", []):
644
- key = obj["key"]
649
+ key = self._normalise_release_key(obj["key"])
645
650
  relative_path = obj.get("relative_path") or key
646
651
  target = os.path.join(root, *relative_path.split("/"))
647
652
  old = state.execute("SELECT etag, sha256, path FROM objects WHERE key=?", (key,)).fetchone()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantdb-sdk
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: QuantDB 量化数据平台官方 Python SDK
5
5
  Author: QuantDB Team
6
6
  License: MIT
@@ -55,7 +55,7 @@ async def test_a_query_kline_without_range_forces_v1_layout():
55
55
  async def test_a_sync_dataset_uses_release_cursor(tmp_path):
56
56
  payload = b"release-parquet"
57
57
  digest = __import__("hashlib").sha256(payload).hexdigest()
58
- respx.get(f"{API_HOST}/api/v1/data/releases").mock(return_value=httpx.Response(200, json={"releases": [{"release_id": "20260726_180000", "objects": [{"key": "1_kline_data/daily_forward/dt=20260726/data.parquet", "etag": "etag-1", "sha256": digest}]}]}))
58
+ respx.get(f"{API_HOST}/api/v1/data/releases").mock(return_value=httpx.Response(200, json={"releases": [{"release_id": "20260726_180000", "objects": [{"key": "v2/1_kline_data/daily_forward/dt=20260726/data.parquet", "etag": "etag-1", "sha256": digest}]}]}))
59
59
  route = respx.get(f"{API_HOST}/api/v1/data/download").mock(return_value=httpx.Response(200, content=payload))
60
60
  async with AsyncQuantDBClient(api_host=API_HOST, api_key="test-key") as client:
61
61
  result = await client.a_sync_dataset("daily_forward", str(tmp_path))
@@ -79,7 +79,7 @@ def test_sync_dataset_uses_release_cursor_and_object_key(tmp_path):
79
79
  digest = __import__("hashlib").sha256(payload).hexdigest()
80
80
  responses.get(
81
81
  f"{API_HOST}/api/v1/data/releases",
82
- json={"releases": [{"release_id": "20260726_180000", "objects": [{"key": "1_kline_data/daily_forward/dt=20260726/data.parquet", "etag": "etag-1", "sha256": digest}]}]}, status=200,
82
+ json={"releases": [{"release_id": "20260726_180000", "objects": [{"key": "v2/1_kline_data/daily_forward/dt=20260726/data.parquet", "etag": "etag-1", "sha256": digest}]}]}, status=200,
83
83
  )
84
84
  responses.get(f"{API_HOST}/api/v1/data/download", body=payload, status=200)
85
85
  client = QuantDBClient(api_host=API_HOST, api_key="test-key")
File without changes
File without changes
File without changes
File without changes