feat(report): replace the reader edition with the full-data report
Generate the full-data edition (pl9_personal_long_report.v4) and remove the reader edition. English still contains Han, so the API withholds it (BUG-1272, investigating). This commit is not pushed to staging.
This commit is contained in:
@@ -52,10 +52,17 @@ def test_reader_report_shows_three_components_and_no_plus_minus_scoring() -> Non
|
||||
for language in ("zh", "en"):
|
||||
edition = copy.deepcopy(packet)
|
||||
edition["report_language"] = language
|
||||
markdown = _pl9_export_markdown_for_edition(edition, "reader_main")
|
||||
header = next(line for line in markdown.splitlines() if line.startswith("| House | Sign | Lord | Bhavadhipati"))
|
||||
assert header == "| House | Sign | Lord | Bhavadhipati | Dig | Drishti | Total (Virupa) | Total (Rupa) |"
|
||||
assert not re.search(r"\(Benefic\): \+2|\(Malefic\): -1\.5|吉星 \+2|凶星 -1\.5", markdown)
|
||||
markdown = _pl9_export_markdown_for_edition(edition, "full_data")
|
||||
# 原值:两版都是 | House | Sign | Lord | Bhavadhipati | Dig | Drishti | Total (Virupa) | Total (Rupa) |
|
||||
# 新值:中文表头为 | 宫位 | 星座 | 宫主 | Bhavadhipati | …;英文保持原表头
|
||||
# 原因:完整数据版中文清理翻译 House/Sign/Lord。三项分量与禁止网站 +2/−1.5 不变
|
||||
expected = {
|
||||
"zh": "| 宫位 | 星座 | 宫主 | Bhavadhipati | Dig | Drishti | Total (Virupa) | Total (Rupa) |",
|
||||
"en": "| House | Sign | Lord | Bhavadhipati | Dig | Drishti | Total (Virupa) | Total (Rupa) |",
|
||||
}[language]
|
||||
header = next(line for line in markdown.splitlines() if line.startswith(expected.split(" | Bhavadhipati")[0]))
|
||||
assert header == expected
|
||||
assert not re.search(r"\(Benefic\): \+2|\(Malefic\): -1\.5|吉星 \+2|凶星 −1\.5|凶星 -1\.5", markdown)
|
||||
|
||||
|
||||
def test_adhipathi_is_the_lords_shadbala() -> None:
|
||||
|
||||
@@ -66,7 +66,7 @@ def test_reader_report_karaka_table_is_in_bphs_order() -> None:
|
||||
from tests.test_report_english_edition import CASES, _packet
|
||||
|
||||
packet = _packet(CASES["day"])
|
||||
markdown = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reader_main")
|
||||
markdown = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "full_data")
|
||||
lines = markdown.splitlines()
|
||||
start = next(i for i, line in enumerate(lines) if line.startswith("### Jaimini Karaka"))
|
||||
rows = [line for line in lines[start + 1:start + 14] if line.startswith("| ") and "星" in line.split("|")[1]]
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
"""Read-only packet slice for the consult card (TASK-report-full-data-edition T7)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from scripts.pl9_full_data_export import FULL_DATA_DOMAINS, read_full_data_domain
|
||||
|
||||
|
||||
def test_domain_reader_detaches_a_copy_and_names_the_domain() -> None:
|
||||
packet = {
|
||||
"report_version": "pl9_personal_long_report.v4",
|
||||
"birth_info": {"name": "虚构甲"},
|
||||
"core_chart": {"lagna": "Leo"},
|
||||
"calculation_profile": {"ayanamsa": "lahiri"},
|
||||
"worksheets": {"timing": {"value": 1}},
|
||||
}
|
||||
view = read_full_data_domain(packet, "career")
|
||||
assert view["domain"] == "career"
|
||||
assert view["label"] == "事业"
|
||||
assert view["report_version"] == "pl9_personal_long_report.v4"
|
||||
assert view["core_chart"] == {"lagna": "Leo"}
|
||||
view["worksheets"]["timing"]["value"] = 2
|
||||
assert packet["worksheets"]["timing"]["value"] == 1
|
||||
|
||||
|
||||
def test_every_consult_domain_is_addressable() -> None:
|
||||
packet = {
|
||||
"report_version": "pl9_personal_long_report.v4",
|
||||
"birth_info": {},
|
||||
"core_chart": {},
|
||||
"calculation_profile": {},
|
||||
"worksheets": {},
|
||||
}
|
||||
expected = {
|
||||
"career": "事业",
|
||||
"wealth": "财富",
|
||||
"relationship": "婚恋",
|
||||
"health": "健康",
|
||||
"children": "子女",
|
||||
"parents": "父母",
|
||||
"education": "学业",
|
||||
"relocation": "迁居",
|
||||
"family": "家庭",
|
||||
"annual": "流年",
|
||||
"timing": "时间",
|
||||
"general": "综合",
|
||||
}
|
||||
assert FULL_DATA_DOMAINS == expected
|
||||
for domain, label in expected.items():
|
||||
view = read_full_data_domain(packet, domain)
|
||||
assert (view["domain"], view["label"]) == (domain, label)
|
||||
|
||||
|
||||
def test_unknown_domain_and_bad_packet_are_rejected() -> None:
|
||||
packet = {"worksheets": {}}
|
||||
with pytest.raises(KeyError):
|
||||
read_full_data_domain(packet, "romance")
|
||||
with pytest.raises(TypeError):
|
||||
read_full_data_domain([], "career") # type: ignore[arg-type]
|
||||
@@ -23,7 +23,10 @@ ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
def test_report_module_and_reference_edition_carry_the_label() -> None:
|
||||
packet = _packet(CASES["day"])
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reference")
|
||||
# 原值:reference 版含旧算法标注
|
||||
# 新值:full_data 版含同一句
|
||||
# 原因:用户看到的是完整数据版;旧算法标注必须跟着走(BUG-1215)
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "full_data")
|
||||
assert f"- 算法:{LEGACY_NOTE_ZH}" in zh
|
||||
from scripts.jyotish_engine import cmd_full_reading
|
||||
|
||||
@@ -92,7 +95,10 @@ def test_reference_edition_shows_both_and_english_terms_cover_the_rath_lines() -
|
||||
from scripts.pl9_reader_english_terms import PHRASES_EN, REGEX_EN
|
||||
|
||||
packet = _packet(CASES["day"])
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reference")
|
||||
# 原值:reference 版同时有旧算法句和 Rath 表
|
||||
# 新值:full_data 版同时有这两段
|
||||
# 原因:用户看到的是完整数据版;Rath 并列表必须跟着走(BUG-1218)
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "full_data")
|
||||
legacy = zh.index(f"- 算法:{LEGACY_NOTE_ZH}")
|
||||
rath = zh.index("- 并列:Sanjay Rath 版(并列参考,未进打分与时间轴结论;按原书 p.43 正文(第七轮裁定)):起运宫 ")
|
||||
assert legacy < rath
|
||||
|
||||
@@ -100,7 +100,7 @@ def test_reader_report_shows_conditions_not_raja() -> None:
|
||||
"node_mode": "mean", "ayanamsa": "raman", "today": "2026-10-03", "target_year": 2026, "age": 65}
|
||||
packet = dict(build_professional_report_reference_packet(cmd_full_reading(type("Args", (), dict(case))()), _export_args(dict(case)), []))
|
||||
packet["report_version"] = "pl9_personal_long_report.v3"
|
||||
markdown = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reader_main")
|
||||
markdown = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "full_data")
|
||||
rows = [line for line in markdown.splitlines() if line.startswith("| 落陷取消 |")]
|
||||
assert rows and all("成立条件:" in row for row in rows)
|
||||
assert not RAJA.search(markdown)
|
||||
|
||||
@@ -64,10 +64,10 @@ def test_chart_ascendant_carries_its_nakshatra_and_planets_are_unchanged() -> No
|
||||
@pytest.fixture(scope="module")
|
||||
def editions() -> tuple[str, str, dict]:
|
||||
packet = _packet(CASES["day"])
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reader_main")
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "full_data")
|
||||
english = copy.deepcopy(packet)
|
||||
english["report_language"] = "en"
|
||||
return zh, _pl9_export_markdown_for_edition(english, "reader_main"), packet
|
||||
return zh, _pl9_export_markdown_for_edition(english, "full_data"), packet
|
||||
|
||||
|
||||
def _table_after(markdown: str, heading: str) -> list[list[str]]:
|
||||
@@ -83,10 +83,16 @@ def _table_after(markdown: str, heading: str) -> list[list[str]]:
|
||||
|
||||
|
||||
def test_declination_table_has_no_kranti_column(editions) -> None:
|
||||
for markdown, heading in ((editions[0], "Declination / Speed"), (editions[1], "Declination / Speed")):
|
||||
# 原值:两版标题都是 Declination / Speed,表头 Planet/Degree/Declination/Speed
|
||||
# 新值:中文标题「赤纬 / 速度」,表头 行星/度数/赤纬/速度;英文保持原文
|
||||
# 原因:完整数据版中文清理翻译这四列。Kranti 列仍然不出现
|
||||
for markdown, heading, header in (
|
||||
(editions[0], "赤纬 / 速度", ["行星", "度数", "赤纬", "速度"]),
|
||||
(editions[1], "Declination / Speed", ["Planet", "Degree", "Declination", "Speed"]),
|
||||
):
|
||||
assert "Kranti" not in markdown
|
||||
rows = _table_after(markdown, heading)
|
||||
assert rows[0] == ["Planet", "Degree", "Declination", "Speed"]
|
||||
assert rows[0] == header
|
||||
assert len(rows) == 8 and all(len(row) == 4 and "-" not in row for row in rows)
|
||||
|
||||
|
||||
@@ -97,9 +103,12 @@ def test_ashtakavarga_house_table_shows_three_real_columns(editions) -> None:
|
||||
# labelled Raw. Was: ["House", "Sign", "SAV", "Lagna BAV", "SAV + Lagna"]
|
||||
# with the raw cells at indexes 2..4 (now 3..5).
|
||||
sodhita = packet["worksheets"]["strengths_and_scores"]["ashtakavarga"]["sodhita"]["sodhita_sav"]["scores"]
|
||||
# 原值:中文表头 House/Sign/…/上升 BAV;英文标题 Ashtakavarga Full House Scores,合计行 Total
|
||||
# 新值:中文按「完整宫位分数」找表,表头 宫位/星座/…/上升 BAV,合计行「合计」;英文标题 Full House Scores,表头 House/Sign/Lagna BAV,合计行 Total
|
||||
# 原因:完整数据版中文清理翻译 House/Sign/Lagna。英文先译整节标题,并把「合计」写成 Total,避免单字清理把标题拆碎或把合计留成汉字
|
||||
for markdown, heading, header, total in (
|
||||
(zh, "Ashtakavarga 完整宫位分数", ["House", "Sign", "Sodhita SAV", "Raw SAV", "上升 BAV", "Raw SAV + 上升"], "合计"),
|
||||
(en, "Ashtakavarga Full House Scores", ["House", "Sign", "Sodhita SAV", "Raw SAV", "Lagna BAV", "Raw SAV + Lagna"], "Total"),
|
||||
(zh, "完整宫位分数", ["宫位", "星座", "Sodhita SAV", "Raw SAV", "上升 BAV", "Raw SAV + 上升"], "合计"),
|
||||
(en, "Full House Scores", ["House", "Sign", "Sodhita SAV", "Raw SAV", "Lagna BAV", "Raw SAV + Lagna"], "Total"),
|
||||
):
|
||||
rows = _table_after(markdown, heading)
|
||||
assert rows[0] == header
|
||||
@@ -108,12 +117,17 @@ def test_ashtakavarga_house_table_shows_three_real_columns(editions) -> None:
|
||||
sav, lagna, full = (int(cell) for cell in row[3:])
|
||||
assert sav + lagna == full
|
||||
assert int(row[2]) <= sav
|
||||
assert totals == [total, "-", str(sum(sodhita.values())), str(EXPECTED_SAV_TOTAL), str(BAV_TOTALS["Lagna"]), str(EXPECTED_SAV_TOTAL + BAV_TOTALS["Lagna"])]
|
||||
# 原值:合计行星座格是 "-"
|
||||
# 新值:星座格是 "-"、"未列" 或 "not listed";后面四格数字不变
|
||||
# 原因:完整数据版清理器把空位写成「未列」。Sodhita / Raw SAV / 上升 BAV / 合计仍是原数
|
||||
assert totals[0] == total
|
||||
assert totals[1] in {"-", "未列", "not listed"}
|
||||
assert totals[2:] == [str(sum(sodhita.values())), str(EXPECTED_SAV_TOTAL), str(BAV_TOTALS["Lagna"]), str(EXPECTED_SAV_TOTAL + BAV_TOTALS["Lagna"])]
|
||||
# SAV equals the per-sign SAV table, Lagna BAV the Lagna bindus, and the last
|
||||
# column the engine's `house_scores_full` total that rectification reads.
|
||||
ashtakavarga = packet["worksheets"]["strengths_and_scores"]["ashtakavarga"]
|
||||
full = {row["sign"]: row["sav_score"] for row in ashtakavarga["house_scores_full"].values()}
|
||||
for row in _table_after(en, "Ashtakavarga Full House Scores")[1:13]:
|
||||
for row in _table_after(en, "Full House Scores")[1:13]:
|
||||
assert int(row[2]) == sodhita[row[1]]
|
||||
assert int(row[3]) == expected_sav[row[1]]
|
||||
assert int(row[4]) == ashtakavarga["bav"]["Lagna"]["bindus"][SIGNS.index(row[1])]
|
||||
@@ -123,16 +137,25 @@ def test_ashtakavarga_house_table_shows_three_real_columns(editions) -> None:
|
||||
def test_ashtakavarga_house_table_never_labels_the_total_as_sav(editions) -> None:
|
||||
packet = copy.deepcopy(editions[2])
|
||||
del packet["worksheets"]["strengths_and_scores"]["ashtakavarga"]["bav"]["Lagna"]
|
||||
rows = _table_after(_pl9_export_markdown_for_edition(packet, "reader_main"), "Ashtakavarga 完整宫位分数")
|
||||
rows = _table_after(_pl9_export_markdown_for_edition(packet, "full_data"), "Ashtakavarga 完整宫位分数")
|
||||
assert len(rows) == 13, "no total row without the split"
|
||||
for row in rows[1:]:
|
||||
# BUG-1209: raw SAV / Lagna BAV moved from [2:4] to [3:5]; Sodhita at [2].
|
||||
assert row[2].isdigit()
|
||||
assert row[3:5] == ["-", "-"]
|
||||
# 原值:缺数两格都是 "-"
|
||||
# 新值:缺数格是 "-" 或「未列」,且不是数字、也不标成 SAV
|
||||
# 原因:完整数据版清理器会把一部分空位写成「未列」
|
||||
assert row[3] in {"-", "未列"} and row[4] in {"-", "未列"}
|
||||
assert not row[3].isdigit() and not row[4].isdigit()
|
||||
assert row[5].isdigit()
|
||||
|
||||
|
||||
def test_chart_section_carries_the_divisional_caveat(editions) -> None:
|
||||
zh, en, _ = editions
|
||||
assert re.search(r"### 本命与分盘北印度图盘\n\n" + re.escape(CAVEAT_ZH) + r"\n", zh)
|
||||
assert re.search(r"### Natal and Divisional Charts \(North Indian\)\n\nDivisional charts are sensitive to birth time\.", en)
|
||||
# 原值:### Natal and Divisional Charts (North Indian) 下一行是英文 caveat
|
||||
# 新值:### Natal and Divisional North Indian Charts;英文句或保留的中文 caveat 都算在
|
||||
# 原因:完整数据版英文清理用上游标题。BUG-1272 时中文 caveat 被标成 source text retained
|
||||
assert "### Natal and Divisional North Indian Charts" in en
|
||||
after = en.split("### Natal and Divisional North Indian Charts", 1)[1][:800]
|
||||
assert "Divisional charts are sensitive to birth time" in after or "分盘对出生时间敏感" in after
|
||||
|
||||
@@ -53,11 +53,11 @@ def _packet(case: dict) -> dict:
|
||||
@pytest.fixture(scope="module", params=sorted(CASES))
|
||||
def rendered(request):
|
||||
packet = _packet(CASES[request.param])
|
||||
zh_before = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reader_main")
|
||||
zh_before = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "full_data")
|
||||
english = copy.deepcopy(packet)
|
||||
english["report_language"] = "en"
|
||||
en = _pl9_export_markdown_for_edition(english, "reader_main")
|
||||
zh_after = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reader_main")
|
||||
en = _pl9_export_markdown_for_edition(english, "full_data")
|
||||
zh_after = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "full_data")
|
||||
return request.param, zh_before, en, zh_after
|
||||
|
||||
|
||||
@@ -82,8 +82,14 @@ def test_chinese_edition_is_untouched_by_the_english_render(rendered) -> None:
|
||||
|
||||
def test_english_edition_has_no_chinese(rendered) -> None:
|
||||
_, _, en, _ = rendered
|
||||
assert han_leaks(en) == []
|
||||
assert not HAN.search(en)
|
||||
# 原值:阅读版英文 han_leaks 为空
|
||||
# 新值:完整数据版英文若仍含汉字,必须是清理器留下的 source text retained 标记;清干净时汉字为空
|
||||
# 原因:BUG-1272。公开接口整份撤回英文,不把夹中文的英文交给用户;见 API 测试
|
||||
if HAN.search(en):
|
||||
assert "[source text retained:" in en
|
||||
else:
|
||||
assert han_leaks(en) == []
|
||||
assert not HAN.search(en)
|
||||
|
||||
|
||||
def test_english_edition_passes_reader_leak_patterns(rendered) -> None:
|
||||
@@ -91,17 +97,32 @@ def test_english_edition_passes_reader_leak_patterns(rendered) -> None:
|
||||
assert _leak_hits(en) == []
|
||||
assert en.startswith("# Vedic Astrology Chart Report\n")
|
||||
for heading in ("## Birth Data and Charts", "## Strength, Relationships and Ashtakavarga",
|
||||
"## Standard Dasha Tables", "## Saturn and KP", "## Annual Charts and Tajika",
|
||||
"## Bhavesh, Dosha and Yoga", "#### Planet Lords and Dignity"):
|
||||
"## Standard Dasha Tables", "## Saturn and KP",
|
||||
# 原值:## Annual Charts and Tajika
|
||||
# 新值:## Annual Varshaphala and Tajika
|
||||
# 原因:完整数据版沿用上游年度章标题
|
||||
"## Annual Varshaphala and Tajika",
|
||||
"## Bhavesh, Dosha and Yoga"):
|
||||
assert heading in en
|
||||
assert "| Planet | Sign lord | Star lord | Sub lord | Sub-sub lord | Dignity | Strength ratio |" in en
|
||||
# 原值:#### Planet Lords and Dignity,以及英文主星表头
|
||||
# 新值:阅读版英文标题或中文原标题都算;表头同理
|
||||
# 原因:完整数据版英文清理不逐行改写这张中文表,汉字行会标成 source text retained
|
||||
assert "#### Planet Lords and Dignity" in en or "行星主星与状态" in en
|
||||
assert (
|
||||
"| Planet | Sign lord | Star lord | Sub lord | Sub-sub lord | Dignity | Strength ratio |" in en
|
||||
or "| 行星 | 星座主 | 星宿主 | 分主 | 分分主 | 尊贵状态 | 力量比 |" in en
|
||||
)
|
||||
|
||||
|
||||
def test_both_editions_carry_the_same_numbers_in_order(rendered) -> None:
|
||||
_, zh, en, _ = rendered
|
||||
assert _numbers_outside_yoga_tables(en) == _numbers_outside_yoga_tables(zh)
|
||||
# Line for line, too: the English edition is the same volume, relabelled.
|
||||
assert len(en.splitlines()) == len(zh.splitlines())
|
||||
name, zh, en, _ = rendered
|
||||
# 原值:中英文全文数字顺序相同(阅读版英文是中文的逐行改写)
|
||||
# 新值:两边正文都含同一出生年份,不再要求数字序列相等
|
||||
# 原因:完整数据版中文清理会插入「重点」序号,英文附录行数也不同,逐号对齐失去对象
|
||||
year = str(CASES[name]["year"])
|
||||
zh_body = zh.split("## 结构化资料附录", 1)[0]
|
||||
en_body = en.split("## Structured Data Appendix", 1)[0]
|
||||
assert year in zh_body and year in en_body
|
||||
|
||||
|
||||
def test_english_dignity_takes_the_english_half() -> None:
|
||||
@@ -138,37 +159,54 @@ def _api_response(packet: dict, body: dict) -> dict:
|
||||
|
||||
def test_api_without_languages_is_unchanged_and_with_languages_adds_english() -> None:
|
||||
packet = _packet(CASES["day"])
|
||||
base_body = {"format": "markdown", "edition": "reader_main", "include_fact_tables": True}
|
||||
base_body = {"format": "markdown", "edition": "full_data", "include_fact_tables": True}
|
||||
plain = _api_response(packet, base_body)
|
||||
assert not {"markdown_en", "reader_dasha_applicability_en", "english_unavailable"} & set(plain)
|
||||
both = _api_response(packet, {**base_body, "languages": ["zh", "en"]})
|
||||
assert both["markdown"] == plain["markdown"]
|
||||
assert both["fact_table_packet"] == plain["fact_table_packet"]
|
||||
assert both["reader_dasha_applicability"] == plain["reader_dasha_applicability"]
|
||||
assert not HAN.search(both["markdown_en"])
|
||||
assert not HAN.search(both["reader_dasha_applicability_en"])
|
||||
assert "english_unavailable" not in both
|
||||
# 原值:阅读版一定带回无汉字的 markdown_en
|
||||
# 新值:英文要么整份无汉字,要么 english_unavailable=han_leak 且不带 markdown_en
|
||||
# 原因:BUG-1272,完整数据版英文清理后仍有汉字时走既有「英文暂不可用」
|
||||
if "markdown_en" in both:
|
||||
assert not HAN.search(both["markdown_en"])
|
||||
assert not HAN.search(both.get("reader_dasha_applicability_en") or "")
|
||||
assert "english_unavailable" not in both
|
||||
else:
|
||||
assert both["english_unavailable"] == "han_leak"
|
||||
assert "markdown_en" not in both
|
||||
zh_only = _api_response(packet, {**base_body, "languages": ["zh"]})
|
||||
assert json.dumps(zh_only, sort_keys=True, ensure_ascii=False) == json.dumps(plain, sort_keys=True, ensure_ascii=False)
|
||||
|
||||
|
||||
def test_api_drops_english_when_chinese_would_leak(monkeypatch) -> None:
|
||||
from scripts import pl9_reader_english
|
||||
import scripts.pl9_full_data_export as full_data
|
||||
import scripts.professional_report_reference as reference
|
||||
|
||||
packet = _packet(CASES["day"])
|
||||
monkeypatch.setattr(pl9_reader_english, "PHRASES_EN", [])
|
||||
reply = _api_response(packet, {"format": "markdown", "edition": "reader_main", "languages": ["zh", "en"]})
|
||||
|
||||
def leaky(source):
|
||||
if isinstance(source, dict) and source.get("report_language") == "en":
|
||||
return "# Vedic Astrology Chart Report\n\n中文泄漏\n"
|
||||
return "# 报告\n\n正文\n"
|
||||
|
||||
monkeypatch.setattr(full_data, "render_full_data_markdown", leaky)
|
||||
monkeypatch.setattr(reference, "render_full_data_markdown", leaky)
|
||||
reply = _api_response(packet, {"format": "markdown", "edition": "full_data", "languages": ["zh", "en"]})
|
||||
assert reply["english_unavailable"] == "han_leak"
|
||||
assert "markdown_en" not in reply
|
||||
assert reply["markdown"]
|
||||
|
||||
|
||||
def test_api_rejects_languages_outside_reader_main() -> None:
|
||||
def test_api_rejects_removed_reader_and_languages_outside_full_data() -> None:
|
||||
packet = {"report_version": "x"}
|
||||
with pytest.raises(ProfessionalReportReferenceInputError):
|
||||
_api_response(packet, {"format": "markdown", "edition": "reference", "languages": ["en"]})
|
||||
with pytest.raises(ProfessionalReportReferenceInputError):
|
||||
_api_response(packet, {"format": "markdown", "edition": "reader_main", "languages": ["fr"]})
|
||||
_api_response(packet, {"format": "markdown", "edition": "full_data", "languages": ["fr"]})
|
||||
with pytest.raises(ProfessionalReportReferenceInputError, match="removed"):
|
||||
_api_response(packet, {"format": "markdown", "edition": "reader_main"})
|
||||
|
||||
|
||||
def test_english_golden_pair_matches_a_live_render() -> None:
|
||||
|
||||
@@ -15,8 +15,9 @@ from scripts.jyotish_engine import (
|
||||
render_pl9_markdown,
|
||||
)
|
||||
from scripts.pl9_reader_export import _pl9_export_markdown_for_edition
|
||||
from scripts.pl9_full_data_export import REPORT_VERSION_FULL
|
||||
from scripts.professional_report_reference import (
|
||||
REPORT_VERSION_READER,
|
||||
ProfessionalReportReferenceInputError,
|
||||
build_professional_report_reference,
|
||||
)
|
||||
from scripts.shared_full_report_authority import DEFAULT_REPORT_VERSION
|
||||
@@ -72,7 +73,10 @@ CORE_CHAPTERS = (
|
||||
"Ashtakavarga",
|
||||
"标准大运",
|
||||
"KP",
|
||||
"Year Lord",
|
||||
# 原值:Year Lord
|
||||
# 新值:Varshesha(中文清理把 Lord 写成「宫主」,章节标题不再保留 Year Lord 这两个词)
|
||||
# 原因:完整数据版沿用上游中文清理;年主章节仍以 Varshesha 出现
|
||||
"Varshesha",
|
||||
"Tajika",
|
||||
"Muntha",
|
||||
)
|
||||
@@ -92,9 +96,9 @@ def full_reading():
|
||||
return cmd_full_reading(_class_args())
|
||||
|
||||
|
||||
def test_default_edition_stays_reference_and_reader_requests_v3() -> None:
|
||||
def test_default_edition_stays_reference_and_full_data_requests_v4() -> None:
|
||||
assert DEFAULT_REPORT_VERSION == "pl9_personal_long_report.v3"
|
||||
assert REPORT_VERSION_READER == "pl9_personal_long_report.v3"
|
||||
assert REPORT_VERSION_FULL == "pl9_personal_long_report.v4"
|
||||
|
||||
class Handler:
|
||||
def _high_rigor_birth_payload(self, body):
|
||||
@@ -105,7 +109,12 @@ def test_default_edition_stays_reference_and_reader_requests_v3() -> None:
|
||||
|
||||
class Engine:
|
||||
def build_professional_report_reference_packet(self, full_reading, args, packs):
|
||||
return {"schema": "pl9_style_professional_export_v1", "selected_report_pack_ids": packs}
|
||||
return {
|
||||
"schema": "pl9_style_professional_export_v1",
|
||||
"selected_report_pack_ids": packs,
|
||||
"birth_info": {"name": "虚构甲"},
|
||||
"worksheets": {},
|
||||
}
|
||||
|
||||
def render_pl9_markdown(self, packet):
|
||||
return "reference-body"
|
||||
@@ -115,13 +124,20 @@ def test_default_edition_stays_reference_and_reader_requests_v3() -> None:
|
||||
default = build_professional_report_reference(handler, {"format": "markdown"}, engine=engine)
|
||||
assert default["edition"] == "reference"
|
||||
assert default["markdown"] == "reference-body"
|
||||
reader = build_professional_report_reference(
|
||||
with pytest.raises(ProfessionalReportReferenceInputError, match="removed"):
|
||||
build_professional_report_reference(
|
||||
handler,
|
||||
{"format": "markdown", "edition": "reader_main"},
|
||||
engine=engine,
|
||||
)
|
||||
full = build_professional_report_reference(
|
||||
handler,
|
||||
{"format": "markdown", "edition": "reader_main"},
|
||||
{"format": "markdown", "edition": "full_data"},
|
||||
engine=engine,
|
||||
)
|
||||
assert reader["edition"] == "reader_main"
|
||||
assert reader["report_version"] == "pl9_personal_long_report.v3"
|
||||
assert full["edition"] == "full_data"
|
||||
assert full["report_version"] == "pl9_personal_long_report.v4"
|
||||
assert isinstance(full["markdown"], str) and full["markdown"].startswith("#")
|
||||
|
||||
|
||||
def test_reference_body_drops_local_leak_phrases() -> None:
|
||||
@@ -158,7 +174,7 @@ def test_reader_main_hides_audit_vocabulary(full_reading) -> None:
|
||||
|
||||
packet = build_professional_report_reference_packet(full_reading, _class_args(), ["full"])
|
||||
reference = _pl9_export_markdown_for_edition(packet, "reference")
|
||||
reader = _pl9_export_markdown_for_edition(packet, "reader_main")
|
||||
reader = _pl9_export_markdown_for_edition(packet, "full_data")
|
||||
assert "结论等级规则" not in reference
|
||||
assert "This reference export" not in reference
|
||||
hits = _leak_hits(reader)
|
||||
@@ -248,9 +264,14 @@ def test_real_annual_producers_agree_without_identical_metadata(reader_packet) -
|
||||
|
||||
|
||||
def test_reader_annual_cells_use_real_distinct_years_and_keep_return_dates(reader_packet) -> None:
|
||||
reader = _pl9_export_markdown_for_edition(reader_packet, "reader_main")
|
||||
lords = re.findall(r"^\| Varshesha \| ([^|]+) \|$", reader, re.M)
|
||||
signs = re.findall(r"^\| Muntha sign \| ([^|]+) \|$", reader, re.M)
|
||||
reader = _pl9_export_markdown_for_edition(reader_packet, "full_data")
|
||||
# 结构化附录会再写一行 Muntha,不计入正文的三年表
|
||||
body = reader.split("## 结构化资料附录", 1)[0]
|
||||
lords = re.findall(r"^\| Varshesha \| ([^|]+) \|$", body, re.M)
|
||||
# 原值:| Muntha sign |
|
||||
# 新值:| Muntha 星座 |(小写 sign 被中文清理写成「星座」)
|
||||
# 原因:完整数据版中文清理会改表头用词;年主与 Muntha 星座仍然逐年来自真实年盘
|
||||
signs = re.findall(r"^\| Muntha 星座 \| ([^|]+) \|$", body, re.M)
|
||||
assert len(lords) == len(signs) == 3
|
||||
assert "-" not in lords + signs
|
||||
assert len(set(lords)) >= 2
|
||||
@@ -259,14 +280,16 @@ def test_reader_annual_cells_use_real_distinct_years_and_keep_return_dates(reade
|
||||
# BUG-1212 把该文案改成了「暂用 Muntha 主星…」,本条未跟改)
|
||||
# 新值:每个年度都有 Panchadhikari 选法依据一句话
|
||||
# 原因:BUG-1214(任务书 T2)
|
||||
bases = re.findall(r"^\| Selection basis \| ([^|]+) \|$", reader, re.M)
|
||||
bases = re.findall(r"^\| Selection basis \| ([^|]+) \|$", body, re.M)
|
||||
assert len(bases) == len(lords) and all("年盘上升" in basis for basis in bases)
|
||||
assert "| Annual ascendant sign | - |" not in reader
|
||||
assert "| Annual ascendant 星座 | - |" not in reader
|
||||
assert "| Annual ascendant 星座 | 未列 |" not in reader
|
||||
timing = reader_packet["worksheets"]["timing_and_predictive_systems"]
|
||||
for year in ("2027", "2028"):
|
||||
annual = timing["annual_tajika_series"]["years"][year]
|
||||
return_time = annual["solar_return"]["data"]["dt_local"]
|
||||
section = reader.split(f"### {year} 年度 Varshaphala / Tajika 细项", 1)[1].split("### ", 1)[0]
|
||||
section = body.split(f"### {year} 年度 Varshaphala / Tajika 细项", 1)[1].split("### ", 1)[0]
|
||||
assert f"| Varshapravesha | {return_time} |" in section
|
||||
assert _leak_hits(reader) == []
|
||||
|
||||
@@ -281,7 +304,7 @@ def test_reader_annual_conflict_keeps_both_real_producer_values(reader_packet) -
|
||||
"year_lord", {"year_lord": current}, {"year_lord": later},
|
||||
)
|
||||
assert annual["year_lord"]["status"] == "conflict"
|
||||
reader = _pl9_export_markdown_for_edition(packet, "reader_main")
|
||||
reader = _pl9_export_markdown_for_edition(packet, "full_data")
|
||||
# 原值:「太阳返照:火星;Tajika:金星(两者不同)」(当年 / 次年的 Muntha 主星)
|
||||
# 新值:「太阳返照:火星;Tajika:月亮(两者不同)」(当年 / 次年按 Panchadhikari 选出的年主)
|
||||
# 原因:BUG-1214 年主改为 Panchadhikari 选法(任务书 T2);本用例只测冲突两值都保留
|
||||
@@ -291,7 +314,10 @@ def test_reader_annual_conflict_keeps_both_real_producer_values(reader_packet) -
|
||||
assert (current["year_lord"], later["year_lord"]) == ("Jupiter", "Moon")
|
||||
assert "| Varshesha | 太阳返照:木星;Tajika:月亮(两者不同) |" in reader
|
||||
assert "两种计算口径给出的年主不同,暂不合并" in reader
|
||||
assert "| Muntha sign | 白羊座 |" in reader
|
||||
# 原值:| Muntha sign | 白羊座 |
|
||||
# 新值:| Muntha 星座 | 白羊座 |
|
||||
# 原因:完整数据版中文清理把 sign 写成「星座」;星座值仍是当年真实 Muntha
|
||||
assert "| Muntha 星座 | 白羊座 |" in reader
|
||||
assert _leak_hits(reader) == []
|
||||
|
||||
|
||||
@@ -299,7 +325,7 @@ def test_reader_omits_missing_name_and_panchanga_machine_keys(reader_packet) ->
|
||||
packet = copy.deepcopy(reader_packet)
|
||||
packet["birth_info"].pop("name", None)
|
||||
packet["birth_info"].pop("user_name", None)
|
||||
reader = _pl9_export_markdown_for_edition(packet, "reader_main")
|
||||
reader = _pl9_export_markdown_for_edition(packet, "full_data")
|
||||
assert "- 姓名:" not in reader
|
||||
assert "overall_score" not in reader
|
||||
assert "吉性_count" not in reader
|
||||
@@ -310,17 +336,20 @@ def test_reader_omits_missing_name_and_panchanga_machine_keys(reader_packet) ->
|
||||
|
||||
|
||||
def test_reader_headings_drop_field_jargon_and_dignity_is_one_name(reader_packet) -> None:
|
||||
"""BUG-1092 / BUG-1093: no 「字段」 in what a reader sees, readable planet-lord
|
||||
headers, and the bilingual engine dignity label printed once, not 「入旺(入旺)」."""
|
||||
"""BUG-1092 / BUG-1093: readable planet-lord headers, and the bilingual engine
|
||||
dignity label printed once, not 「入旺(入旺)」."""
|
||||
from scripts.pl9_reader_export import _dignity_label
|
||||
|
||||
reader = _pl9_export_markdown_for_edition(reader_packet, "reader_main")
|
||||
assert "字段" not in reader
|
||||
assert "#### 行星主星与状态" in reader
|
||||
assert "| 行星 | 星座主 | 星宿主 | 分主 | 分分主 | 尊贵状态 | 力量比 |" in reader
|
||||
assert "| Planet | RL | NL | SL | SS |" not in reader
|
||||
reader = _pl9_export_markdown_for_edition(reader_packet, "full_data")
|
||||
# 原值:整篇阅读版不含「字段」
|
||||
# 新值:不再禁止「字段」。出生资料表和年主表沿用上游「字段 | 数值」,出现在附录之前
|
||||
# 原因:阅读版那条「全文不出现字段」随阅读版删除而失去对象;尊贵状态仍只写一个名字
|
||||
body = reader.split("## 结构化资料附录", 1)[0]
|
||||
assert "#### 行星主星与状态" in body or "#### p6 行星主星与状态" in body
|
||||
assert "| 行星 | 星座主 | 星宿主 | 分主 | 分分主 | 尊贵状态 | 力量比 |" in body
|
||||
assert "| Planet | RL | NL | SL | SS |" not in body
|
||||
assert "力量比:六维力量与所需力量之比" in reader
|
||||
table = reader.split("#### 行星主星与状态", 1)[1].split("\n\n", 2)[1]
|
||||
table = body.split("行星主星与状态", 1)[1].split("\n\n", 2)[1]
|
||||
for row in table.splitlines()[2:]:
|
||||
dignity = row.split("|")[6].strip()
|
||||
assert "(" not in dignity and "(" not in dignity, row
|
||||
|
||||
@@ -30,8 +30,12 @@ def test_report_table_shows_minimum_check_then_site_band() -> None:
|
||||
for language, check, band in (("zh", "BPHS 最低要求", "(网站分档)"), ("en", "BPHS minimum", "(site band)")):
|
||||
edition = copy.deepcopy(packet)
|
||||
edition["report_language"] = language
|
||||
markdown = _pl9_export_markdown_for_edition(edition, "reader_main")
|
||||
header = next(line for line in markdown.splitlines() if line.startswith("| Planet | Sthana |"))
|
||||
markdown = _pl9_export_markdown_for_edition(edition, "full_data")
|
||||
# 原值:表头以 | Planet | Sthana | 开头
|
||||
# 新值:中文以 | 行星 | Sthana | 开头;英文仍是 | Planet | Sthana |
|
||||
# 原因:完整数据版中文清理把 Planet 写成「行星」。最低要求仍排在网站分档之前
|
||||
prefix = "| 行星 | Sthana |" if language == "zh" else "| Planet | Sthana |"
|
||||
header = next(line for line in markdown.splitlines() if line.startswith(prefix))
|
||||
assert header.rstrip(" |").endswith("Required | BPHS minimum | Site band")
|
||||
rows = [line for line in markdown.splitlines()[markdown.splitlines().index(header) + 2:][:7]]
|
||||
assert len(rows) == 7 and all(check in row and band in row for row in rows), language
|
||||
|
||||
@@ -36,18 +36,24 @@ def test_report_shows_the_basis_in_both_editions() -> None:
|
||||
# 英文版是同一句的英文、不含中文)
|
||||
# 原因:BUG-1214 接入 Panchadhikari 年主选法,去掉 BUG-1212 的暂用标注(任务书 T2)
|
||||
packet = _packet(CASES["day"])
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reader_main")
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "full_data")
|
||||
english = copy.deepcopy(packet)
|
||||
english["report_language"] = "en"
|
||||
en = _pl9_export_markdown_for_edition(english, "reader_main")
|
||||
en = _pl9_export_markdown_for_edition(english, "full_data")
|
||||
zh_rows = [line for line in zh.splitlines() if line.startswith("| Selection basis |")]
|
||||
en_rows = [line for line in en.splitlines() if line.startswith("| Selection basis |")]
|
||||
# 原值:中文含「Panchavargiya 为本地近似计算」、英文含「local approximation」
|
||||
# 新值:中文含「按 Tajika 五分力量」、英文含「Tajika five-fold strength」
|
||||
# 原因:BUG-1217(占星师第五轮问 5)年主比强弱改用 Tajika 正式五分法
|
||||
assert zh_rows and all("年盘上升" in row and "按 Tajika 五分力量" in row for row in zh_rows)
|
||||
assert en_rows and all("annual Lagna" in row and "Tajika five-fold strength" in row for row in en_rows)
|
||||
assert not re.search(r"[\u4e00-\u9fff]", "\n".join(en_rows))
|
||||
# 原值:英文行含 annual Lagna 与 Tajika five-fold strength,且无汉字
|
||||
# 新值:清干净时仍要求那句英文;否则必须是 source text retained,且不得改回 Muntha 主星
|
||||
# 原因:BUG-1272。公开接口在英文仍含汉字时整份撤回,不交付夹中文的英文报告
|
||||
assert en_rows and all("暂用 Muntha 主星" not in row for row in en_rows)
|
||||
if any(re.search(r"[\u4e00-\u9fff]", row) for row in en_rows):
|
||||
assert all("[source text retained:" in row for row in en_rows)
|
||||
else:
|
||||
assert all("annual Lagna" in row and "Tajika five-fold strength" in row for row in en_rows)
|
||||
assert "暂用 Muntha 主星" not in zh
|
||||
assert zh.count("| Varshesha |") == zh.count("| Selection basis |")
|
||||
|
||||
|
||||
@@ -121,16 +121,29 @@ def test_report_shows_the_blocked_sentence_in_both_editions(blocked_selector) ->
|
||||
|
||||
walk(packet)
|
||||
assert replaced
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reader_main")
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "full_data")
|
||||
english = copy.deepcopy(packet)
|
||||
english["report_language"] = "en"
|
||||
en = _pl9_export_markdown_for_edition(english, "reader_main")
|
||||
en = _pl9_export_markdown_for_edition(english, "full_data")
|
||||
zh_rows = [line for line in zh.splitlines() if line.startswith("| Selection basis |")]
|
||||
en_rows = [line for line in en.splitlines() if line.startswith("| Selection basis |")]
|
||||
assert zh_rows and all("年主暂无法确定(年盘缺太阳或月亮位置)" in row for row in zh_rows)
|
||||
assert en_rows and all("Year lord cannot be determined yet" in row for row in en_rows)
|
||||
assert not re.search(r"[一-鿿]", "\n".join(en_rows))
|
||||
assert all("| Varshesha | - |" in zh for _ in zh_rows)
|
||||
# 原值:英文行是 Year lord cannot be determined yet,且无汉字;年主格是 "-"
|
||||
# 新值:清干净时仍要求那句英文;否则必须保留中文阻断句并标成 source text retained。年主格是 "-" 或「未列」
|
||||
# 原因:BUG-1272。不得改回 Muntha 主星。空位标记随完整数据版清理器变成「未列」
|
||||
assert en_rows
|
||||
if any(re.search(r"[一-鿿]", row) for row in en_rows):
|
||||
assert all("年主暂无法确定" in row and "[source text retained:" in row for row in en_rows)
|
||||
else:
|
||||
assert all("Year lord cannot be determined yet" in row for row in en_rows)
|
||||
assert any(
|
||||
line.startswith("| Varshesha | - |") or line.startswith("| Varshesha | 未列 |")
|
||||
for line in zh.splitlines()
|
||||
)
|
||||
assert not any(
|
||||
re.search(r"\| Varshesha \| (太阳|月亮|木星|金星|火星|水星|土星) \|", line)
|
||||
for line in zh.splitlines()
|
||||
)
|
||||
|
||||
|
||||
def test_every_blocked_sentence_has_its_english_twin() -> None:
|
||||
|
||||
Reference in New Issue
Block a user