()
| 420 | |
| 421 | |
| 422 | def load_lexicon() -> Dict[str, Dict[str, Any]]: |
| 423 | lexicon = {key: _normalize_entry(key, value) for key, value in BUILTIN_DIRECTION_REGISTRY.items()} |
| 424 | if LEXICON_PATH.exists(): |
| 425 | try: |
| 426 | with LEXICON_PATH.open("r", encoding="utf-8") as handle: |
| 427 | runtime_lexicon = json.load(handle) or {} |
| 428 | except Exception as exc: |
| 429 | print(f"Failed to load direction lexicon: {exc}") |
| 430 | runtime_lexicon = {} |
| 431 | |
| 432 | if isinstance(runtime_lexicon, dict): |
| 433 | for key, value in runtime_lexicon.items(): |
| 434 | normalized_key = normalize_direction_key(key) or str(key) |
| 435 | runtime_entry = _normalize_entry(str(key), value) |
| 436 | builtin_entry = lexicon.get(normalized_key) |
| 437 | if builtin_entry: |
| 438 | merged_entry = _normalize_entry( |
| 439 | normalized_key, |
| 440 | { |
| 441 | "canonical_name": normalized_key, |
| 442 | "name": builtin_entry.get("name"), |
| 443 | "name_cn": builtin_entry.get("name_cn"), |
| 444 | "aliases": _dedupe_strings( |
| 445 | [ |
| 446 | *(builtin_entry.get("aliases", []) or []), |
| 447 | *(runtime_entry.get("aliases", []) or []), |
| 448 | ] |
| 449 | ), |
| 450 | "paper_terms": _dedupe_strings( |
| 451 | [ |
| 452 | *(builtin_entry.get("paper_terms", []) or []), |
| 453 | *(runtime_entry.get("paper_terms", []) or []), |
| 454 | ] |
| 455 | ), |
| 456 | "source_text": runtime_entry.get("source_text") or builtin_entry.get("source_text", ""), |
| 457 | }, |
| 458 | ) |
| 459 | lexicon[normalized_key] = merged_entry |
| 460 | else: |
| 461 | lexicon[normalized_key] = runtime_entry |
| 462 | |
| 463 | return lexicon |
| 464 | |
| 465 | |
| 466 | def save_lexicon(lexicon: Dict[str, Any]) -> bool: |
no test coverage detected