Files
Jyotisha/scripts/research_timing/rashi_pd.py
T
jesse-uxandGrok (agent loop) d45e65a9ec 完整数据版补上研究口径的推运、次小运和细分盘(#92)。
研究章在渲染时计算,不写入资料包。四种星座大运次小运和 Kalachakra 第三层不改原来的主运、子运。D81、D108、D144 只留在研究章。

自测:test_research_timing、星座大运、域读取、卫生预算、真恒星、jhora 扫描、API 增长、六章标题、英文版。三张虚构盘中英出稿都低于 180 秒。PyJHora 已导入但未做逐层对照。

Co-Authored-By: Grok (agent loop)
2026-10-23 18:20:44 +08:00

80 lines
2.6 KiB
Python

"""Third-level rows for four rashi dashas, on a copy only.
The producer stays free of this key. Printed pages name the sub-period
and not the third level. The split used here is the direct equal-time
rule in the upstream calendar helper: the first child keeps the
sub-period sign, the rest run forward, and the last child ends on the
sub-period end. An empty sub-period list, including a Drig strength tie,
gets no third level.
"""
from __future__ import annotations
from copy import deepcopy
from datetime import datetime
try:
from rashi_dashas_native import SIGNS
except ImportError: # pragma: no cover - package import
from scripts.rashi_dashas_native import SIGNS
FAMILIES = ("sthira", "drig", "shoola", "navamsha")
def attach_rashi_pratyantar(calculated: dict) -> dict:
"""Return a deep copy with third-level rows. The input is not changed."""
copied = deepcopy(calculated)
for name in FAMILIES:
section = copied.get(name)
if not isinstance(section, dict):
continue
for major in section.get("periods") or []:
if not isinstance(major, dict):
continue
children = major.get("antardasha")
if not isinstance(children, list) or not children:
continue
for child in children:
if not isinstance(child, dict):
continue
third = _equal_forward(child)
if third:
child["pratyantar"] = third
return copied
def _equal_forward(child: dict) -> list[dict]:
sign = child.get("sign_index")
if not isinstance(sign, int):
label = child.get("sign")
if label not in SIGNS:
return []
sign = SIGNS.index(label)
try:
start = datetime.fromisoformat(str(child["start"]))
end = datetime.fromisoformat(str(child["end"]))
except (KeyError, TypeError, ValueError):
return []
total = (end - start).total_seconds()
if total <= 0:
return []
rows = []
for offset in range(12):
moment = end if offset == 11 else start + _seconds(total * (offset + 1) / 12.0)
opened = start if offset == 0 else start + _seconds(total * offset / 12.0)
index = (int(sign) + offset) % 12
rows.append({
"sign": SIGNS[index],
"sign_index": index,
"start": opened.date().isoformat(),
"end": moment.date().isoformat(),
"level": "PD",
})
rows[-1]["end"] = end.date().isoformat()
return rows
def _seconds(value: float):
from datetime import timedelta
return timedelta(seconds=value)