Files
Jyotisha/tests/test_upstream_sync9_kalachakra_source_lords.py
T
jesse-uxandGrok (agent loop) 96312893b7 fix(kalachakra): classical sign periods when the Moon longitude is present (BUG-1476, upstream f353a096)
Without a Moon longitude the simplified table remains. Exact pada starts use a local boundary table because shared find_nakshatra misclassifies 50 of 108 starts. Two existing child-period assertions now expect antardasha; original, new value, and reason are in the test comments. 116 source tests passed.

Co-Authored-By: Grok (agent loop)
2026-10-28 09:45:08 +08:00

112 lines
5.5 KiB
Python

"""Published examples check semantics, not merely child-table presence."""
from datetime import datetime
import pytest
from scripts.kalachakra_dasha import calculate_kalachakra_dasha
@pytest.mark.parametrize('quarter', range(108))
def test_exact_quarter_start_has_full_first_major_balance(quarter):
from scripts.kalachakra_dasha import _fraction_completed_in_pada
longitude = quarter * 10 / 3
assert _fraction_completed_in_pada(longitude, quarter // 4, quarter % 4 + 1) == 0
packet = calculate_kalachakra_dasha({
'moon_longitude': longitude, 'birth_datetime': datetime(2000, 1, 1),
'as_of': '2000-01-01',
})
first = packet['major'][0]
assert first['years'] > 0
assert first['start_date'] < first['end_date']
assert packet['variant_trace']['pada_index'] == quarter % 4
assert packet['variant_trace']['completed_paramayush_years'] == 0
@pytest.mark.parametrize("longitude,nakshatra,pada,first_sign,balance", [
(45 + 50 / 60, 3, 2, "Scorpio", 4.75), # PVR example 95
(93.0, 6, 4, "Pisces", 8.6), # PVR example 96
])
def test_published_birth_balances_and_sign_owners(longitude, nakshatra, pada,
first_sign, balance):
result = calculate_kalachakra_dasha({
"moon_longitude": longitude, "moon_nakshatra_index": nakshatra,
"moon_pada": pada, "birth_datetime": datetime(2000, 1, 1),
})
owners = dict(zip(
"Aries Taurus Gemini Cancer Leo Virgo Libra Scorpio Sagittarius Capricorn Aquarius Pisces".split(),
"Mars Venus Mercury Moon Sun Mercury Venus Mars Jupiter Saturn Saturn Jupiter".split(),
))
assert result["starting_rashi"] == first_sign
assert result["major"][0]["years"] == pytest.approx(balance)
assert result["starting_lord"] == owners[first_sign]
if first_sign == 'Pisces':
assert [result['dasha_balance_at_birth'][key] for key in
('years_whole','months_whole','days_whole')] == [8,7,6]
for row in result["major"] + result["antardasha"] + result["pratyantardasha"]:
assert row["lord"] == owners[row["rashi"]]
def test_example_97_child_sequence_and_prebirth_clipping():
result = calculate_kalachakra_dasha({
'moon_longitude': 45 + 50 / 60, 'moon_nakshatra_index': 3,
'moon_pada': 2, 'birth_datetime': datetime(2000, 1, 1),
})
# Example 95 has already consumed 2.25 of the 7 Scorpio years.
# Sc=.49, Li=1.12, Vi=.63 total 2.24; Leo is active at birth.
first = result['major'][0]['antardasha'][0]
assert first['rashi'] == 'Leo'
assert first['years'] == pytest.approx(.34)
assert first['start_date'] == '2000-01-01T00:00:00'
leo = result['major'][3]
assert leo['rashi'] == 'Leo'
assert [row['rashi'] for row in leo['antardasha']] == [
'Leo', 'Cancer', 'Gemini', 'Taurus', 'Aries', 'Sagittarius',
'Capricorn', 'Aquarius', 'Pisces',
]
assert leo['antardasha'][0]['years'] == pytest.approx(5 * 5 / 86)
for parent in result['major'] + result['antardasha']:
children = parent.get('antardasha', parent.get('pratyantardasha'))
assert children[0]['start_date'] == parent['start_date']
assert children[-1]['end_date'] == parent['end_date']
assert sum(row['years'] for row in children) == pytest.approx(parent['years'])
for left, right in zip(children, children[1:]):
assert left['end_date'] == right['start_date']
assert all(row['start_date'] < row['end_date'] for row in children)
def test_current_period_uses_exact_half_open_boundaries_without_repetition():
birth = {'moon_longitude': 45 + 50 / 60, 'moon_nakshatra_index': 3,
'moon_pada': 2, 'birth_datetime': datetime(2000, 1, 1, 12, 34, 56)}
initial = calculate_kalachakra_dasha(birth)
boundary = initial['major'][0]['end_date']
current = calculate_kalachakra_dasha({**birth, 'as_of': boundary})['current']
assert current['rashi'] == 'Libra'
assert current['start_date'] == boundary
assert current['end_date'] == initial['major'][1]['end_date']
assert current['elapsed_years'] == 0
assert calculate_kalachakra_dasha({**birth, 'as_of': '1999-01-01'})['current'] is None
assert calculate_kalachakra_dasha({**birth, 'as_of': initial['major'][-1]['end_date']})['current'] is None
@pytest.mark.parametrize('year_days',[360,365.25,365.256364])
def test_selected_year_applies_at_every_depth(year_days):
birth = {'moon_longitude':93.,'moon_nakshatra_index':6,'moon_pada':4,
'birth_datetime':datetime(2000,1,1),'dasha_year_days':year_days}
result = calculate_kalachakra_dasha(birth)
assert result['dasha_year_days'] == year_days
for row in result['major'] + result['antardasha'] + result['pratyantardasha']:
span = datetime.fromisoformat(row['end_date']) - datetime.fromisoformat(row['start_date'])
assert span.total_seconds() == pytest.approx(row['years']*year_days*86400,abs=.00002)
def test_actual_longitude_controls_seed_and_nonfinite_inputs_do_not_fallback():
birth = {'moon_longitude':93.,'moon_nakshatra_index':0,'moon_pada':1,
'birth_datetime':datetime(2000,1,1)}
result = calculate_kalachakra_dasha(birth)
assert result['starting_rashi'] == 'Pisces'
assert result['major'][0]['years'] == pytest.approx(8.6)
for key,value in [('moon_longitude',float('nan')),('dasha_year_days',0),
('dasha_year_days',float('inf'))]:
with pytest.raises(ValueError):
calculate_kalachakra_dasha({**birth,key:value})