fix(ayanamsa): keep a caller-selected mode across import and transit paths (BUG-1269, upstream 23be1807)
This commit is contained in:
@@ -45,6 +45,10 @@ AYANAMSA_DISPLAY_NAMES = {
|
||||
|
||||
DEFAULT_AYANAMSA_NAME = 'raman'
|
||||
ACTIVE_AYANAMSA_NAME = DEFAULT_AYANAMSA_NAME
|
||||
# Flipped the first time any caller applies a mode. Import bootstraps read this
|
||||
# so they do not replace a mode that was already selected. This module is
|
||||
# imported once; jyotish_engine can be loaded a second time as its own module.
|
||||
AYANAMSA_APPLIED_IN_PROCESS = False
|
||||
|
||||
|
||||
class UnsupportedAyanamsaError(ValueError):
|
||||
@@ -92,7 +96,7 @@ def current_ayanamsa_name(args: Any = None) -> str:
|
||||
|
||||
def apply_ayanamsa(name: Any = None, swe_module: Any = None) -> bool:
|
||||
"""Set Swiss Ephemeris sidereal mode explicitly."""
|
||||
global ACTIVE_AYANAMSA_NAME
|
||||
global ACTIVE_AYANAMSA_NAME, AYANAMSA_APPLIED_IN_PROCESS
|
||||
module = swe_module or swe
|
||||
if module is None:
|
||||
return False
|
||||
@@ -102,9 +106,15 @@ def apply_ayanamsa(name: Any = None, swe_module: Any = None) -> bool:
|
||||
except Exception:
|
||||
return False
|
||||
ACTIVE_AYANAMSA_NAME = key
|
||||
AYANAMSA_APPLIED_IN_PROCESS = True
|
||||
return True
|
||||
|
||||
|
||||
def ayanamsa_already_applied() -> bool:
|
||||
"""True once any caller has applied an ayanamsa in this process."""
|
||||
return AYANAMSA_APPLIED_IN_PROCESS
|
||||
|
||||
|
||||
@contextmanager
|
||||
def temporary_ayanamsa(name: Any = None, swe_module: Any = None) -> Iterator[str]:
|
||||
"""Apply a sidereal mode and restore the previous process-wide mode."""
|
||||
|
||||
+18
-8
@@ -473,9 +473,12 @@ def cmd_bhava_chalit(args):
|
||||
if not HAS_SWE:
|
||||
return {"error": "swisseph 未安装, 无法计算"}
|
||||
|
||||
second = int(getattr(args, 'second', 0) or 0)
|
||||
chart, asc_idx, jd, ayanamsa = compute_chart_data(
|
||||
args.year, args.month, args.day, args.hour, args.minute,
|
||||
args.lat, args.lon, args.tz, getattr(args, 'node_mode', 'mean'))
|
||||
args.lat, args.lon, args.tz, getattr(args, 'node_mode', 'mean'),
|
||||
second=second,
|
||||
ayanamsa_name=getattr(args, 'ayanamsa', None))
|
||||
|
||||
if chart is None:
|
||||
return {"error": "星盘计算失败"}
|
||||
@@ -490,7 +493,7 @@ def cmd_bhava_chalit(args):
|
||||
asc_lon = chart['ascendant']['degree_raw']
|
||||
# MC: 从 swisseph 重新获取
|
||||
import swisseph as swe
|
||||
hour_decimal = args.hour + args.minute / 60.0 - args.tz
|
||||
hour_decimal = args.hour + args.minute / 60.0 + second / 3600.0 - args.tz
|
||||
jd_val = swe.julday(args.year, args.month, args.day, hour_decimal)
|
||||
cusps_raw, ascmc = swe.houses(jd_val, args.lat, args.lon, b'A')
|
||||
mc_tropical = ascmc[1] # MC
|
||||
@@ -500,15 +503,22 @@ def cmd_bhava_chalit(args):
|
||||
calc = BhavaChalitCalculator()
|
||||
|
||||
mode = getattr(args, 'mode', 'compare')
|
||||
applied_ayanamsa = (chart.get('birth_info') or {}).get('ayanamsa_name')
|
||||
|
||||
def _stamp(payload):
|
||||
if isinstance(payload, dict):
|
||||
payload['requested_ayanamsa'] = getattr(args, 'ayanamsa', None)
|
||||
payload['applied_ayanamsa'] = applied_ayanamsa
|
||||
return payload
|
||||
|
||||
if mode == 'boundaries':
|
||||
return calc.calculate_bhava_boundaries(
|
||||
asc_lon, mc_lon, house_system, jd_val, args.lat, args.lon)
|
||||
return _stamp(calc.calculate_bhava_boundaries(
|
||||
asc_lon, mc_lon, house_system, jd_val, args.lat, args.lon))
|
||||
elif mode == 'chart':
|
||||
return calc.get_bhava_chalit_chart(
|
||||
return _stamp(calc.get_bhava_chalit_chart(
|
||||
planet_lons, asc_lon, mc_lon, house_system,
|
||||
jd_val, args.lat, args.lon)
|
||||
jd_val, args.lat, args.lon))
|
||||
else: # compare
|
||||
return calc.compare_rashi_vs_bhava(
|
||||
return _stamp(calc.compare_rashi_vs_bhava(
|
||||
planet_lons, asc_lon, mc_lon, house_system,
|
||||
jd_val, args.lat, args.lon)
|
||||
jd_val, args.lat, args.lon))
|
||||
|
||||
@@ -26,7 +26,9 @@ def _compute_chart_from_args(args: Any) -> tuple:
|
||||
|
||||
chart, asc_idx, jd, ayanamsa = compute_chart_data(
|
||||
args.year, args.month, args.day, args.hour, args.minute,
|
||||
args.lat, args.lon, args.tz, getattr(args, 'node_mode', 'mean'))
|
||||
args.lat, args.lon, args.tz, getattr(args, 'node_mode', 'mean'),
|
||||
second=int(getattr(args, 'second', 0) or 0),
|
||||
ayanamsa_name=getattr(args, 'ayanamsa', None))
|
||||
|
||||
if chart is None:
|
||||
return None, None, None, None, {}, 0, 0, 0
|
||||
@@ -66,6 +68,14 @@ def cmd_nakshatra_adv(args: Any) -> Dict[str, Any]:
|
||||
if chart is None:
|
||||
return {"error": "swisseph未安装"}
|
||||
|
||||
applied_ayanamsa = (chart.get('birth_info') or {}).get('ayanamsa_name') if isinstance(chart, dict) else None
|
||||
|
||||
def _stamp(payload):
|
||||
if isinstance(payload, dict):
|
||||
payload['requested_ayanamsa'] = getattr(args, 'ayanamsa', None)
|
||||
payload['applied_ayanamsa'] = applied_ayanamsa
|
||||
return payload
|
||||
|
||||
try:
|
||||
from nakshatra_advanced import (
|
||||
find_nakshatra, calc_all_tara_balas, calc_sub_lord,
|
||||
@@ -85,7 +95,7 @@ def cmd_nakshatra_adv(args: Any) -> Dict[str, Any]:
|
||||
detail[pn] = find_nakshatra(lon)
|
||||
result_dict = {'planets': detail}
|
||||
if mode == 'detail':
|
||||
return result_dict
|
||||
return _stamp(result_dict)
|
||||
else:
|
||||
result_dict = {}
|
||||
|
||||
@@ -93,7 +103,7 @@ def cmd_nakshatra_adv(args: Any) -> Dict[str, Any]:
|
||||
if mode in ('all', 'tara'):
|
||||
tara = calc_all_tara_balas(moon_nak_idx, planet_lons)
|
||||
if mode == 'tara':
|
||||
return {'tara_bala': tara, 'moon_nakshatra_idx': moon_nak_idx}
|
||||
return _stamp({'tara_bala': tara, 'moon_nakshatra_idx': moon_nak_idx})
|
||||
result_dict['tara_bala'] = tara
|
||||
|
||||
# === mode: 'chandra' (v6.0.22 新增) ===
|
||||
@@ -107,7 +117,7 @@ def cmd_nakshatra_adv(args: Any) -> Dict[str, Any]:
|
||||
'chandra': calc_chandra_bala(moon_sign_idx, p_sign),
|
||||
}
|
||||
if mode == 'chandra':
|
||||
return {'chandra_bala': chandra, 'moon_sign_idx': moon_sign_idx}
|
||||
return _stamp({'chandra_bala': chandra, 'moon_sign_idx': moon_sign_idx})
|
||||
result_dict['chandra_bala'] = chandra
|
||||
|
||||
# === mode: 'combined' (v6.0.22 新增) ===
|
||||
@@ -115,14 +125,14 @@ def cmd_nakshatra_adv(args: Any) -> Dict[str, Any]:
|
||||
moon_sign_idx = int(moon_lon / 30) % 12
|
||||
combined = calc_tara_chandra_combined(moon_nak_idx, moon_sign_idx, planet_lons)
|
||||
if mode == 'combined':
|
||||
return {'tara_chandra_combined': combined}
|
||||
return _stamp({'tara_chandra_combined': combined})
|
||||
result_dict['tara_chandra_combined'] = combined
|
||||
|
||||
# === mode: 'sublord' ===
|
||||
if mode in ('all', 'sublord'):
|
||||
sublords = {pn: calc_sub_lord(lon) for pn, lon in planet_lons.items()}
|
||||
if mode == 'sublord':
|
||||
return {'sub_lords': sublords}
|
||||
return _stamp({'sub_lords': sublords})
|
||||
result_dict['sub_lords'] = sublords
|
||||
|
||||
# === mode: 'all' / 'full' — 综合报告 ===
|
||||
@@ -130,7 +140,7 @@ def cmd_nakshatra_adv(args: Any) -> Dict[str, Any]:
|
||||
full = nakshatra_full_report(chart)
|
||||
result_dict.update(full)
|
||||
|
||||
return result_dict
|
||||
return _stamp(result_dict)
|
||||
|
||||
|
||||
def cmd_nakshatra_dasha(args: Any) -> Dict[str, Any]:
|
||||
@@ -196,7 +206,8 @@ def cmd_nakshatra_dasha(args: Any) -> Dict[str, Any]:
|
||||
ty, tm, td = map(int, transit_date_str.split('-'))
|
||||
transit_jd = swe.julday(ty, tm, td, 12.0 - args.tz)
|
||||
transit_planets, transit_ayanamsa = _calc_sidereal_planets_for_jd(
|
||||
transit_jd, node_mode=getattr(args, 'node_mode', 'mean'), include_ketu=True)
|
||||
transit_jd, node_mode=getattr(args, 'node_mode', 'mean'), include_ketu=True,
|
||||
ayanamsa_name=getattr(args, 'ayanamsa', None))
|
||||
transit_lons = {}
|
||||
for pn, pd in transit_planets.items():
|
||||
if isinstance(pd, dict) and 'degree' in pd:
|
||||
@@ -217,7 +228,8 @@ def cmd_nakshatra_dasha(args: Any) -> Dict[str, Any]:
|
||||
ty, tm, td = map(int, transit_date_str.split('-'))
|
||||
transit_jd = swe.julday(ty, tm, td, 12.0 - args.tz)
|
||||
transit_planets, _ = _calc_sidereal_planets_for_jd(
|
||||
transit_jd, node_mode=getattr(args, 'node_mode', 'mean'), include_ketu=True)
|
||||
transit_jd, node_mode=getattr(args, 'node_mode', 'mean'), include_ketu=True,
|
||||
ayanamsa_name=getattr(args, 'ayanamsa', None))
|
||||
transit_lons = {}
|
||||
for pn, pd in transit_planets.items():
|
||||
if isinstance(pd, dict) and 'degree' in pd:
|
||||
|
||||
@@ -93,6 +93,7 @@ from ayanamsa_utils import (
|
||||
DEFAULT_AYANAMSA_NAME,
|
||||
UnsupportedAyanamsaError,
|
||||
apply_ayanamsa,
|
||||
ayanamsa_already_applied,
|
||||
ayanamsa_display_name,
|
||||
current_ayanamsa_name,
|
||||
)
|
||||
@@ -145,7 +146,10 @@ load_local_env(ROOT_DIR)
|
||||
|
||||
try:
|
||||
import swisseph as swe
|
||||
apply_ayanamsa(DEFAULT_AYANAMSA_NAME, swe) # default Raman sidereal mode; callers pass explicit names
|
||||
# Default stays Raman. Skip when this process already applied a mode, including
|
||||
# a second import of this file under the name jyotish_engine.
|
||||
if not ayanamsa_already_applied():
|
||||
apply_ayanamsa(DEFAULT_AYANAMSA_NAME, swe)
|
||||
HAS_SWE = True
|
||||
except ImportError:
|
||||
HAS_SWE = False
|
||||
@@ -772,10 +776,15 @@ def _sidereal_calculation_profile(jd, position_mode):
|
||||
return mode, ephemeris_flags, ayanamsa
|
||||
|
||||
|
||||
def _calc_sidereal_planets_for_jd(jd, node_mode='mean', include_ketu=True):
|
||||
"""使用 Swiss Ephemeris 计算指定 Julian Day 的恒星黄道行星位置。"""
|
||||
def _calc_sidereal_planets_for_jd(jd, node_mode='mean', include_ketu=True, ayanamsa_name=None):
|
||||
"""使用 Swiss Ephemeris 计算指定 Julian Day 的恒星黄道行星位置。
|
||||
|
||||
ayanamsa_name 显式指定岁差。省略时沿用进程当前模式。
|
||||
"""
|
||||
if not HAS_SWE:
|
||||
return {}, None
|
||||
if ayanamsa_name:
|
||||
_apply_ayanamsa(ayanamsa_name)
|
||||
ayanamsa = swe.get_ayanamsa(jd)
|
||||
calc_flags = getattr(swe, 'FLG_SWIEPH', 2)
|
||||
data = {}
|
||||
@@ -12867,11 +12876,16 @@ def cmd_db_stats(args):
|
||||
# ============================================================================
|
||||
# 8. 过境查询
|
||||
# ============================================================================
|
||||
def _transit_ayanamsa_mixed_review_policy(command_name, *, requested_ayanamsa=None, transit_ayanamsa=None):
|
||||
def _transit_ayanamsa_mixed_review_policy(command_name, *, requested_ayanamsa=None, transit_ayanamsa=None,
|
||||
applied_ayanamsa=None):
|
||||
requested_key = str(requested_ayanamsa).strip().lower().replace('-', '_') if requested_ayanamsa else None
|
||||
applied_key = str(applied_ayanamsa).strip().lower().replace('-', '_') if applied_ayanamsa else None
|
||||
return {
|
||||
'status': 'mixed_review',
|
||||
'command': command_name,
|
||||
'requested_ayanamsa': requested_ayanamsa,
|
||||
'applied_ayanamsa': applied_ayanamsa,
|
||||
'same_ayanamsa_transit_parity': bool(requested_key and requested_key == applied_key),
|
||||
'transit_ayanamsa': round(transit_ayanamsa, 4) if isinstance(transit_ayanamsa, (int, float)) else transit_ayanamsa,
|
||||
'degree_claim_policy': 'sign_house_month_only_until_same_ayanamsa_transit_parity_closes',
|
||||
'runtime_note': (
|
||||
@@ -12891,6 +12905,9 @@ def cmd_transit(args):
|
||||
return {"error": "swisseph未安装,无法计算实时Transit"}
|
||||
|
||||
swe.set_ephe_path('')
|
||||
requested_ayanamsa = getattr(args, 'ayanamsa', None)
|
||||
if requested_ayanamsa:
|
||||
_apply_ayanamsa(requested_ayanamsa)
|
||||
|
||||
# --- 参数解析 ---
|
||||
t_year = args.year
|
||||
@@ -12912,7 +12929,8 @@ def cmd_transit(args):
|
||||
|
||||
# --- 计算行星位置 ---
|
||||
node_mode = getattr(args, 'node_mode', 'mean')
|
||||
transit_data, ayanamsa = _calc_sidereal_planets_for_jd(jd_mid, node_mode=node_mode, include_ketu=True)
|
||||
transit_data, ayanamsa = _calc_sidereal_planets_for_jd(
|
||||
jd_mid, node_mode=node_mode, include_ketu=True, ayanamsa_name=requested_ayanamsa)
|
||||
if target_planets:
|
||||
target_set = set(target_planets)
|
||||
transit_data = {p: d for p, d in transit_data.items() if p in target_set}
|
||||
@@ -12971,7 +12989,8 @@ def cmd_transit(args):
|
||||
'data_layer': 'true_transit_positions',
|
||||
'transit_ayanamsa_policy': _transit_ayanamsa_mixed_review_policy(
|
||||
'transit',
|
||||
requested_ayanamsa=getattr(args, 'ayanamsa', None),
|
||||
requested_ayanamsa=requested_ayanamsa,
|
||||
applied_ayanamsa=_current_ayanamsa_name(args),
|
||||
transit_ayanamsa=ayanamsa,
|
||||
),
|
||||
'planets': transit_data,
|
||||
|
||||
Reference in New Issue
Block a user