Files
Jyotisha/tests/test_report_full_data_fix.py
T
jesse-uxandJesse_Chen 25d067bf12 fix(report): fill the full-data edition and clear English Han
Add the interpretation pages from fields the engine already computed, project the annual tables the reader prints, and clear English Han on the four measured charts. Patyayini is not implemented. The generate button copy is unchanged.

This commit stays on the feature branch and is not pushed to staging.
2026-10-08 22:29:41 +08:00

219 lines
8.4 KiB
Python

"""Report completion for the full-data edition (TASK-report-full-data-fix-20261008).
Template wording, annual field projection, the opening focus, and the two
mistranslations. Chart numbers come from the packet. These tests do not
calculate a new dasha or import PyJHora.
"""
from __future__ import annotations
import copy
import re
from scripts.pl9_full_data_export import _sanitize_pl9_ai_density_markdown, render_full_data_markdown
from scripts.pl9_interpretation_packs import (
attach_full_data_interpretation,
missing_field_count,
opening_focus_block,
section_coverage,
)
from scripts.pl9_reader_english import HAN
FORBIDDEN_ZH = (
"再婚",
"几段关系",
"早夭",
"一定会",
"必然",
"Neecha Bhanga Raja Yoga",
"落陷取消王",
"疾病诊断",
"疾病",
)
FORBIDDEN_EN = (
"divorce",
"miscarriage",
"infertility",
"guarantee",
"guaranteed",
)
HALF_TRANSLATED = re.compile(r"[A-Za-z]+\s*[\u4e00-\u9fff]+s")
def _planet(sign: str, house: int, nakshatra: str, status: str = "Own Sign") -> dict:
return {"sign": sign, "house": house, "status": status, "nakshatra": nakshatra}
def _packet(language: str = "zh") -> dict:
planets = {
"Sun": _planet("Aries", 10, "Ashwini", "入旺(Exalted)"),
"Moon": _planet("Taurus", 2, "Rohini"),
"Mars": _planet("Capricorn", 7, "Exalted"),
"Mercury": _planet("Pisces", 6, "Debilitated"),
"Jupiter": _planet("Cancer", 1, "Exalted"),
"Venus": _planet("Libra", 4, "Own Sign"),
"Saturn": _planet("Aquarius", 8, "Own Sign"),
"Rahu": _planet("Gemini", 12, "Ardra", ""),
"Ketu": _planet("Sagittarius", 6, "Mula", ""),
}
lords = ["Mars", "Venus", "Mercury", "Moon", "Sun", "Mercury", "Venus", "Mars", "Jupiter", "Saturn", "Saturn", "Jupiter"]
houses = {f"house_{index}": {"lord": lord, "cusp_sign": "Aries"} for index, lord in enumerate(lords, start=1)}
timeline = []
for lord in ("Sun", "Moon", "Mars"):
current = lord == "Moon"
timeline.append({
"lord": lord,
"start": "2000-01-01",
"end": "2006-01-01",
"is_current": current,
"antardasha_timeline": [{
"lord": "Mars",
"start": "2001-01-01",
"end": "2002-01-01",
"is_current": current,
"pratyantar_dasha_timeline": [{
"lord": "Mercury",
"start": "2001-02-01",
"end": "2001-04-01",
"is_current": current,
}],
}],
})
return {
"report_language": language,
"birth_info": {"name": "虚构甲" if language == "zh" else "Fictional"},
"worksheets": {
"d1_rasi_bhava": {"planets": planets, "houses": houses, "ascendant": {"sign": "Cancer"}},
"strengths_and_scores": {
"functional_benefic_malefic": {
"functional_benefics": ["Jupiter", "Mars"],
"functional_malefics": ["Saturn"],
"functional_neutrals": ["Moon"],
},
"shadbala": {"planets": {"Sun": {"total": 1.25}}},
},
"timing_and_predictive_systems": {
"dasha": {"timeline": timeline, "current_dasha": timeline[1]},
"annual_tajika_pack": {
"solar_return": {"status": "partial_verified", "data": {"dt_local": "2026-04-07T09:00:00"}},
"mudda_dasha": {
"status": "partial_verified",
"periods": [{"lord": "Sun", "start": "2026-04-07", "end": "2026-05-07", "months": 1}],
},
"patyayini_dasha": {"status": "blocked", "reason": "not_in_engine"},
"sahams": {"status": "partial_verified", "data": [{"name": "Punya", "sign": "Aries", "degree_in_sign": 1.2}]},
"tajika_yogas": {
"status": "partial_verified",
"data": {"yogas": [{"name": "Ithasala", "present": True, "planets": ["Sun", "Moon"]}]},
},
"monthly_windows": [{
"index": 1,
"lord": "Sun",
"duration_months": 1,
"start": "2026-04-07",
"end": "2026-05-07",
}],
},
},
"advanced_systems": {
"yoga": {
"detected_yogas": [{
"name": "Gajakesari Yoga",
"name_cn": "象鹿瑜伽",
"category": "raja",
"effects": ["名声可见"],
"effects_en": ["visible reputation"],
"planets": ["Moon", "Jupiter"],
"combination": "Moon and Jupiter",
}, {
"name": "Neecha Bhanga Raja Yoga",
"name_cn": "落陷取消王瑜伽",
"category": "neecha_bhanga",
"effects": ["传统条件成立"],
"effects_en": ["the cancellation conditions hold"],
"planets": ["Mercury"],
}],
},
"yogas_doshas": {"mangal_dosha": {"has_dosha": False, "mars_house": 7, "severity": "none"}},
},
},
}
def test_t5_repairs_bhava_bala_and_planets_suffix() -> None:
raw = "\n".join([
"# 印度占星星盘报告",
"",
"### p31-p33 Shadbala / Bhava Bala 摘要",
"",
"### p32 Bhava Bala 十二宫力量",
"",
"### p125 Natal / KP Ruling Planets",
"",
"### Upagraha and Sub-Planets Points",
"",
"### Planetary Friendship Matrix",
"",
])
text = _sanitize_pl9_ai_density_markdown(raw)
assert "Bhava 年龄状态" not in text
assert "六维力量 / Bhava Bala" in text
assert "Bhava Bala 十二宫力量" in text
assert "行星s" not in text
assert "本命 / KP 征象星" in text
assert HALF_TRANSLATED.search(text) is None
assert "年龄状态" not in text.split("Graha Avastha", 1)[-1] or "Baladi" not in raw
def test_templates_cover_required_sections_and_forbidden_wording() -> None:
packet = _packet("zh")
attach_full_data_interpretation(packet)
focus = opening_focus_block(packet)
assert focus.startswith("重点:")
assert "MD" in focus and "AD" in focus and "PD" in focus
assert "第10宫" in focus and "第2宫" in focus and "第7宫" in focus
text = render_full_data_markdown(packet)
for heading in ("大运解释", "行星、星宿与宫位解释", "宫主逐宫解释", "Dosha 逐项事实与解释", "瑜伽解释"):
assert heading in text
assert "Patyayini 没有实现" in text
assert "Mudda 月段窗口" in text
assert "blocked" not in text.lower()
for phrase in FORBIDDEN_ZH:
assert phrase not in text
assert "落陷取消(Neecha Bhanga" in text
assert "Raja Yoga" not in text
assert HALF_TRANSLATED.search(text) is None
assert "行星s" not in text
coverage = {row["section"]: row["status"] for row in section_coverage(packet)}
assert coverage["sthira"] == "out_of_scope"
assert "Sthira Dasha" not in text
assert missing_field_count(packet) <= 10
def test_english_focus_and_new_sections_have_no_han() -> None:
packet = _packet("en")
text = render_full_data_markdown(packet)
assert "Focus: current Maha Dasha MD" in text
assert "AD" in text and "PD" in text
assert "Dasha Interpretation" in text
assert "House-lord interpretation" in text
assert "Yoga interpretation" in text
assert "Patyayini is not implemented" in text
assert "Monthly mudda windows" in text
for phrase in FORBIDDEN_EN:
assert phrase not in text.lower()
assert "Neecha Bhanga Raja Yoga" not in text
assert "not a Raja Yoga" in text
leaked = HAN.findall(text)
assert leaked == [], leaked[:12]
def test_chinese_render_stays_stable_when_english_uses_a_copy() -> None:
packet = _packet("zh")
before = render_full_data_markdown(copy.deepcopy(packet))
english = copy.deepcopy(packet)
english["report_language"] = "en"
render_full_data_markdown(english)
after = render_full_data_markdown(copy.deepcopy(packet))
assert after == before