Source code for betty.ancestry.person

"""
Data types describing persons.
"""

from __future__ import annotations

from typing import final, Iterable, MutableSequence, Iterator, TYPE_CHECKING
from urllib.parse import quote

from typing_extensions import override

from betty.ancestry.citation import Citation
from betty.ancestry.gender.genders import Unknown as UnknownGender
from betty.ancestry.has_citations import HasCitations
from betty.ancestry.has_file_references import HasFileReferences
from betty.ancestry.has_notes import HasNotes
from betty.ancestry.link import HasLinks, Link
from betty.functools import unique
from betty.json.linked_data import dump_context, JsonLdObject
from betty.json.schema import Enum
from betty.locale.localizable import _, Localizable
from betty.model import (
    UserFacingEntity,
    Entity,
    EntityReferenceCollectionSchema,
    persistent_id,
)
from betty.model.association import ToManyResolver, BidirectionalToMany
from betty.plugin import ShorthandPluginBase
from betty.privacy import HasPrivacy, Privacy

if TYPE_CHECKING:
    from betty.ancestry.person_name import PersonName
    from betty.ancestry.note import Note
    from betty.ancestry.file_reference import FileReference
    from betty.ancestry.citation import Citation
    from betty.ancestry.presence import Presence
    from betty.ancestry.gender import Gender
    from betty.project import Project
    from betty.serde.dump import DumpMapping, Dump


[docs] @final class Person( ShorthandPluginBase, HasFileReferences, HasCitations, HasNotes, HasLinks, HasPrivacy, UserFacingEntity, Entity, ): """ A person. """ _plugin_id = "person" _plugin_label = _("Person") parents = BidirectionalToMany["Person", "Person"]( "betty.ancestry.person:Person", "parents", "betty.ancestry.person:Person", "children", title="Parents", ) children = BidirectionalToMany["Person", "Person"]( "betty.ancestry.person:Person", "children", "betty.ancestry.person:Person", "parents", title="Children", ) presences = BidirectionalToMany["Person", "Presence"]( "betty.ancestry.person:Person", "presences", "betty.ancestry.presence:Presence", "person", title="Presences", description="This person's presences at events", linked_data_embedded=True, ) names = BidirectionalToMany["Person", "PersonName"]( "betty.ancestry.person:Person", "names", "betty.ancestry.person_name:PersonName", "person", title="Names", linked_data_embedded=True, )
[docs] def __init__( self, *, id: str | None = None, # noqa A002 file_references: Iterable[FileReference] | ToManyResolver[FileReference] | None = None, citations: Iterable["Citation"] | ToManyResolver["Citation"] | None = None, links: MutableSequence[Link] | None = None, notes: Iterable[Note] | ToManyResolver[Note] | None = None, privacy: Privacy | None = None, public: bool | None = None, private: bool | None = None, parents: Iterable[Person] | ToManyResolver[Person] | None = None, children: Iterable[Person] | ToManyResolver[Person] | None = None, presences: Iterable["Presence"] | ToManyResolver["Presence"] | None = None, names: Iterable["PersonName"] | ToManyResolver["PersonName"] | None = None, gender: Gender | None = None, ): super().__init__( id, file_references=file_references, citations=citations, links=links, notes=notes, privacy=privacy, public=public, private=private, ) if children is not None: self.children = children if parents is not None: self.parents = parents if presences is not None: self.presences = presences if names is not None: self.names = names self.gender = gender or UnknownGender()
[docs] @override @classmethod def plugin_label_plural(cls) -> Localizable: return _("People")
@property def ancestors(self) -> Iterator[Person]: """ All ancestors. """ for parent in self.parents: yield parent yield from parent.ancestors @property def siblings(self) -> Iterator[Person]: """ All siblings. """ yield from unique( sibling for parent in self.parents for sibling in parent.children if sibling != self ) @property def descendants(self) -> Iterator[Person]: """ All descendants. """ for child in self.children: yield child yield from child.descendants @override @property def label(self) -> Localizable: for name in self.names: if name.public: return name.label return super().label
[docs] @override async def dump_linked_data(self, project: Project) -> DumpMapping[Dump]: dump = await super().dump_linked_data(project) url_generator = await project.url_generator dump_context( dump, names="https://schema.org/name", parents="https://schema.org/parent", children="https://schema.org/child", siblings="https://schema.org/sibling", ) dump["@type"] = "https://schema.org/Person" dump["siblings"] = [ url_generator.generate( f"betty-static:///person/{quote(sibling.id)}/index.json" ) for sibling in self.siblings if persistent_id(sibling) ] if self.public: dump["gender"] = self.gender.plugin_id() return dump
[docs] @override @classmethod async def linked_data_schema(cls, project: Project) -> JsonLdObject: schema = await super().linked_data_schema(project) schema.add_property( "gender", Enum( *[gender.plugin_id() async for gender in project.gender_repository], title="Gender", ), property_required=False, ) schema.add_property( "siblings", EntityReferenceCollectionSchema(title="Siblings") ) return schema