fix(bhava): use the named mirrored equal-house strength profile
Upstream a4d4a249. Dig tables, Capricorn's first half, the sputa formula, and the benefic set now match jyotishganit_mirrored_equal_house_v2. Mercury is neutral. The result names that profile and does not call it a classical ruling. BUG-1385. Co-Authored-By: Grok (agent loop) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Grok (agent loop)
Cursor
parent
e8a7f3ac22
commit
6cbae4ce23
@@ -0,0 +1,71 @@
|
||||
"""Replay the vendored pure formula functions, not a second handwritten oracle.
|
||||
|
||||
AST isolation avoids importing the vendor's unrelated Skyfield/network stack.
|
||||
This establishes bounded formula parity, not full-engine or classical authority.
|
||||
"""
|
||||
import ast
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from scripts import bhava_bala as local
|
||||
|
||||
VENDOR=Path(__file__).resolve().parents[1]/'references/open_source_sources/jyotishganit/jyotishganit'
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def vendor(monkeypatch):
|
||||
name='jyotishganit.core.constants'
|
||||
spec=importlib.util.spec_from_file_location(name,VENDOR/'core/constants.py')
|
||||
constants=importlib.util.module_from_spec(spec);spec.loader.exec_module(constants)
|
||||
monkeypatch.setitem(sys.modules,name,constants)
|
||||
names={'normalize','planet_longitude_from_sign','get_sputa_drishti_degree',
|
||||
'_calculate_general_sputa','_calculate_planet_sputa',
|
||||
'compute_bhava_adhipathi_bala','compute_bhava_dig_bala','compute_bhava_drik_bala',
|
||||
'get_angular_distance_between_planets_and_house'}
|
||||
path=VENDOR/'components/strengths.py'
|
||||
parsed=ast.parse(path.read_text())
|
||||
functions=[node for node in parsed.body if isinstance(node,ast.FunctionDef) and node.name in names]
|
||||
assert {f.name for f in functions}==names
|
||||
module=ast.Module(body=[ast.ImportFrom(module='__future__',names=[ast.alias(name='annotations')],level=0),*functions],type_ignores=[])
|
||||
namespace=dict(vars(constants))
|
||||
exec(compile(ast.fix_missing_locations(module),str(path),'exec'),namespace)
|
||||
return SimpleNamespace(**namespace)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('planet',['Sun','Moon','Mars','Mercury','Jupiter','Venus','Saturn'])
|
||||
def test_aspect_boundaries_against_vendor(vendor,planet):
|
||||
angles=[-360,-210,0,1,15,29.99999,30,45,59.99999,60,75,89.99999,90,
|
||||
105,119.99999,120,135,149.99999,150,165,179.99999,180,210,240,270,300,359.99999,360]
|
||||
for angle in angles:
|
||||
assert local._get_sputa_drishti(angle,planet)==pytest.approx(vendor.get_sputa_drishti_degree(angle,planet))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('degree',[0.0001,14.9999,15,29.9999])
|
||||
def test_all_signs_at_all_house_indices(vendor,degree):
|
||||
for sign in local.SIGNS:
|
||||
chart=SimpleNamespace(houses=[SimpleNamespace(sign=sign,sign_degrees=degree) for _ in range(12)])
|
||||
vendor.compute_bhava_dig_bala(chart)
|
||||
assert local.calc_bhava_dig_bala([sign]*12,[degree]*12)==[h.bhava_dig_bala for h in chart.houses]
|
||||
|
||||
|
||||
def test_zero_degree_capricorn_uses_first_half():
|
||||
# Vendor's `(sign_degrees or 15)` misclassifies exact zero; honor the
|
||||
# explicit first-half boundary rather than copying that input bug.
|
||||
assert local.calc_bhava_dig_bala(['Capricorn']*12,[0]*12)==local.BHAVA_STRENGTH_FROM_SIGN_NATURE['chatushpada']
|
||||
|
||||
|
||||
def test_full_component_replay_on_synthetic_chart(vendor):
|
||||
positions={p:{'sign':local.SIGNS[i],'degree':3.75+i*2} for i,p in enumerate(('Sun','Moon','Mars','Mercury','Jupiter','Venus','Saturn'))}
|
||||
strengths={p:300+i*20 for i,p in enumerate(positions)}
|
||||
planets=[SimpleNamespace(celestial_body=p,sign=row['sign'],sign_degrees=row['degree'],shadbala={'Shadbala':{'Total':strengths[p]}}) for p,row in positions.items()]
|
||||
houses=[SimpleNamespace(sign=s,sign_degrees=12.3,lord=local.SIGN_LORDS[s]) for s in local.SIGNS]
|
||||
chart=SimpleNamespace(planets=planets,houses=houses)
|
||||
vendor.compute_bhava_adhipathi_bala(chart);vendor.compute_bhava_dig_bala(chart);vendor.compute_bhava_drik_bala(chart)
|
||||
got=local.calc_bhava_bala(local.SIGNS,[12.3]*12,'Aries',12.3,positions,strengths)
|
||||
for row,h in zip(got['houses'],houses):
|
||||
for key,expected in [('adhipathi_bala',h.bhava_bala_adhipathi),('dig_bala',h.bhava_dig_bala),('drik_bala',h.bhava_drik_bala)]:
|
||||
assert row[key]==round(expected,2)
|
||||
assert row['total']==round(h.bhava_bala_adhipathi+h.bhava_dig_bala+h.bhava_drik_bala,2)
|
||||
Reference in New Issue
Block a user