Files
Jyotisha/scripts/cmd_solar_return.py
T
ClaudeandClaude Opus 5.5 297e27e0bd docs(privacy): swap the leftover private sample for upstream's public example
Upstream replaced the redacted-year sample (April 17, 14:45, about 36.5N
114.2E) with a public birth (1935-06-21 11:00, Cajarc, France) in the
reading workflow and in the narayana-dasha / solar-return usage text. Our
copies still carried the private date, time and place. The PDF guide's
example coordinates now name the San Francisco values it already labels.

Doc and docstring text only; no calculation changes. The same sample is
still a quality-gate fixture in scripts/run_quality_gate.py and appears in
older docs/research notes; neither is changed here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:54:12 +08:00

107 lines
4.3 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
cmd_solar_return: Solar Return (Varshaphala) CLI 子命令
Jyotish Vedic Astrology Skill — v6.0.18
用法:
python3 jyotish_engine.py solar-return --year 1935 --month 6 --day 21 \
--hour 11 --minute 0 --lat 44.486 --lon 1.842 --tz 1 --target-year 2026
"""
import sys
import os
from typing import Dict, Any
def cmd_solar_return(args: Any) -> Dict[str, Any]:
"""
solar-return 子命令:计算太阳返照盘 + 完整 Varshaphala 分析。
参数 (来自 args):
year, month, day, hour, minute: 出生时间
lat, lon, tz: 出生地点/时区
target_year: 目标年份(计算该年太阳返照)
返回:
dict: solar_return_full_report() 的结果
"""
try:
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from ayanamsa_utils import DEFAULT_AYANAMSA_NAME
from solar_return import solar_return_full_report
except ImportError as e:
return {"error": f"solar_return 模块导入失败: {e}"}
if not hasattr(args, 'target_year') or args.target_year is None:
return {"error": "solar-return 需要 --target-year 参数",
"hint": "指定目标年份,如 --target-year 2026"}
return solar_return_full_report(
args.year, args.month, args.day,
args.hour, args.minute,
args.lat, args.lon, args.tz,
args.target_year,
ayanamsa_name=getattr(args, 'ayanamsa', None) or DEFAULT_AYANAMSA_NAME,
birth_second=int(getattr(args, 'second', 0) or 0),
node_mode=getattr(args, 'node_mode', None) or 'mean', # BUG-1501
**solar_return_location_kwargs(args),
)
def solar_return_location_kwargs(args: Any) -> Dict[str, Any]:
"""Return-location kwargs for ``solar_return_full_report``.
Two arg shapes are accepted: the annual-pack namespace (``return_lat`` /
``return_lon`` / ``return_tz`` / ``return_timezone_id``, built by
``annual_tajika_pack._args_from_payload``) and the CLI namespace
(``--solar-return-location-mode`` / ``--current-*`` / ``--timezone-id``).
Upstream yinduzhanxing 41d1c740.
"""
if getattr(args, 'return_lat', None) is not None or getattr(args, 'return_timezone_id', None):
return {
'local_timezone_id': getattr(args, 'return_timezone_id', None),
'return_lat': getattr(args, 'return_lat', None),
'return_lon': getattr(args, 'return_lon', None),
'return_tz': getattr(args, 'return_tz', None),
}
mode = getattr(args, 'solar_return_location_mode', None) or 'birth_place'
if mode == 'current_location':
if any(getattr(args, key, None) is None for key in ('current_lat', 'current_lon', 'current_tz')):
raise ValueError('current_location requires current_lat, current_lon and current_tz')
return {
'local_timezone_id': getattr(args, 'current_timezone_id', None),
'return_lat': float(args.current_lat),
'return_lon': float(args.current_lon),
'return_tz': float(args.current_tz),
}
# CLI passes ``--timezone-id``; API payloads reach here as ``timezone`` /
# ``timezone_name`` (calculation_profile_contract keys). Only IANA ids count.
for key in ('timezone_id', 'timezone', 'timezone_name'):
value = getattr(args, key, None)
if isinstance(value, str) and '/' in value:
return {'local_timezone_id': value.strip()}
return {'local_timezone_id': None}
if __name__ == '__main__':
# 独立测试入口
import argparse
from datetime import datetime
parser = argparse.ArgumentParser(description='Solar Return 测试')
parser.add_argument('--year', type=int, required=True)
parser.add_argument('--month', type=int, required=True)
parser.add_argument('--day', type=int, required=True)
parser.add_argument('--hour', type=int, default=12)
parser.add_argument('--minute', type=int, default=0)
parser.add_argument('--lat', type=float, required=True)
parser.add_argument('--lon', type=float, required=True)
parser.add_argument('--tz', type=float, default=0.0)
parser.add_argument('--target-year', type=int, required=True)
a = parser.parse_args()
result = cmd_solar_return(a)
import json
print(json.dumps(result, ensure_ascii=False, indent=2, default=str))