betty.ancestry.source - Betty documentation

Hide navigation sidebar
Hide table of contents sidebar
Skip to content
Back to top
Toggle table of contents sidebar

# Source code for betty.ancestry.source

    """
    Data types to describe information sources.
    """

    from __future__ import annotations

    from typing import final, Iterable, MutableSequence, Iterator, TYPE_CHECKING

    from typing_extensions import override

    from betty.ancestry.date import HasDate
    from betty.ancestry.has_file_references import HasFileReferences
    from betty.ancestry.has_notes import HasNotes
    from betty.ancestry.link import HasLinks, Link
    from betty.json.linked_data import dump_context
    from betty.locale.localizable import (
        _,
        OptionalStaticTranslationsLocalizableAttr,
        ShorthandStaticTranslations,
        Localizable,
    )
    from betty.model import UserFacingEntity, Entity
    from betty.model.association import (
        BidirectionalToZeroOrOne,
        BidirectionalToMany,
        ToOneResolver,
        ToManyResolver,
        ToZeroOrOneResolver,
    )
    from betty.plugin import ShorthandPluginBase
    from betty.privacy import HasPrivacy, Privacy, merge_privacies

    if TYPE_CHECKING:
        from betty.ancestry.citation import Citation  # noqa F401
        from betty.ancestry.note import Note
        from betty.ancestry.file_reference import FileReference
        from betty.serde.dump import DumpMapping, Dump
        from betty.project import Project
        from betty.date import Datey

    @final
    class Source(
        ShorthandPluginBase,
        HasDate,
        HasFileReferences,
        HasNotes,
        HasLinks,
        HasPrivacy,
        UserFacingEntity,
        Entity,
    ):
        """
        A source of information.
        """

        _plugin_id = "source"
        _plugin_label = _("Source")

        #: The source this one is directly contained by.
        contained_by = BidirectionalToZeroOrOne["Source", "Source"](
            "betty.ancestry.source:Source",
            "contained_by",
            "betty.ancestry.source:Source",
            "contains",
            title="Contained by",
            description="Another source this source may be contained by",
        )
        contains = BidirectionalToMany["Source", "Source"](
            "betty.ancestry.source:Source",
            "contains",
            "betty.ancestry.source:Source",
            "contained_by",
            title="Contains",
            description="Other sources this source may contain",
        )
        citations = BidirectionalToMany["Source", "Citation"](
            "betty.ancestry.source:Source",
            "citations",
            "betty.ancestry.citation:Citation",
            "source",
            title="Citations",
            description="The citations referencing this source",
        )

        #: The human-readable source name.
        name = OptionalStaticTranslationsLocalizableAttr("name", title="Name")

        #: The human-readable author.
        author = OptionalStaticTranslationsLocalizableAttr("author", title="Author")

        #: The human-readable publisher.
        publisher = OptionalStaticTranslationsLocalizableAttr(
            "publisher", title="Publisher"
        )

        def __init__(
            self,
            name: ShorthandStaticTranslations | None = None,
            *,
            id: str | None = None,  # noqa A002  # noqa A002
            author: ShorthandStaticTranslations | None = None,
            publisher: ShorthandStaticTranslations | None = None,
            contained_by: Source
            | ToZeroOrOneResolver[Source]
            | ToOneResolver[Source]
            | None = None,
            contains: Iterable[Source] | ToManyResolver[Source] | None = None,
            notes: Iterable[Note] | ToManyResolver[Note] | None = None,
            date: Datey | None = None,
            file_references: Iterable["FileReference"]
            | ToManyResolver["FileReference"]
            | None = None,
            links: MutableSequence[Link] | None = None,
            privacy: Privacy | None = None,
            public: bool | None = None,
            private: bool | None = None,
        ):
            super().__init__(
                id,
                notes=notes,
                date=date,
                file_references=file_references,
                links=links,
                privacy=privacy,
                public=public,
                private=private,
            )
            if name:
                self.name = name
            if author:
                self.author = author
            if publisher:
                self.publisher = publisher
            if contained_by is not None:
                self.contained_by = contained_by
            if contains is not None:
                self.contains = contains

        @override
        def _get_effective_privacy(self) -> Privacy:
            privacy = super()._get_effective_privacy()
            if self.contained_by:
                return merge_privacies(privacy, self.contained_by.privacy)
            return privacy

        @property
        def walk_contains(self) -> Iterator[Source]:
            """
            All directly and indirectly contained sources.
            """
            for source in self.contains:
                yield source
                yield from source.contains

        @override
        @classmethod
        def plugin_label_plural(cls) -> Localizable:
            return _("Sources")

        @override
        @property
        def label(self) -> Localizable:
            return self.name if self.name else super().label

        @override
        async def dump_linked_data(self, project: Project) -> DumpMapping[Dump]:
            dump = await super().dump_linked_data(project)
            dump["@type"] = "https://schema.org/Thing"
            dump_context(dump, name="https://schema.org/name")
            return dump