Files
Jyotisha/scripts/shadbala_display.py
T
Jesse_ChenandClaude Opus 5.5 5fdf2f7498 feat(shadbala): BPHS minimum check first, bands labelled as the site's (T3, BUG-1208)
Astrologer ruling 甲13. New scripts/shadbala_display.py (display only; shadbala.py is
frozen and unchanged): chart.shadbala now carries min_required, meets_minimum,
minimum_check (达到/未达到 BPHS 最低要求), level_source=site_band and level
'<band>(网站分档)'; report Shadbala table gains 'BPHS minimum' and 'Site band'
columns (zh/en); evidence snapshot ranking and health narrative say the minimum
check first and mark the band as the site's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-10-03 12:30:19 +08:00

66 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""How a Shadbala strength is shown (astrologer rulings 2026-10-03 甲13, BUG-1208).
First whether the planet meets the BPHS minimum (BPHS ch. 27 vv. 32-33, the
`shadbala.MIN_REQUIRED` table), then the site's own band (150/125/100/75/50 % of
that minimum -> 极强…极弱), labelled as the site's band. `shadbala.py` is in the
frozen rectification identity, so the fields are added here, at display time,
from values the engine already returns; nothing is recomputed.
"""
from __future__ import annotations
from typing import Any, Dict, Optional
LEVEL_SOURCE = 'site_band'
SITE_BAND_SUFFIX = '(网站分档)'
SITE_BAND_SUFFIX_EN = ' (site band)'
MEETS_ZH = '达到 BPHS 最低要求'
MISSES_ZH = '未达到 BPHS 最低要求'
MEETS_EN = 'meets the BPHS minimum'
MISSES_EN = 'below the BPHS minimum'
def _number(value: Any) -> Optional[float]:
return float(value) if isinstance(value, (int, float)) and not isinstance(value, bool) else None
def minimum_fields(rupas: Any, min_required: Any, band: Any) -> Dict[str, Any]:
"""`min_required`, `meets_minimum`, `minimum_check`, band label and source."""
total = _number(rupas)
minimum = _number(min_required)
meets = None if total is None or minimum is None else total >= minimum
fields: Dict[str, Any] = {
'min_required': minimum,
'meets_minimum': meets,
'minimum_check': None if meets is None else (MEETS_ZH if meets else MISSES_ZH),
'level_source': LEVEL_SOURCE,
}
if band not in (None, ''):
fields['level'] = f'{band}{SITE_BAND_SUFFIX}'
return fields
def row_fields(row: Dict[str, Any]) -> Dict[str, Any]:
"""Display fields for one `shadbala.calc_shadbala` planet row."""
return minimum_fields(row.get('total_rupas', row.get('rupas')), row.get('min_required'), row.get('strength_level'))
BAND_EN = {'极强': 'very strong', '强': 'strong', '充足': 'adequate', '略弱': 'slightly weak', '弱': 'weak', '极弱': 'very weak'}
def band_text(band: Any, language: str = 'zh') -> Optional[str]:
if band in (None, ''):
return None
if language == 'en':
return f"{BAND_EN.get(str(band), str(band))}{SITE_BAND_SUFFIX_EN}"
return f'{band}{SITE_BAND_SUFFIX}'
def check_text(meets: Optional[bool], language: str = 'zh') -> str:
if meets is None:
return '-'
if language == 'en':
return MEETS_EN if meets else MISSES_EN
return MEETS_ZH if meets else MISSES_ZH