"""
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
[docs]
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)
[docs]
@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