#!/usr/bin/env python3 """Canonical consultation-domain registry shared by Python entry points.""" from __future__ import annotations from typing import Any CANONICAL_DOMAINS = ( "career", "marriage", "wealth", "health", "education", "migration", "family", "annual", "timing", "general", ) DEFAULT_THEMES = ("career", "marriage", "wealth") DEFAULT_DOMAINS = DEFAULT_THEMES DOMAIN_ALIASES = { "relationship": "marriage", "finance": "wealth", "money": "wealth", "health-pressure": "health", "health_pressure": "health", "home": "migration", "relocation": "migration", "foreign": "migration", "study": "education", "children": "family", "yearly": "annual", "varshaphala": "annual", "事业": "career", "婚恋": "marriage", "婚姻": "marriage", "感情": "marriage", "财富": "wealth", "财运": "wealth", "健康": "health", "迁移": "migration", "海外": "migration", "教育": "education", "学习": "education", "家庭": "family", "子女": "family", "年度": "annual", "流年": "annual", } _CANONICAL_DOMAIN_SET = frozenset(CANONICAL_DOMAINS) def normalize_domain(value: Any) -> str: """Return one canonical domain or reject the value as unknown.""" key = str(value).strip().lower() canonical = DOMAIN_ALIASES.get(key, key) if canonical not in _CANONICAL_DOMAIN_SET: raise ValueError(f"Unknown theme: {value}") return canonical def normalize_themes(raw: Any) -> list[str]: """Normalize themes, preserving first-seen order and failing closed.""" if raw is None or raw == "" or (isinstance(raw, str) and raw.strip().lower() == "all"): values = list(DEFAULT_THEMES) elif isinstance(raw, str): values = [raw] elif isinstance(raw, list): values = raw else: raise ValueError("theme/themes must be a string, list, or all") if not values: return list(DEFAULT_THEMES) normalized: list[str] = [] for value in values: canonical = normalize_domain(value) if canonical not in normalized: normalized.append(canonical) return normalized