Source code for betty.extension.gramps.config

"""
Provide configuration for the :py:class:`betty.extension.gramps.Gramps` extension.
"""

from __future__ import annotations

from pathlib import Path
from typing import Iterable, Any, Self

from typing_extensions import override

from betty.assertion import (
    RequiredField,
    OptionalField,
    assert_record,
    assert_path,
    assert_setattr,
    assert_mapping,
    assert_len,
    assert_str,
)
from betty.config import Configuration
from betty.config.collections.mapping import ConfigurationMapping
from betty.config.collections.sequence import ConfigurationSequence
from betty.machine_name import assert_machine_name, MachineName
from betty.serde.dump import minimize, Dump, VoidableDump


def _assert_gramps_event_type(value: Any) -> str:
    event_type = assert_str()(value)
    assert_len(minimum=1)(event_type)
    return event_type


[docs] class FamilyTreeEventTypeConfiguration(Configuration): """ Configure for loading Gramps events. """ _gramps_event_type: str _event_type_id: MachineName
[docs] def __init__(self, gramps_event_type: str, event_type_id: MachineName): super().__init__() self.gramps_event_type = gramps_event_type self.event_type_id = event_type_id
@property def gramps_event_type(self) -> str: """ The Gramps event type this configuration applies to. """ return self._gramps_event_type @gramps_event_type.setter def gramps_event_type(self, event_type: str) -> None: self._gramps_event_type = _assert_gramps_event_type(event_type) @property def event_type_id(self) -> MachineName: """ The ID of the Betty event type to load Gramps events of type :py:attr:`betty.extension.gramps.config.FamilyTreeEventTypeConfiguration.gramps_event_type` as. """ return self._event_type_id @event_type_id.setter def event_type_id(self, event_type_id: MachineName) -> None: self._event_type_id = assert_machine_name()(event_type_id)
[docs] @override def load(self, dump: Dump) -> None: assert_record( RequiredField( "gramps_event_type", assert_setattr(self, "gramps_event_type") ), RequiredField("event_type", assert_setattr(self, "event_type_id")), )(dump)
[docs] @override def dump(self) -> VoidableDump: return { "gramps_event_type": self.gramps_event_type, "event_type": self.event_type_id, }
[docs] @override def update(self, other: Self) -> None: self.gramps_event_type = other.gramps_event_type self.event_type_id = other.event_type_id
[docs] class FamilyTreeEventTypeConfigurationMapping( ConfigurationMapping[str, FamilyTreeEventTypeConfiguration] ): """ Configure how to map Gramps events to Betty events. """
[docs] def __init__( self, configurations: Iterable[FamilyTreeEventTypeConfiguration] | None = None ): if configurations is None: configurations = [ FamilyTreeEventTypeConfiguration("Adopted", "adoption"), FamilyTreeEventTypeConfiguration("Baptism", "baptism"), FamilyTreeEventTypeConfiguration("Birth", "birth"), FamilyTreeEventTypeConfiguration("Burial", "burial"), FamilyTreeEventTypeConfiguration("Confirmation", "confirmation"), FamilyTreeEventTypeConfiguration("Cremation", "cremation"), FamilyTreeEventTypeConfiguration("Death", "death"), FamilyTreeEventTypeConfiguration("Divorce", "divorce"), FamilyTreeEventTypeConfiguration( "Divorce Filing", "divorce-announcement" ), FamilyTreeEventTypeConfiguration("Emigration", "emigration"), FamilyTreeEventTypeConfiguration("Engagement", "engagement"), FamilyTreeEventTypeConfiguration("Immigration", "immigration"), FamilyTreeEventTypeConfiguration("Marriage", "marriage"), FamilyTreeEventTypeConfiguration( "Marriage Banns", "marriage-announcement" ), FamilyTreeEventTypeConfiguration("Occupation", "occupation"), FamilyTreeEventTypeConfiguration("Residence", "residence"), FamilyTreeEventTypeConfiguration("Retirement", "retirement"), FamilyTreeEventTypeConfiguration("Will", "will"), ] super().__init__(configurations)
@override def _minimize_item_dump(self) -> bool: return True @override def _get_key(self, configuration: FamilyTreeEventTypeConfiguration) -> str: return configuration.gramps_event_type @override def _load_key(self, item_dump: Dump, key_dump: str) -> Dump: mapping_dump = assert_mapping()(item_dump) mapping_dump["gramps_event_type"] = _assert_gramps_event_type(key_dump) return mapping_dump @override def _dump_key(self, item_dump: VoidableDump) -> tuple[VoidableDump, str]: mapping_dump = assert_mapping()(item_dump) return mapping_dump, mapping_dump.pop("entity_type")
[docs] @override def load_item(self, dump: Dump) -> FamilyTreeEventTypeConfiguration: # Use dummy configuration for now to satisfy the initializer. # It will be overridden when loading the dump. configuration = FamilyTreeEventTypeConfiguration("-", "-") configuration.load(dump) return configuration
[docs] class FamilyTreeConfiguration(Configuration): """ Configure a single Gramps family tree. """
[docs] def __init__( self, file_path: Path, *, event_types: Iterable[FamilyTreeEventTypeConfiguration] | None = None, ): super().__init__() self.file_path = file_path self._event_types = FamilyTreeEventTypeConfigurationMapping(event_types)
@override def __eq__(self, other: Any) -> bool: if not isinstance(other, FamilyTreeConfiguration): return False return self._file_path == other.file_path @property def file_path(self) -> Path | None: """ The path to the Gramps family tree file. """ return self._file_path @file_path.setter def file_path(self, file_path: Path | None) -> None: self._file_path = file_path @property def event_types(self) -> FamilyTreeEventTypeConfigurationMapping: """ How to map event types. """ return self._event_types
[docs] @override def load(self, dump: Dump) -> None: assert_record( RequiredField("file", assert_path() | assert_setattr(self, "file_path")) )(dump)
[docs] @override def dump(self) -> VoidableDump: return {"file": str(self.file_path) if self.file_path else None}
[docs] @override def update(self, other: Self) -> None: self.file_path = other.file_path
[docs] class FamilyTreeConfigurationSequence(ConfigurationSequence[FamilyTreeConfiguration]): """ Configure zero or more Gramps family trees. """
[docs] @override def load_item(self, dump: Dump) -> FamilyTreeConfiguration: # Use a dummy path to satisfy initializer arguments. # It will be overridden when loading the fump. item = FamilyTreeConfiguration(Path()) item.load(dump) return item
[docs] class GrampsConfiguration(Configuration): """ Provide configuration for the :py:class:`betty.extension.gramps.Gramps` extension. """
[docs] def __init__( self, *, family_trees: Iterable[FamilyTreeConfiguration] | None = None ): super().__init__() self._family_trees = FamilyTreeConfigurationSequence(family_trees)
@property def family_trees(self) -> FamilyTreeConfigurationSequence: """ The Gramps family trees to load. """ return self._family_trees
[docs] @override def update(self, other: Self) -> None: self._family_trees.update(other._family_trees)
[docs] @override def load(self, dump: Dump) -> None: assert_record(OptionalField("family_trees", self.family_trees.load))(dump)
[docs] @override def dump(self) -> VoidableDump: return minimize({"family_trees": self.family_trees.dump()}, True)