Source code for betty.ancestry.person_name

"""
Data types to describe people's names.
"""

from __future__ import annotations

from typing import final, TYPE_CHECKING, Iterable

from typing_extensions import override

from betty.ancestry.has_citations import HasCitations
from betty.ancestry.locale import HasLocale
from betty.json.linked_data import dump_context, JsonLdObject
from betty.json.schema import String
from betty.locale import UNDETERMINED_LOCALE
from betty.locale.localizable import _, Localizable
from betty.model import Entity
from betty.model.association import BidirectionalToOne, ToOneResolver, ToManyResolver
from betty.plugin import ShorthandPluginBase
from betty.privacy import HasPrivacy, Privacy, merge_privacies
from betty.repr import repr_instance

if TYPE_CHECKING:
    from betty.ancestry.citation import Citation
    from betty.project import Project
    from betty.serde.dump import DumpMapping, Dump
    from betty.ancestry.person import Person


[docs] @final class PersonName(ShorthandPluginBase, HasLocale, HasCitations, HasPrivacy, Entity): """ A name for a :py:class:`betty.ancestry.person.Person`. """ _plugin_id = "person-name" _plugin_label = _("Person name") #: The person whose name this is. person = BidirectionalToOne["PersonName", "Person"]( "betty.ancestry.person_name:PersonName", "person", "betty.ancestry.person:Person", "names", title="Person", )
[docs] def __init__( self, *, person: Person | ToOneResolver[Person], id: str | None = None, # noqa A002 individual: str | None = None, affiliation: str | None = None, privacy: Privacy | None = None, public: bool | None = None, private: bool | None = None, locale: str = UNDETERMINED_LOCALE, citations: Iterable[Citation] | ToManyResolver[Citation] | None = None, ): if not individual and not affiliation: raise ValueError( "The individual and affiliation names must not both be empty." ) super().__init__( id, privacy=privacy, public=public, private=private, locale=locale, citations=citations, ) self._individual = individual self._affiliation = affiliation # Set the person association last, because the association requires comparisons, and self.__eq__() uses the # individual and affiliation names. self.person = person
@override def _get_effective_privacy(self) -> Privacy: privacy = super()._get_effective_privacy() return merge_privacies(privacy, self.person.privacy) @override def __repr__(self) -> str: return repr_instance( self, id=self.id, individual=self.individual, affiliation=self.affiliation )
[docs] @override @classmethod def plugin_label_plural(cls) -> Localizable: return _("Person names")
@property def individual(self) -> str | None: """ The name's individual component. Also known as: - first name - given name """ return self._individual @property def affiliation(self) -> str | None: """ The name's affiliation, or family component. Also known as: - last name - surname """ return self._affiliation @override @property def label(self) -> Localizable: return _("{individual_name} {affiliation_name}").format( individual_name="…" if not self.individual else self.individual, affiliation_name="…" if not self.affiliation else self.affiliation, )
[docs] @override async def dump_linked_data(self, project: Project) -> DumpMapping[Dump]: dump = await super().dump_linked_data(project) if self.public: if self.individual is not None: dump_context(dump, individual="https://schema.org/givenName") dump["individual"] = self.individual if self.affiliation is not None: dump_context(dump, affiliation="https://schema.org/familyName") dump["affiliation"] = self.affiliation return dump
[docs] @override @classmethod async def linked_data_schema(cls, project: Project) -> JsonLdObject: schema = await super().linked_data_schema(project) schema.add_property( "individual", String( title="Individual name", description="The part of the name unique to this individual, such as a first name.", ), False, ) schema.add_property( "affiliation", String( title="Affiliation name", description="The part of the name shared with others, such as a surname.", ), False, ) return schema