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)
112 lines
5.5 KiB
Python
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})
|