Skip to content

Commit 6146834

Browse files
yjwyjw
authored andcommitted
fix: ignore invalid index cache
1 parent 71c800a commit 6146834

6 files changed

Lines changed: 38 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.1.18] - 2026-06-14
9+
10+
### Fixed
11+
- Cache reads no longer create cache directories, avoiding permission-related failures when the cache path is not writable.
12+
- A-share index loading now ignores invalid cached/API shapes instead of passing non-list data to the renderer.
13+
814
## [0.1.17] - 2026-06-14
915

1016
### Fixed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "young-stock-cli"
7-
version = "0.1.17"
7+
version = "0.1.18"
88
description = "A-share (China stock market) after-hours CLI — no login, no scraping tricks, just data."
99
readme = "README.md"
1010
requires-python = ">=3.9"

src/young_stock/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""young-stock-cli: A-share after-hours CLI."""
22

3-
__version__ = "0.1.17"
3+
__version__ = "0.1.18"

src/young_stock/_core.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ def _cache_key(symbol: str, date_str: str, source: str) -> str:
252252

253253

254254
def _cache_path(symbol: str, date_str: str, source: str) -> Path:
255+
return CACHE_DIR / date_str / _cache_key(symbol, date_str, source)
256+
257+
258+
def _cache_write_path(symbol: str, date_str: str, source: str) -> Path:
255259
d = CACHE_DIR / date_str
256260
d.mkdir(parents=True, exist_ok=True)
257261
return d / _cache_key(symbol, date_str, source)
@@ -280,7 +284,7 @@ def cache_save(symbol: str, date_str: str, source: str, data: dict[str, Any]) ->
280284
payload = data.get("data") if isinstance(data, dict) else None
281285
if payload is not None and not payload: # data: [] / data: {}
282286
return
283-
p = _cache_path(symbol, date_str, source)
287+
p = _cache_write_path(symbol, date_str, source)
284288
try:
285289
with open(p, "w", encoding="utf-8") as f:
286290
json.dump(data, f, ensure_ascii=False, default=str)
@@ -1603,13 +1607,17 @@ def normalize_stock_symbol(symbol: str) -> tuple[str, str]:
16031607
def get_index(date_str: str) -> list[dict[str, Any]]:
16041608
cached = cache_load("index_all", date_str, "eastmoney")
16051609
if cached:
1606-
return cached.get("data", [])
1610+
cached_rows = cached.get("data")
1611+
if isinstance(cached_rows, list):
1612+
return cached_rows
1613+
diag("Ignored cached A-share index because data is not a list")
16071614

16081615
url = INDEX_URL.format(secids=INDEX_SECIDS, fields=INDEX_FIELDS, ts=datetime.now().timestamp())
16091616
data = fetch_json(url, {"Referer": "https://quote.eastmoney.com/"})
16101617
if "_error" in data:
16111618
diag(f"Eastmoney index: {data['_error']}")
1612-
result = data.get("data", {}).get("diff", []) if "_error" not in data else []
1619+
diff = data.get("data", {}).get("diff", []) if "_error" not in data else []
1620+
result = diff if isinstance(diff, list) else []
16131621
# 东财失败时降级到新浪
16141622
if not result:
16151623
result = _fetch_a_indices_sina()

tests/test_core.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,23 @@ def test_cache_key_deterministic():
3737
assert a == b
3838

3939

40+
def test_cache_load_missing_entry_does_not_create_directory(monkeypatch, tmp_path):
41+
cache_dir = tmp_path / "cache"
42+
monkeypatch.setattr(_core, "CACHE_DIR", cache_dir)
43+
44+
assert _core.cache_load("index_all", "20260612", "eastmoney") is None
45+
assert not cache_dir.exists()
46+
47+
48+
def test_get_index_ignores_invalid_cached_shape(monkeypatch):
49+
monkeypatch.setattr(_core, "cache_load", lambda *args, **kwargs: {"data": {"diff": "bad-shape"}})
50+
monkeypatch.setattr(_core, "fetch_json", lambda *args, **kwargs: {"_error": "blocked"})
51+
monkeypatch.setattr(_core, "_fetch_a_indices_sina", lambda: [])
52+
monkeypatch.setattr(_core, "_fetch_a_indices_tencent", lambda: [])
53+
54+
assert _core.get_index("20260612") == []
55+
56+
4057
def test_hk_indices_use_full_hsi_quote_with_volume(monkeypatch):
4158
def fake_fetch_sina_batch(codes):
4259
assert "hkHSI" in codes

tests/test_packaging_docs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ def test_package_version_is_next_patch_release():
1616
pyproject = (ROOT / "pyproject.toml").read_text(encoding="utf-8")
1717
init_py = (ROOT / "src" / "young_stock" / "__init__.py").read_text(encoding="utf-8")
1818

19-
assert 'version = "0.1.17"' in pyproject
19+
assert 'version = "0.1.18"' in pyproject
2020
assert 'requires-python = ">=3.9"' in pyproject
2121
assert '"Programming Language :: Python :: 3.9"' in pyproject
22-
assert '__version__ = "0.1.17"' in init_py
22+
assert '__version__ = "0.1.18"' in init_py
2323

2424

2525
def test_ci_covers_python_39():

0 commit comments

Comments
 (0)