"""Provide Betty's data model API."""
from __future__ import annotations
from abc import abstractmethod
from reprlib import recursive_repr
from typing import (
TypeVar,
Generic,
Any,
Self,
TypeAlias,
TYPE_CHECKING,
)
from uuid import uuid4
from betty.classtools import repr_instance
from betty.json.linked_data import LinkedDataDumpable, add_json_ld
from betty.json.schema import ref_json_schema
from betty.locale.localizable import _, Localizable
from betty.plugin import PluginRepository, Plugin
from betty.plugin.entry_point import EntryPointPluginRepository
from betty.string import kebab_case_to_lower_camel_case
from typing_extensions import override
if TYPE_CHECKING:
from betty.project import Project
from betty.serde.dump import DumpMapping, Dump
import builtins
ENTITY_TYPE_REPOSITORY: PluginRepository[Entity] = EntryPointPluginRepository(
"betty.entity_type"
)
"""
The entity type plugin repository.
Read more about :doc:`/development/plugin/entity-type`.
"""
[docs]
class GeneratedEntityId(str):
"""
Generate a unique entity ID.
Entities must have IDs for identification. However, not all entities can be provided with an ID that exists in the
original data set (such as a third-party family tree loaded into Betty), so IDs can be generated.
"""
__slots__ = ()
[docs]
class Entity(LinkedDataDumpable, Plugin):
"""
An entity is a uniquely identifiable data container.
Read more about :doc:`/development/plugin/entity-type`.
"""
[docs]
def __init__(
self,
id: str | None = None, # noqa A002
*args: Any,
**kwargs: Any,
):
self._id = GeneratedEntityId() if id is None else id
super().__init__(*args, **kwargs)
[docs]
class UserFacingEntity:
"""
A sentinel to mark an entity type as being visible to users (e.g. not internal).
"""
pass
_EntityT = TypeVar("_EntityT", bound=Entity)
[docs]
class AliasedEntity(Generic[_EntityT]):
"""
An aliased entity wraps an entity and gives aliases its ID.
Aliases are used when deserializing ancestries from sources where intermediate IDs
are used to declare associations between entities. By wrapping an entity in an alias,
the alias can use the intermediate ID, allowing it to be inserted into APIs such as
:py:class:`betty.model.graph.EntityGraphBuilder` which will use the alias ID to finalize
associations before the original entities are returned.
"""