diff --git a/sanguo_factor/composite_weighting.py b/sanguo_factor/composite_weighting.py index f7d9bb0..c883d62 100644 --- a/sanguo_factor/composite_weighting.py +++ b/sanguo_factor/composite_weighting.py @@ -155,6 +155,10 @@ def _register_all() -> None: 文件到位即自动注册,不 ImportError). """ composite_library._register_all() + # 幂等重挂 fund_*_neu(reload 场景 registry 被清后,neu 模块不会随之重执行, + # v2b 档案存在时其源必须可重建——v2b 档案上线前此缺口被 graceful 分支掩盖) + from .fundamental_neutralize import _register_all as _neu_register_all + _neu_register_all() register_composite_from_profile(load_profile(str(_DEFAULT_PROFILE_PATH)), _DEFAULT_COMPOSITE_NAME) if _V2B_PROFILE_PATH.exists(): diff --git a/tests/factor/test_fundamental_library.py b/tests/factor/test_fundamental_library.py index 741566c..985c027 100644 --- a/tests/factor/test_fundamental_library.py +++ b/tests/factor/test_fundamental_library.py @@ -19,8 +19,9 @@ def _ensure_fundamental_registered(): # 表达式可引用的列 = adapter 特征列 + 行情列 close(估值类 ÷ close×share_capital) -# + 表达式函数名(P1 起用到 log) -_ALLOWED = set(FEATURE_COLUMNS) | {"close", "cs_rank", "log"} +# + 表达式函数名(P1 起用到 log;v2b 起中性化因子用 cs_neutralize) +from sanguo_factor.fundamental_neutralize import FUND_NEU_SOURCES +_ALLOWED = set(FEATURE_COLUMNS) | {"close", "cs_rank", "log", "cs_neutralize"} def _fundamental_factors() -> list[dict]: @@ -31,7 +32,9 @@ def test_p0_32_factors_registered(): facs = _fundamental_factors() names = {f["name"] for f in facs} # P0 32 + P1 37(35 因子 + 2 互评变体;P1 名单见 test_fundamental_p1_library) - assert len(facs) == 75, f"P0+P1+P1-B 应为 75 个,实际 {len(facs)}" + # + v2b 中性化 6(fund_*_neu,注册链经 composite_weighting 可在场,故派生不钉死) + assert len(facs) == 75 + len(FUND_NEU_SOURCES), \ + f"P0+P1+P1-B+neu 应为 {75 + len(FUND_NEU_SOURCES)} 个,实际 {len(facs)}" # 六族代表抽查(全部名单见 fundamental_library 注释) expect = { "fund_roe_ttm", "fund_gp_over_assets", # A @@ -83,4 +86,4 @@ def test_registration_idempotent(): """重复 import 不炸(注册表防重入,同 library.py 模式).""" import importlib importlib.reload(fundamental_library) - assert len(_fundamental_factors()) == 75 + assert len(_fundamental_factors()) == 75 + len(FUND_NEU_SOURCES) diff --git a/tests/factor/test_fundamental_neutralize.py b/tests/factor/test_fundamental_neutralize.py index c37ebc9..c36756c 100644 --- a/tests/factor/test_fundamental_neutralize.py +++ b/tests/factor/test_fundamental_neutralize.py @@ -227,10 +227,12 @@ def test_weighting_rejects_mixed_direction_drift(): assert get_factor(name) is None -def test_v2b_profile_absent_skips_registration(): - """v2b 档案不存在(仓库当前态): _register_all 不炸、不注册 composite_all18_v2b.""" +def test_v2b_profile_absent_skips_registration(tmp_path, monkeypatch): + """v2b 档案不存在(真档案已上线,monkeypatch 指向不存在路径模拟缺席): + _register_all 不炸、不注册 composite_all18_v2b.""" _REGISTRY.pop(composite_weighting._V2B_COMPOSITE_NAME, None) - assert not composite_weighting._V2B_PROFILE_PATH.exists() + monkeypatch.setattr(composite_weighting, "_V2B_PROFILE_PATH", + tmp_path / "absent_v2b.json") composite_weighting._register_all() # 不应 raise assert get_factor(composite_weighting._V2B_COMPOSITE_NAME) is None