betty.project.extension.demo.project - 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.project.extension.demo.project

    """
    Provide the demonstration project.
    """

    from __future__ import annotations

    from random import choice
    from typing import TYPE_CHECKING

    from betty.ancestry.citation import Citation
    from betty.ancestry.enclosure import Enclosure
    from betty.ancestry.event import Event
    from betty.ancestry.event_type.event_types import Marriage, Birth, Death
    from betty.ancestry.file import File
    from betty.ancestry.file_reference import FileReference
    from betty.ancestry.gender.genders import Female, Male
    from betty.ancestry.link import Link
    from betty.ancestry.name import Name
    from betty.ancestry.note import Note
    from betty.ancestry.person import Person
    from betty.ancestry.person_name import PersonName
    from betty.ancestry.place import Place
    from betty.ancestry.place_type.place_types import (
        Province,
        Country,
        Municipality,
        Village,
    )
    from betty.ancestry.presence import Presence
    from betty.ancestry.presence_role.presence_roles import Subject
    from betty.ancestry.source import Source
    from betty.date import Date, DateRange
    from betty.fs import DATA_DIRECTORY_PATH
    from betty.license.licenses import spdx_license_id_to_license_id
    from betty.media_type.media_types import SVG
    from betty.model.config import EntityReference
    from betty.plugin.config import PluginInstanceConfiguration
    from betty.project import Project
    from betty.project.config import LocaleConfiguration, ProjectConfiguration
    from betty.project.extension.demo.copyright_notice import Streetmix
    from betty.project.extension.raspberry_mint import RaspberryMint
    from betty.project.extension.raspberry_mint.config import RaspberryMintConfiguration
    from betty.typing import internal

    if TYPE_CHECKING:
        from pathlib import Path
        from betty.machine_name import MachineName
        from collections.abc import Mapping, Sequence
        from betty.app import App

    async def create_project(app: App, project_directory_path: Path) -> Project:
        """
        Create a new demonstration project.
        """
        from betty.project.extension.demo import Demo

        configuration = await ProjectConfiguration.new(
            project_directory_path / "betty.json",
            name=Demo.plugin_id(),
            license=PluginInstanceConfiguration("spdx-gpl-3--0-or-later"),
            title={
                "en-US": "A Betty demonstration",
                "de-DE": "Eine Betty-Demonstration",
                "fr-FR": "Une démonstration de Betty",
                "nl-NL": "Een demonstratie van Betty",
                "uk": "Демонстрація Betty",
            },
            author={
                "en-US": "Bart Feenstra and contributors",
                "fr-FR": "Bart Feenstra et contributeurs",
                "nl-NL": "Bart Feenstra en bijdragers",
                "uk": "Bart Feenstra і учасники",
            },
            extensions=[
                PluginInstanceConfiguration(Demo),
                PluginInstanceConfiguration(
                    RaspberryMint,
                    configuration=RaspberryMintConfiguration(
                        featured_entities=[
                            EntityReference(Place, "betty-demo-amsterdam"),
                            EntityReference(Person, "betty-demo-liberta-lankester"),
                            EntityReference(Place, "betty-demo-netherlands"),
                        ],
                    ),
                ),
            ],
            locales=[
                LocaleConfiguration(
                    "en-US",
                    alias="en",
                ),
                LocaleConfiguration("ar"),
                LocaleConfiguration(
                    "de-DE",
                    alias="de",
                ),
                LocaleConfiguration(
                    "fr-FR",
                    alias="fr",
                ),
                LocaleConfiguration("he"),
                LocaleConfiguration(
                    "nl-NL",
                    alias="nl",
                ),
                LocaleConfiguration(
                    "uk",
                    alias="uk",
                ),
            ],
        )
        return await Project.new(app, configuration=configuration)

    @internal
    async def load_ancestry(project: Project) -> None:
        """
        Load the demo ancestry.
        """
        ancestry = project.ancestry

        streetmix_files_per_gender, fallback_streetmix_files = await _load_streetmix_images(
            project
        )

        def _streetmix_image(person: Person) -> None:
            if person.file_references:
                return

            try:
                streetmix_files = streetmix_files_per_gender[person.gender.plugin_id()]
            except KeyError:
                streetmix_files = fallback_streetmix_files
            streetmix_file = choice(streetmix_files)
            ancestry.add(FileReference(person, streetmix_file))

        netherlands = Place(
            id="betty-demo-netherlands",
            names=[
                Name(
                    {
                        "en": "Netherlands",
                        "nl": "Nederland",
                        "uk": "Нідерланди",
                        "fr": "Pays-Bas",
                    }
                ),
            ],
            links=[Link("https://en.wikipedia.org/wiki/Netherlands")],
            place_type=Country(),
        )
        ancestry.add(netherlands)

        north_holland = Place(
            id="betty-demo-north-holland",
            names=[
                Name(
                    {
                        "en": "North Holland",
                        "nl": "Noord-Holland",
                        "uk": "Північна Голландія",
                        "fr": "Hollande-Septentrionale",
                    }
                ),
            ],
            links=[
                Link("https://en.wikipedia.org/wiki/North_Holland"),
                Link("https://www.noord-holland.nl/"),
            ],
            place_type=Province(),
        )
        ancestry.add(Enclosure(enclosee=north_holland, encloser=netherlands))
        ancestry.add(north_holland)

        amsterdam_note = Note(
            """
    Did you know that while Amsterdam is the country's official capital, The Hague is the Netherlands' administrative center and seat of government?
        """
        )

        amsterdam = Place(
            id="betty-demo-amsterdam",
            names=[
                Name({"nl": "Amsterdam", "uk": "Амстерда́м"}),
            ],
            links=[
                Link("https://nl.wikipedia.org/wiki/Amsterdam"),
                Link("https://www.amsterdam.nl/"),
            ],
            notes=[amsterdam_note],
            place_type=Municipality(),
        )
        ancestry.add(Enclosure(enclosee=amsterdam, encloser=north_holland))
        ancestry.add(amsterdam)

        ilpendam = Place(
            id="betty-demo-ilpendam",
            names=[
                Name(
                    {
                        "nl": "Ilpendam",
                        "uk": "Илпендам",
                    }
                ),
            ],
            links=[Link("https://nl.wikipedia.org/wiki/Ilpendam")],
            place_type=Village(),
        )
        ancestry.add(Enclosure(enclosee=ilpendam, encloser=north_holland))
        ancestry.add(ilpendam)

        personal_accounts = Source(
            id="betty-demo-personal-accounts",
            name="Personal accounts",
        )
        ancestry.add(personal_accounts)

        cite_first_person_account = Citation(
            id="betty-demo-first-person-account",
            source=personal_accounts,
            location="Bart Feenstra",
        )
        ancestry.add(cite_first_person_account)

        noord_hollands_archief = Source(
            id="betty-demo-noord-hollands-archief",
            name="Noord-Hollands Archief",
            links=[Link("https://noord-hollandsarchief.nl/")],
        )
        ancestry.add(noord_hollands_archief)

        bevolkingsregister_amsterdam = Source(
            id="betty-demo-bevolkingsregister-amsterdam",
            name="Bevolkingsregister Amsterdam",
            author="Gemeente Amsterdam",
            publisher="Gemeente Amsterdam",
            contained_by=noord_hollands_archief,
        )
        ancestry.add(bevolkingsregister_amsterdam)

        david_marinus_lankester = Person(
            id="betty-demo-david-marinus-lankester", gender=Male()
        )
        _streetmix_image(david_marinus_lankester)
        ancestry.add(
            PersonName(
                person=david_marinus_lankester,
                individual="David Marinus",
                affiliation="Lankester",
            ),
            david_marinus_lankester,
        )

        geertruida_van_ling = Person(id="betty-demo-geertruida-van-ling", gender=Female())
        _streetmix_image(geertruida_van_ling)
        ancestry.add(
            PersonName(
                person=geertruida_van_ling,
                individual="Geertruida",
                affiliation="Van Ling",
            ),
            geertruida_van_ling,
        )

        marriage_of_dirk_jacobus_lankester_and_jannigje_palsen = Event(
            id="betty-demo-marriage-of-dirk-jacobus-lankester-and-jannigje-palsen",
            event_type=Marriage(),
            date=Date(1922, 7, 4),
            place=ilpendam,
        )
        ancestry.add(marriage_of_dirk_jacobus_lankester_and_jannigje_palsen)

        birth_of_dirk_jacobus_lankester = Event(
            id="betty-demo-birth-of-dirk-jacobus-lankester",
            event_type=Birth(),
            date=Date(1897, 8, 25),
            place=amsterdam,
        )
        ancestry.add(birth_of_dirk_jacobus_lankester)

        death_of_dirk_jacobus_lankester = Event(
            id="betty-demo-death-of-dirk-jacobus-lankester",
            event_type=Death(),
            date=Date(1986, 8, 18),
            place=amsterdam,
        )
        ancestry.add(death_of_dirk_jacobus_lankester)

        dirk_jacobus_lankester = Person(
            id="betty-demo-dirk-jacobus-lankester",
            gender=Male(),
            parents=[david_marinus_lankester, geertruida_van_ling],
        )
        _streetmix_image(dirk_jacobus_lankester)
        ancestry.add(
            PersonName(
                person=dirk_jacobus_lankester,
                individual="Dirk Jacobus",
                affiliation="Lankester",
            ),
            Presence(dirk_jacobus_lankester, Subject(), birth_of_dirk_jacobus_lankester),
            Presence(dirk_jacobus_lankester, Subject(), death_of_dirk_jacobus_lankester),
            Presence(
                dirk_jacobus_lankester,
                Subject(),
                marriage_of_dirk_jacobus_lankester_and_jannigje_palsen,
            ),
        )
        ancestry.add(dirk_jacobus_lankester)

        birth_of_marinus_david_lankester = Event(
            id="betty-demo-birth-of-marinus-david",
            event_type=Birth(),
            date=DateRange(
                Date(1874, 1, 15),
                Date(1874, 3, 21),
                start_is_boundary=True,
                end_is_boundary=True,
            ),
            place=amsterdam,
        )
        ancestry.add(birth_of_marinus_david_lankester)

        death_of_marinus_david_lankester = Event(
            id="betty-demo-death-of-marinus-david",
            event_type=Death(),
            date=Date(1971),
            place=amsterdam,
        )
        ancestry.add(death_of_marinus_david_lankester)

        marinus_david_lankester = Person(
            id="betty-demo-marinus-david-lankester",
            gender=Male(),
            parents=[david_marinus_lankester, geertruida_van_ling],
        )
        _streetmix_image(marinus_david_lankester)
        ancestry.add(
            PersonName(
                person=marinus_david_lankester,
                individual="Marinus David",
                affiliation="Lankester",
            ),
            Presence(marinus_david_lankester, Subject(), birth_of_marinus_david_lankester),
            Presence(marinus_david_lankester, Subject(), death_of_marinus_david_lankester),
        )
        ancestry.add(marinus_david_lankester)

        birth_of_jacoba_gesina_lankester = Event(
            id="betty-demo-birth-of-jacoba-gesina",
            event_type=Birth(),
            date=Date(1900, 3, 14),
            place=amsterdam,
        )
        ancestry.add(birth_of_jacoba_gesina_lankester)

        jacoba_gesina_lankester = Person(
            id="betty-demo-jacoba-gesina-lankester",
            gender=Female(),
            parents=[david_marinus_lankester, geertruida_van_ling],
        )
        _streetmix_image(jacoba_gesina_lankester)
        ancestry.add(
            PersonName(
                person=jacoba_gesina_lankester,
                individual="Jacoba Gesina",
                affiliation="Lankester",
            ),
            Presence(jacoba_gesina_lankester, Subject(), birth_of_jacoba_gesina_lankester),
        )
        ancestry.add(jacoba_gesina_lankester)

        jannigje_palsen = Person(id="betty-demo-jannigje-palsen", gender=Female())
        _streetmix_image(jannigje_palsen)
        ancestry.add(
            PersonName(
                person=jannigje_palsen,
                individual="Jannigje",
                affiliation="Palsen",
            ),
            Presence(
                jannigje_palsen,
                Subject(),
                marriage_of_dirk_jacobus_lankester_and_jannigje_palsen,
            ),
            jannigje_palsen,
        )

        marriage_of_johan_de_boer_and_liberta_lankester = Event(
            id="betty-demo-marriage-of-johan-de-boer-and-liberta-lankester",
            event_type=Marriage(),
            date=Date(1953, 6, 19),
            place=amsterdam,
        )
        ancestry.add(marriage_of_johan_de_boer_and_liberta_lankester)

        cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam = Citation(
            id="betty-demo-birth-of-liberta-lankester-from-bevolkingsregister-amsterdam",
            source=bevolkingsregister_amsterdam,
            location="Amsterdam",
        )
        ancestry.add(cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam)

        birth_of_liberta_lankester = Event(
            id="betty-demo-birth-of-liberta-lankester",
            event_type=Birth(),
            date=Date(1929, 12, 22),
            place=amsterdam,
            citations=[cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam],
        )
        ancestry.add(birth_of_liberta_lankester)

        death_of_liberta_lankester = Event(
            id="betty-demo-death-of-liberta-lankester",
            event_type=Death(),
            date=Date(2015, 1, 17),
            place=amsterdam,
            citations=[cite_first_person_account],
        )
        ancestry.add(death_of_liberta_lankester)

        liberta_lankester_note = Note(
            {
                "en-US": """Did you know that Liberta "Betty" Lankester is Betty's namesake?""",
                "nl": """Wist je dat Betty vernoemd is naar Liberta "Betty" Lankester?""",
            }
        )

        liberta_lankester = Person(
            id="betty-demo-liberta-lankester",
            gender=Female(),
            parents=[dirk_jacobus_lankester, jannigje_palsen],
            notes=[liberta_lankester_note],
        )
        _streetmix_image(liberta_lankester)
        ancestry.add(
            PersonName(
                person=liberta_lankester,
                individual="Liberta",
                affiliation="Lankester",
            ),
            PersonName(
                person=liberta_lankester,
                individual="Betty",
                citations=[cite_first_person_account],
            ),
            Presence(liberta_lankester, Subject(), birth_of_liberta_lankester),
            Presence(liberta_lankester, Subject(), death_of_liberta_lankester),
            Presence(
                liberta_lankester,
                Subject(),
                marriage_of_johan_de_boer_and_liberta_lankester,
            ),
        )
        ancestry.add(liberta_lankester)

        birth_of_johan_de_boer = Event(
            id="betty-demo-birth-of-johan-de-boer",
            event_type=Birth(),
            date=Date(1930, 6, 20),
            place=amsterdam,
        )
        ancestry.add(birth_of_johan_de_boer)

        death_of_johan_de_boer = Event(
            id="betty-demo-death-of-johan-de-boer",
            event_type=Death(),
            date=Date(1999, 3, 10),
            place=amsterdam,
            citations=[cite_first_person_account],
        )
        ancestry.add(death_of_johan_de_boer)

        johan_de_boer = Person(id="betty-demo-johan-de-boer", gender=Male())
        _streetmix_image(johan_de_boer)
        ancestry.add(
            PersonName(
                person=johan_de_boer,
                individual="Johan",
                affiliation="De Boer",
            ),
            PersonName(
                person=johan_de_boer,
                individual="Hans",
            ),
            Presence(johan_de_boer, Subject(), birth_of_johan_de_boer),
            Presence(johan_de_boer, Subject(), death_of_johan_de_boer),
            Presence(
                johan_de_boer,
                Subject(),
                marriage_of_johan_de_boer_and_liberta_lankester,
            ),
            johan_de_boer,
        )

        parent_of_bart_feenstra_child_of_liberta_lankester = Person(
            id="betty-demo-parent-of-bart-feenstra-child-of-liberta-lankester",
            parents=[johan_de_boer, liberta_lankester],
        )
        _streetmix_image(parent_of_bart_feenstra_child_of_liberta_lankester)
        ancestry.add(
            PersonName(
                person=parent_of_bart_feenstra_child_of_liberta_lankester,
                individual="Bart's parent",
            )
        )
        ancestry.add(parent_of_bart_feenstra_child_of_liberta_lankester)

        birth_of_bart_feenstra = Event(
            id="betty-demo-birth-of-bart-feenstra",
            event_type=Birth(),
            date=DateRange(Date(1970, 1, 1), start_is_boundary=True),
            place=netherlands,
            citations=[cite_first_person_account],
            description={
                "en-US": "The 'birth of the author', so to speak.",
                "nl-NL": "De 'geboorte van de auteur', om het zo maar te zeggen.",
            },
        )
        ancestry.add(birth_of_johan_de_boer)

        bart_feenstra = Person(
            id="betty-demo-bart-feenstra",
            gender=Male(),
            parents=[parent_of_bart_feenstra_child_of_liberta_lankester],
        )
        Presence(bart_feenstra, Subject(), birth_of_bart_feenstra)
        _streetmix_image(bart_feenstra)
        ancestry.add(
            PersonName(
                person=bart_feenstra,
                individual="Bart",
                affiliation="Feenstra",
            )
        )
        ancestry.add(bart_feenstra)

    async def _load_streetmix_images(
        project: Project,
    ) -> tuple[Mapping[MachineName, Sequence[File]], Sequence[File]]:
        licenses = await project.license_repository
        license = await licenses.new_target(  # noqa A001
            spdx_license_id_to_license_id("AGPL-3.0-or-later")
        )
        copyright_notice = await project.copyright_notice_repository.new_target(Streetmix)
        streetmix_image_directory_path = DATA_DIRECTORY_PATH / "images" / "streetmix"
        masculine: Sequence[File] = []
        feminine: Sequence[File] = []
        androgynous: Sequence[File] = []
        file_names = [
            ("johnny-01.svg", masculine),
            ("johnny-02.svg", masculine),
            ("junebug-01.svg", feminine),
            ("junebug-02.svg", feminine),
            ("people-01.svg", feminine),
            ("people-02.svg", androgynous),
            ("people-06.svg", androgynous),
            ("people-07.svg", feminine),
            ("people-08.svg", feminine),
            ("people-09.svg", androgynous),
            ("people-11.svg", masculine),
            ("people-13.svg", feminine),
            ("people-14.svg", masculine),
            ("people-15.svg", masculine),
            ("people-16.svg", androgynous),
            ("people-17.svg", feminine),
            ("people-18.svg", feminine),
            ("people-19.svg", feminine),
            ("people-23.svg", feminine),
            ("people-24.svg", androgynous),
            ("people-31.svg", masculine),
        ]
        for file_name, appearance in file_names:
            file = File(
                streetmix_image_directory_path / file_name,
                id=f"streetmix-{file_name}",
                media_type=SVG,
                copyright_notice=copyright_notice,
                license=license,
            )
            appearance.append(file)
            project.ancestry.add(file)

        return {
            Female.plugin_id(): feminine + androgynous,
            Male.plugin_id(): masculine + androgynous,
        }, androgynous