研究章在渲染时计算,不写入资料包。四种星座大运次小运和 Kalachakra 第三层不改原来的主运、子运。D81、D108、D144 只留在研究章。 自测:test_research_timing、星座大运、域读取、卫生预算、真恒星、jhora 扫描、API 增长、六章标题、英文版。三张虚构盘中英出稿都低于 180 秒。PyJHora 已导入但未做逐层对照。 Co-Authored-By: Grok (agent loop)
80 lines
2.6 KiB
Python
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)
|