OPEN SOURCE
software/src/data/migrations.py
Read on this site and download the files you need.
Nichijoyaku was created using AI. A complete review by human biblical-language and biblical-studies specialists has not been established. Read alongside established translations and original-language resources.
← Back to the open-source guide
1"""Data migration utilities for upgrading glossary and other data formats."""23from __future__ import annotations45import json6from pathlib import Path7from typing import Any89from src.models.glossary import EnhancedGlossaryTerm, TheologicalDomain101112def infer_domain_from_notes(notes: str | None, english: str) -> TheologicalDomain:13"""Infer theological domain from notes and English translation.1415Args:16notes: Notes field from the term.17english: English translation.1819Returns:20Best-guess theological domain.21"""22if not notes:23notes = ""2425notes_lower = notes.lower()26english_lower = english.lower()2728# Christology indicators29christology_terms = [30"son",31"christ",32"messiah",33"lord",34"i am",35"word",36"logos",37]38if any(term in notes_lower or term in english_lower for term in christology_terms):39return TheologicalDomain.CHRISTOLOGY4041# Pneumatology indicators42pneumatology_terms = ["spirit", "holy spirit", "paraclete", "helper", "advocate"]43if any(44term in notes_lower or term in english_lower for term in pneumatology_terms45):46return TheologicalDomain.PNEUMATOLOGY4748# Soteriology indicators49soteriology_terms = [50"grace",51"salvation",52"save",53"redeem",54"faith",55"believe",56"justif",57]58if any(term in notes_lower or term in english_lower for term in soteriology_terms):59return TheologicalDomain.SOTERIOLOGY6061# Hamartiology indicators62hamartiology_terms = ["sin", "transgression", "iniquity", "flesh"]63if any(64term in notes_lower or term in english_lower for term in hamartiology_terms65):66return TheologicalDomain.HAMARTIOLOGY6768# Theology Proper indicators69theology_proper_terms = ["god", "father", "divine", "glory", "holy"]70if any(71term in notes_lower or term in english_lower for term in theology_proper_terms72):73return TheologicalDomain.THEOLOGY_PROPER7475return TheologicalDomain.GENERAL767778def migrate_glossary_v1_to_v2(data: dict[str, Any]) -> dict[str, Any]:79"""Migrate glossary from v1 format to v2 format with enhanced metadata.8081Args:82data: V1 glossary data with 'terms' list.8384Returns:85V2 glossary data with enhanced fields and version marker.86"""87v1_terms = data.get("terms", [])88v2_terms = []8990for v1_term in v1_terms:91# Create enhanced term with inferred domain92domain = infer_domain_from_notes(93v1_term.get("notes"), v1_term.get("english", "")94)9596v2_term = {97# Core fields (preserved)98"original": v1_term["original"],99"transliteration": v1_term["transliteration"],100"japanese": v1_term["japanese"],101"english": v1_term["english"],102"notes": v1_term.get("notes"),103# Enhanced fields (defaults)104"definition": None,105"semantic_range": [],106"domain": domain.value,107"usage_examples": [],108"frequency": 0,109"related_terms": [],110"avoid_translations": [],111}112v2_terms.append(v2_term)113114return {115"version": "2.0",116"terms": v2_terms,117}118119120def migrate_glossary_file(121input_path: Path, output_path: Path | None = None, backup: bool = True122) -> list[EnhancedGlossaryTerm]:123"""Migrate a glossary JSON file from v1 to v2 format.124125Args:126input_path: Path to the v1 glossary file.127output_path: Path for the output file. If None, overwrites input.128backup: Whether to create a backup of the original file.129130Returns:131List of migrated EnhancedGlossaryTerm objects.132"""133if output_path is None:134output_path = input_path135136# Load existing data137with input_path.open("r", encoding="utf-8") as f:138v1_data = json.load(f)139140# Check if already v2141if v1_data.get("version") == "2.0":142terms = v1_data.get("terms", [])143return [EnhancedGlossaryTerm(**term) for term in terms]144145# Create backup146if backup and output_path == input_path:147backup_path = input_path.with_suffix(".json.v1.bak")148with backup_path.open("w", encoding="utf-8") as f:149json.dump(v1_data, f, ensure_ascii=False, indent=2)150151# Migrate152v2_data = migrate_glossary_v1_to_v2(v1_data)153154# Write output155with output_path.open("w", encoding="utf-8") as f:156json.dump(v2_data, f, ensure_ascii=False, indent=2)157158return [EnhancedGlossaryTerm(**term) for term in v2_data["terms"]]159160161def load_glossary_any_version(path: Path) -> list[EnhancedGlossaryTerm]:162"""Load glossary from any version, converting to EnhancedGlossaryTerm.163164Args:165path: Path to the glossary JSON file.166167Returns:168List of EnhancedGlossaryTerm objects.169"""170if not path.exists():171return []172173with path.open("r", encoding="utf-8") as f:174data = json.load(f)175176# Check version177version = data.get("version", "1.0")178terms = data.get("terms", [])179180if version == "2.0":181# Already v2, load directly182return [EnhancedGlossaryTerm(**term) for term in terms]183184# V1 format - convert on load. Preserve any enhanced fields (e.g.185# inflected_forms) that may already be present in the entries.186converted_terms = []187for v1_term in terms:188term_data = dict(v1_term)189if not term_data.get("domain"):190term_data["domain"] = infer_domain_from_notes(191v1_term.get("notes"), v1_term.get("english", "")192)193converted_terms.append(EnhancedGlossaryTerm(**term_data))194195return converted_terms196