From 64ab9a0818626a768a6ecfaee231f0b643dbc639 Mon Sep 17 00:00:00 2001 From: kevin9327 Date: Sun, 30 Aug 2026 18:38:24 +0900 Subject: [PATCH] =?UTF-8?q?fix(pipeline):=20A=20=E8=82=A1=E7=9B=98?= =?UTF-8?q?=E5=90=8E=E6=8B=89=E5=8F=96=E5=BC=80=E5=85=B3=E7=94=9F=E6=95=88?= =?UTF-8?q?=20(#216)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: 在设置里取消勾选「A 股」拉取(pipeline_pull_a_share=false)后完全不 生效, 每次同步仍拉取全市场 A 股日K。 根因: 两处联合导致开关不可用: 1. get_pipeline_pull_a_share() 硬编码 return True, 从不读取偏好, 使 jobs/daily_pipeline.py 里 `if not pull_a_share` 的跳过分支永不可达。 2. set_pipeline_pull_types() 的白名单 _PIPELINE_PULL_KEYS 遗漏 pipeline_pull_a_share, 即使 API 模型接受该字段, 值也会被静默丢弃、无法落盘。 (ETF / 指数两个开关均正常读写, 仅 A 股异常。) 修复: - get_pipeline_pull_a_share() 改为 load().get("pipeline_pull_a_share", True), 与 ETF / 指数保持一致, 默认仍为 True (向后兼容, 旧配置无此键时行为不变)。 - 白名单补入 pipeline_pull_a_share, 使 PUT /api/settings/preferences/ pipeline-pull-types 能正确落盘。 验证: backend/tests/test_pipeline_pull_types.py 覆盖默认值、关闭后 getter 生效、 setter 落盘与三开关独立性; 修复前 3 例失败, 修复后全过。 Co-Authored-By: Claude Opus 4.8 --- backend/app/services/preferences.py | 6 +-- backend/tests/test_pipeline_pull_types.py | 60 +++++++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 backend/tests/test_pipeline_pull_types.py diff --git a/backend/app/services/preferences.py b/backend/app/services/preferences.py index f5470ff..0180608 100644 --- a/backend/app/services/preferences.py +++ b/backend/app/services/preferences.py @@ -284,8 +284,8 @@ def get_financial_provider() -> str: # ===== 盘后管道拉取内容开关 (A股 / ETF / 指数 独立控制) ===== def get_pipeline_pull_a_share() -> bool: - """A 股日K固定拉取。""" - return True + """是否拉取 A 股日K。默认 True。""" + return load().get("pipeline_pull_a_share", True) def get_pipeline_pull_etf() -> bool: @@ -429,7 +429,7 @@ def set_mainline_filter_config(cfg: dict) -> dict: return get_mainline_filter_config() -_PIPELINE_PULL_KEYS = ("pipeline_pull_etf", "pipeline_pull_index") +_PIPELINE_PULL_KEYS = ("pipeline_pull_a_share", "pipeline_pull_etf", "pipeline_pull_index") def get_pipeline_pull_types() -> dict: diff --git a/backend/tests/test_pipeline_pull_types.py b/backend/tests/test_pipeline_pull_types.py new file mode 100644 index 0000000..e8b65fe --- /dev/null +++ b/backend/tests/test_pipeline_pull_types.py @@ -0,0 +1,60 @@ +"""盘后管道「A股 / ETF / 指数」拉取开关回归测试。 + +覆盖 issue #216: `get_pipeline_pull_a_share()` 硬编码 True 且 A股键不在 +`set_pipeline_pull_types()` 白名单内, 导致取消勾选 A 股完全不生效。 + +纯逻辑, 不触网, 不依赖真实数据源。 +""" +from __future__ import annotations + +import pytest + +from app.services import preferences + + +@pytest.fixture(autouse=True) +def _isolated(tmp_path, monkeypatch): + path = tmp_path / "preferences.json" + monkeypatch.setattr(preferences, "_path", lambda: path) + preferences._invalidate_cache() + yield path + preferences._invalidate_cache() + + +def test_a_share_defaults_to_true_when_unset(): + """未设置时三个开关的默认值: A股/指数 默认开, ETF 默认关。""" + assert preferences.get_pipeline_pull_a_share() is True + assert preferences.get_pipeline_pull_index() is True + assert preferences.get_pipeline_pull_etf() is False + + +def test_a_share_toggle_off_is_honored(): + """写入 False 后 getter 必须返回 False(修复前硬编码 True)。""" + preferences.save({"pipeline_pull_a_share": False}) + assert preferences.get_pipeline_pull_a_share() is False + + +def test_set_pipeline_pull_types_persists_a_share(): + """setter 必须接受并落盘 A 股开关(修复前白名单遗漏该键, 被静默丢弃)。""" + result = preferences.set_pipeline_pull_types({"pipeline_pull_a_share": False}) + assert result["pipeline_pull_a_share"] is False + # 落盘后重新读取仍为 False + preferences._invalidate_cache() + assert preferences.get_pipeline_pull_a_share() is False + assert preferences.get_pipeline_pull_types()["pipeline_pull_a_share"] is False + + +def test_set_pipeline_pull_types_independent_switches(): + """三个开关互相独立: 关 A 股不影响 ETF / 指数。""" + result = preferences.set_pipeline_pull_types( + { + "pipeline_pull_a_share": False, + "pipeline_pull_etf": True, + "pipeline_pull_index": False, + } + ) + assert result == { + "pipeline_pull_a_share": False, + "pipeline_pull_etf": True, + "pipeline_pull_index": False, + }