153 lines
6.7 KiB
Python
153 lines
6.7 KiB
Python
"""T6: whole-sign annual houses, Tripataki, and Saham traces use our longitudes."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from datetime import datetime
|
|
|
|
from scripts.annual_native.annual_houses import build_annual_whole_sign_houses
|
|
from scripts.annual_native.monthly_charts import build_monthly_charts
|
|
from scripts.annual_native.tripataki_chakra import build_tripataki_chakra
|
|
from scripts.jyotish_engine import compute_chart_data
|
|
from scripts.report_render.parity_chapters import render_parity_chapters
|
|
from scripts.tajika import calc_all_sahams
|
|
from tests.report_english_fictional import fictional_case
|
|
|
|
LIMIT = 1e-6
|
|
|
|
|
|
def _delta(left: float, right: float) -> float:
|
|
return abs(((left - right + 180.0) % 360.0) - 180.0)
|
|
|
|
|
|
def _chart():
|
|
birth = fictional_case(0)
|
|
chart, *_rest = compute_chart_data(
|
|
birth["year"], birth["month"], birth["day"], birth["hour"], birth["minute"],
|
|
birth["lat"], birth["lon"], birth["tz"],
|
|
node_mode=birth["node_mode"], second=birth["second"], ayanamsa_name=birth["ayanamsa"],
|
|
)
|
|
return birth, chart
|
|
|
|
|
|
def test_new_longitudes_match_the_chart() -> None:
|
|
_birth, chart = _chart()
|
|
houses = build_annual_whole_sign_houses(chart)
|
|
assert houses["status"] == "partial_verified"
|
|
assert houses["house_system"] == "whole_sign"
|
|
assert len(houses["houses"]) == 12
|
|
raw = {
|
|
name: float(chart["planets"][name]["degree_raw"]) % 360.0
|
|
for name in ("Sun", "Moon")
|
|
}
|
|
for name, longitude in raw.items():
|
|
assert _delta(houses["source_longitudes"][name], longitude) <= LIMIT
|
|
asc = float(chart["ascendant"]["degree_raw"])
|
|
tripataki = build_tripataki_chakra(
|
|
{name: data["degree_raw"] for name, data in chart["planets"].items() if isinstance(data, dict) and "degree_raw" in data},
|
|
asc,
|
|
)
|
|
assert tripataki["status"] == "partial_verified"
|
|
for name, longitude in raw.items():
|
|
assert _delta(tripataki["source_longitudes"][name], longitude) <= LIMIT
|
|
sun = next(row for row in tripataki["placements"] if row["body"] == "Sun")
|
|
assert _delta(sun["longitude"], raw["Sun"]) <= LIMIT
|
|
|
|
|
|
def test_monthly_row_sun_matches_the_chart_function() -> None:
|
|
import swisseph as swe
|
|
from scripts.annual_native.sidereal_bodies import sun_moon_longitudes
|
|
|
|
birth, chart = _chart()
|
|
hour = birth["hour"] + birth["minute"] / 60.0
|
|
jd = swe.julday(birth["year"], birth["month"], birth["day"], hour - birth["tz"])
|
|
sun, moon = sun_moon_longitudes(jd, node_mode=birth["node_mode"], ayanamsa_name=birth["ayanamsa"])
|
|
assert _delta(sun, float(chart["planets"]["Sun"]["degree_raw"])) <= LIMIT
|
|
assert _delta(moon, float(chart["planets"]["Moon"]["degree_raw"])) <= LIMIT
|
|
monthly = build_monthly_charts(
|
|
annual_jd=jd,
|
|
birth_sun_longitude=sun,
|
|
latitude=birth["lat"],
|
|
longitude=birth["lon"],
|
|
tz_hours=birth["tz"],
|
|
ayanamsa=birth["ayanamsa"],
|
|
node_mode=birth["node_mode"],
|
|
target_year=birth["year"],
|
|
)
|
|
assert len(monthly["rows"]) == 12
|
|
first = monthly["rows"][0]
|
|
assert first["status"] == "partial_verified"
|
|
again, *_rest = compute_chart_data(
|
|
int(first["utc_datetime"][0:4]), int(first["utc_datetime"][5:7]), int(first["utc_datetime"][8:10]),
|
|
int(first["utc_datetime"][11:13]), int(first["utc_datetime"][14:16]),
|
|
birth["lat"], birth["lon"], 0,
|
|
node_mode=birth["node_mode"], second=int(first["utc_datetime"][17:19]),
|
|
ayanamsa_name=birth["ayanamsa"],
|
|
)
|
|
assert _delta(float(first["planet_longitudes"]["Sun"]), float(again["planets"]["Sun"]["degree_raw"])) <= LIMIT
|
|
assert _delta(float(first["planet_longitudes"]["Moon"]), float(again["planets"]["Moon"]["degree_raw"])) <= LIMIT
|
|
|
|
|
|
def test_saham_traces_keep_the_stored_longitude() -> None:
|
|
birth, chart = _chart()
|
|
asc = chart["ascendant"]
|
|
asc_lon = float(asc.get("lon") if isinstance(asc.get("lon"), (int, float)) else asc["degree_raw"])
|
|
planet_lons = {
|
|
name: float(data.get("degree", data["degree_raw"]))
|
|
for name, data in chart["planets"].items()
|
|
if isinstance(data, dict) and "degree" in data
|
|
}
|
|
result = calc_all_sahams(
|
|
planet_lons,
|
|
asc_lon,
|
|
datetime(birth["year"], birth["month"], birth["day"], birth["hour"], birth["minute"]),
|
|
lat=birth["lat"],
|
|
lon=birth["lon"],
|
|
tz=birth["tz"],
|
|
)
|
|
assert result.get("status") != "blocked"
|
|
traces = result["formula_traces"]
|
|
assert len(traces) >= 30
|
|
for trace in traces:
|
|
assert trace["longitude"] == result[trace["key"]]["longitude"]
|
|
without = {key: value for key, value in result.items() if key != "formula_traces"}
|
|
assert len(json.dumps(without, ensure_ascii=False, default=str)) > 800
|
|
is_day = result["daynight_evidence"]["is_daytime"]
|
|
karya = next(item for item in traces if item["key"] == "karya_saham")
|
|
first, second = (("Moon", "Mars") if is_day else ("Mars", "Moon"))
|
|
expected = round((asc_lon + planet_lons[second] - planet_lons[first]) % 360.0, 4)
|
|
assert karya["longitude"] == expected
|
|
assert karya["rule"] == f"Asc + {second} - {first}"
|
|
|
|
|
|
def test_four_sections_render_in_both_languages() -> None:
|
|
packet = {
|
|
"worksheets": {
|
|
"advanced_systems": {"sahams": {"formula_traces": [
|
|
{"name": "Punya Saham", "key": "punya_saham", "rule": "Asc + Moon - Sun", "phase": "day", "longitude": 12.5},
|
|
]}},
|
|
"timing_and_predictive_systems": {"annual_tajika_pack": {
|
|
"annual_houses": {"houses": [
|
|
{"house": 1, "sign": "Aries", "lord": "Mars", "occupants": []},
|
|
]},
|
|
"tripataki_chakra": {
|
|
"placements": [{"body": "Sun", "sign": "Leo", "degree_in_sign": 1.25, "longitude": 121.25}],
|
|
"vedha_rows": [{"target": "Sun", "available_sources": ["Moon"], "status": "partial_verified"}],
|
|
},
|
|
"sahams": {"data": {"formula_traces": [
|
|
{"name": "Vivah Saham", "key": "vivah_saham", "rule": "Asc + Venus - Mars", "phase": "night", "longitude": 40.0},
|
|
]}},
|
|
}},
|
|
}
|
|
}
|
|
chinese = render_parity_chapters(packet, "zh")
|
|
english = render_parity_chapters(packet, "en")
|
|
assert "年运整宫框架" in chinese and "无" in chinese
|
|
assert "Annual Return House Framework" in english and "None" in english
|
|
assert "Tripataki 轮盘明细" in chinese and "Tripataki Chakra Detail" in english
|
|
assert "年度特殊点公式轨迹" in chinese and "夜间" in chinese
|
|
assert "Annual Saham Formula Trace" in english and "Night" in english
|
|
assert "本命特殊点公式轨迹" in chinese and "日间" in chinese
|
|
assert "Natal Saham Formula Trace" in english and "Day" in english
|
|
assert "blocked" not in chinese.lower()
|