Exemple #1
0
    async def test_filter(self, m_aioresponses) -> None:
        entry_url = 'https://en.wikipedia.org/wiki/Amsterdam'
        links = [
            Link(entry_url),
            # Add a link to Wikipedia, but using a locale that's not used by the app, to test it's ignored.
            Link('https://nl.wikipedia.org/wiki/Amsterdam'),
            # Add a link that doesn't point to Wikipedia at all to test it's ignored.
            Link('https://example.com'),
        ]
        api_url = 'https://en.wikipedia.org/w/api.php?action=query&titles=Amsterdam&prop=extracts&exintro&format=json&formatversion=2'
        title = 'Amstelredam'
        extract = 'De hoofdstad van Nederland.'
        api_response_body = {
            'query': {
                'pages': [
                    {
                        'title': title,
                        'extract': extract,
                    },
                ],
            }
        }
        m_aioresponses.get(api_url, payload=api_response_body)

        with TemporaryDirectory() as output_directory_path:
            with TemporaryDirectory() as cache_directory_path:
                configuration = Configuration(
                    output_directory_path, 'https://ancestry.example.com')
                configuration.cache_directory_path = Path(cache_directory_path)
                configuration.extensions.add(ExtensionConfiguration(Wikipedia))
                async with App(configuration) as app:
                    actual = app.jinja2_environment.from_string(
                        '{% for entry in (links | wikipedia) %}{{ entry.content }}{% endfor %}').render(links=links)
        self.assertEquals(extract, actual)
Exemple #2
0
def _load_urls(owner: HasLinks, element: ElementTree.Element):
    url_elements = _xpath(element, './ns:url')
    for url_element in url_elements:
        link = Link(str(url_element.get('href')))
        link.relationship = 'external'
        link.label = url_element.get('description')
        owner.links.add(link)
Exemple #3
0
 async def test_populate_link_should_set_locale(self, expected: str, entry_language: str, locale: Optional[str], m_retriever) -> None:
     link = Link('http://%s.wikipedia.org/wiki/Amsterdam' % entry_language)
     link.locale = locale
     with TemporaryDirectory() as output_directory_path:
         with TemporaryDirectory() as cache_directory_path:
             configuration = Configuration(
                 output_directory_path, 'https://example.com')
             configuration.cache_directory_path = cache_directory_path
             async with App(configuration) as app:
                 sut = _Populator(app, m_retriever)
                 await sut.populate_link(link, entry_language)
     self.assertEqual(expected, link.locale)
Exemple #4
0
 async def test_populate_link_should_set_relationship(self, expected: str, relationship: Optional[str], m_retriever) -> None:
     link = Link('http://en.wikipedia.org/wiki/Amsterdam')
     link.relationship = relationship
     with TemporaryDirectory() as output_directory_path:
         with TemporaryDirectory() as cache_directory_path:
             configuration = Configuration(
                 output_directory_path, 'https://example.com')
             configuration.cache_directory_path = cache_directory_path
             async with App(configuration) as app:
                 sut = _Populator(app, m_retriever)
                 await sut.populate_link(link, 'en')
     self.assertEqual(expected, link.relationship)
Exemple #5
0
 async def test_populate_link_should_set_label(self, expected: str, label: Optional[str], m_retriever) -> None:
     link = Link('http://en.wikipedia.org/wiki/Amsterdam')
     link.label = label
     entry = Entry('en', 'The_city_of_Amsterdam', 'The city of Amsterdam', 'Amsterdam, such a lovely place!')
     with TemporaryDirectory() as output_directory_path:
         with TemporaryDirectory() as cache_directory_path:
             configuration = Configuration(
                 output_directory_path, 'https://example.com')
             configuration.cache_directory_path = cache_directory_path
             async with App(configuration) as app:
                 sut = _Populator(app, m_retriever)
                 await sut.populate_link(link, 'en', entry)
     self.assertEqual(expected, link.label)
Exemple #6
0
    async def test_populate_should_populate_existing_link(self, m_retriever) -> None:
        entry_language = 'en'
        entry_name = 'Amsterdam'
        entry_title = 'Amsterdam'
        entry_content = 'Capitol of the Netherlands'
        entry = Entry(entry_language, entry_name, entry_title, entry_content)
        m_retriever.get_entry.return_value = entry

        resource = Source('the_source', 'The Source')
        link = Link('https://en.wikipedia.org/wiki/Amsterdam')
        resource.links.add(link)
        with TemporaryDirectory() as output_directory_path:
            with TemporaryDirectory() as cache_directory_path:
                configuration = Configuration(
                    output_directory_path, 'https://example.com')
                configuration.cache_directory_path = cache_directory_path
                async with App(configuration) as app:
                    app.ancestry.entities.append(resource)
                    sut = _Populator(app, m_retriever)
                    await sut.populate()
        m_retriever.get_entry.assert_called_once_with(entry_language, entry_name)
        self.assertEqual(1, len(resource.links))
        self.assertEqual('Amsterdam', link.label)
        self.assertEqual('en', link.locale)
        self.assertEqual(MediaType('text/html'), link.media_type)
        self.assertIsNotNone(link.description)
        self.assertEqual('external', link.relationship)
Exemple #7
0
 async def test_populate_link_should_convert_http_to_https(self, m_retriever) -> None:
     link = Link('http://en.wikipedia.org/wiki/Amsterdam')
     entry_language = 'nl'
     with TemporaryDirectory() as output_directory_path:
         with TemporaryDirectory() as cache_directory_path:
             configuration = Configuration(
                 output_directory_path, 'https://example.com')
             configuration.cache_directory_path = cache_directory_path
             async with App(configuration) as app:
                 sut = _Populator(app, m_retriever)
                 await sut.populate_link(link, entry_language)
     self.assertEqual('https://en.wikipedia.org/wiki/Amsterdam', link.url)
Exemple #8
0
    async def test_populate_should_add_translation_links(self, m_retriever) -> None:
        entry_language = 'en'
        entry_name = 'Amsterdam'
        entry_title = 'Amsterdam'
        entry_content = 'Capitol of the Netherlands'
        entry = Entry(entry_language, entry_name, entry_title, entry_content)
        added_entry_language = 'nl'
        added_entry_name = 'Amsterdam'
        added_entry_title = 'Amsterdam'
        added_entry_content = 'Hoofdstad van Nederland'
        added_entry = Entry(added_entry_language, added_entry_name, added_entry_title, added_entry_content)
        m_retriever.get_entry.side_effect = [
            entry,
            added_entry
        ]

        m_retriever.get_translations.return_value = {
            entry_language: entry_name,
            added_entry_language: added_entry_name,
        }

        resource = Source('the_source', 'The Source')
        link_en = Link('https://en.wikipedia.org/wiki/Amsterdam')
        resource.links.add(link_en)
        with TemporaryDirectory() as output_directory_path:
            with TemporaryDirectory() as cache_directory_path:
                configuration = Configuration(
                    output_directory_path, 'https://example.com')
                configuration.cache_directory_path = cache_directory_path
                configuration.locales.replace([
                    LocaleConfiguration('en-US', 'en'),
                    LocaleConfiguration('nl-NL', 'nl'),
                ])
                async with App(configuration) as app:
                    app.ancestry.entities.append(resource)
                    sut = _Populator(app, m_retriever)
                    await sut.populate()

        m_retriever.get_entry.assert_has_calls([
            call(entry_language, entry_name),
            call(added_entry_language, added_entry_name),
        ])
        m_retriever.get_translations.assert_called_once_with(entry_language, entry_name)
        self.assertEqual(2, len(resource.links))
        link_nl = resource.links.difference({link_en}).pop()
        self.assertEqual('Amsterdam', link_nl.label)
        self.assertEqual('nl', link_nl.locale)
        self.assertEqual(MediaType('text/html'), link_nl.media_type)
        self.assertIsNotNone(link_nl.description)
        self.assertEqual('external', link_nl.relationship)
Exemple #9
0
 async def test_populate_should_ignore_non_wikipedia_links(self, m_retriever) -> None:
     link = Link('https://example.com')
     resource = Source('the_source', 'The Source')
     resource.links.add(link)
     with TemporaryDirectory() as output_directory_path:
         with TemporaryDirectory() as cache_directory_path:
             configuration = Configuration(
                 output_directory_path, 'https://example.com')
             configuration.cache_directory_path = cache_directory_path
             async with App(configuration) as app:
                 app.ancestry.entities.append(resource)
                 sut = _Populator(app, m_retriever)
                 await sut.populate()
     self.assertSetEqual({link}, resource.links)
Exemple #10
0
    async def test_post_load(self, m_aioresponses) -> None:
        resource = Source('the_source', 'The Source')
        link = Link('https://en.wikipedia.org/wiki/Amsterdam')
        resource.links.add(link)
        entry_title = 'Amstelredam'
        entry_extract = 'Capitol of the Netherlands'
        entry_api_response_body = {
            'query': {
                'pages': [
                    {
                        'title': entry_title,
                        'extract': entry_extract,
                    },
                ],
            }
        }
        entry_api_url = 'https://en.wikipedia.org/w/api.php?action=query&titles=Amsterdam&prop=extracts&exintro&format=json&formatversion=2'
        m_aioresponses.get(entry_api_url, payload=entry_api_response_body)
        translations_api_response_body = {
            'query': {
                'pages': [
                    {
                        'langlinks': [],
                    },
                ],
            },
        }
        translations_api_url = 'https://en.wikipedia.org/w/api.php?action=query&titles=Amsterdam&prop=langlinks&lllimit=500&format=json&formatversion=2'
        m_aioresponses.get(translations_api_url, payload=translations_api_response_body)

        with TemporaryDirectory() as output_directory_path:
            with TemporaryDirectory() as cache_directory_path:
                configuration = Configuration(
                    output_directory_path, 'https://example.com')
                configuration.cache_directory_path = Path(cache_directory_path)
                configuration.extensions.add(ExtensionConfiguration(Wikipedia))
                async with App(configuration) as app:
                    app.ancestry.entities.append(resource)
                    await load(app)

        self.assertEqual(1, len(resource.links))
        self.assertEqual(entry_title, link.label)
        self.assertEqual('en', link.locale)
        self.assertEqual(MediaType('text/html'), link.media_type)
        self.assertIsNotNone(link.description)
        self.assertEqual('external', link.relationship)
Exemple #11
0
    async def _populate_entity(self, entity: Entity,
                               locales: Set[str]) -> None:
        if not isinstance(entity, HasLinks):
            return

        entry_links = set()
        for link in entity.links:
            try:
                entry_language, entry_name = _parse_url(link.url)
                entry_links.add((entry_language, entry_name))
            except NotAnEntryError:
                continue

            entry = None
            if link.label is None:
                with suppress(RetrievalError):
                    entry = await self._retriever.get_entry(
                        entry_language, entry_name)
            await self.populate_link(link, entry_language, entry)

        for entry_language, entry_name in list(entry_links):
            entry_translations = await self._retriever.get_translations(
                entry_language, entry_name)
            if len(entry_translations) == 0:
                continue
            entry_languages = list(entry_translations.keys())
            for locale in locales.difference({entry_language}):
                added_entry_language = negotiate_locale(
                    locale, entry_languages)
                if added_entry_language is None:
                    continue
                added_entry_name = entry_translations[added_entry_language]
                if (added_entry_language, added_entry_name) in entry_links:
                    continue
                try:
                    added_entry = await self._retriever.get_entry(
                        added_entry_language, added_entry_name)
                except RetrievalError:
                    continue
                added_link = Link(added_entry.url)
                await self.populate_link(added_link, added_entry_language,
                                         added_entry)
                entity.links.add(added_link)
                entry_links.add((added_entry_language, added_entry_name))
Exemple #12
0
 async def test_link_should_encode_full(self) -> None:
     link = Link('https://example.com')
     link.label = 'The Link'
     link.relationship = 'external'
     link.locale = 'nl-NL'
     link.media_type = MediaType('text/html')
     expected = {
         'url': 'https://example.com',
         'relationship': 'external',
         'label': 'The Link',
         'locale': 'nl-NL',
         'mediaType': 'text/html',
     }
     await self.assert_encodes(expected, link, 'link')
Exemple #13
0
 async def populate_link(self,
                         link: Link,
                         entry_language: str,
                         entry: Optional[Entry] = None) -> None:
     if link.url.startswith('http:'):
         link.url = 'https:' + link.url[5:]
     if link.media_type is None:
         link.media_type = MediaType('text/html')
     if link.relationship is None:
         link.relationship = 'external'
     if link.locale is None:
         link.locale = entry_language
     if link.description is None:
         # There are valid reasons for links in locales that aren't supported.
         with suppress(ValueError):
             async with self._app.with_locale(link.locale):
                 link.description = _('Read more on Wikipedia.')
     if entry is not None and link.label is None:
         link.label = entry.title
Exemple #14
0
    async def test_person_should_encode_full(self):
        parent_id = 'the_parent'
        parent = Person(parent_id)

        child_id = 'the_child'
        child = Person(child_id)

        sibling_id = 'the_sibling'
        sibling = Person(sibling_id)
        sibling.parents.append(parent)

        person_id = 'the_person'
        person_affiliation_name = 'Person'
        person_individual_name = 'The'
        person = Person(person_id)
        PersonName(person, person_individual_name, person_affiliation_name)
        person.parents.append(parent)
        person.children.append(child)
        person.private = False
        link = Link('https://example.com/the-person')
        link.label = 'The Person Online'
        person.links.add(link)
        person.citations.append(Citation('the_citation', Source('The Source')))
        Presence(person, Subject(), Event('the_event', Birth()))

        expected = {
            '$schema':
            '/schema.json#/definitions/person',
            '@context': {
                'parents': 'https://schema.org/parent',
                'children': 'https://schema.org/child',
                'siblings': 'https://schema.org/sibling',
            },
            '@type':
            'https://schema.org/Person',
            'id':
            person_id,
            'names': [
                {
                    '@context': {
                        'individual': 'https://schema.org/givenName',
                        'affiliation': 'https://schema.org/familyName',
                    },
                    'individual': person_individual_name,
                    'affiliation': person_affiliation_name,
                },
            ],
            'parents': [
                '/en/person/the_parent/index.json',
            ],
            'children': [
                '/en/person/the_child/index.json',
            ],
            'siblings': [
                '/en/person/the_sibling/index.json',
            ],
            'private':
            False,
            'presences': [
                {
                    '@context': {
                        'event': 'https://schema.org/performerIn',
                    },
                    'role': 'subject',
                    'event': '/en/event/the_event/index.json',
                },
            ],
            'citations': [
                '/en/citation/the_citation/index.json',
            ],
            'links': [
                {
                    'url': '/en/person/the_person/index.json',
                    'relationship': 'canonical',
                    'mediaType': 'application/json',
                },
                {
                    'url': '/nl/person/the_person/index.json',
                    'relationship': 'alternate',
                    'locale': 'nl-NL',
                },
                {
                    'url': '/en/person/the_person/index.html',
                    'relationship': 'alternate',
                    'mediaType': 'text/html',
                },
                {
                    'url': 'https://example.com/the-person',
                    'label': 'The Person Online',
                },
            ],
        }
        await self.assert_encodes(expected, person, 'person')
Exemple #15
0
    def _encode_entity(self, encoded: Dict, entity: Entity) -> None:
        self._encode_schema(
            encoded,
            upper_camel_case_to_lower_camel_case(
                get_entity_type_name(entity.entity_type())))

        if 'links' not in encoded:
            encoded['links'] = []

        if not isinstance(entity.id, GeneratedEntityId):
            encoded['id'] = entity.id

            canonical = Link(self._generate_url(entity))
            canonical.relationship = 'canonical'
            canonical.media_type = 'application/json'
            encoded['links'].append(canonical)

            for locale_configuration in self._app.configuration.locales:
                if locale_configuration.locale == self._locale:
                    continue
                translation = Link(
                    self._generate_url(entity,
                                       locale=locale_configuration.locale))
                translation.relationship = 'alternate'
                translation.locale = locale_configuration.locale
                encoded['links'].append(translation)

            html = Link(self._generate_url(entity, media_type='text/html'))
            html.relationship = 'alternate'
            html.media_type = 'text/html'
            encoded['links'].append(html)
Exemple #16
0
 def test_relationship(self) -> None:
     url = 'https://example.com'
     sut = Link(url)
     self.assertIsNone(sut.relationship)
Exemple #17
0
 def test_label(self) -> None:
     url = 'https://example.com'
     sut = Link(url)
     self.assertIsNone(sut.label)
Exemple #18
0
 def test_media_type(self) -> None:
     url = 'https://example.com'
     sut = Link(url)
     self.assertIsNone(sut.media_type)
Exemple #19
0
 def test_description(self) -> None:
     url = 'https://example.com'
     sut = Link(url)
     self.assertIsNone(sut.description)
Exemple #20
0
 def test_url(self) -> None:
     url = 'https://example.com'
     sut = Link(url)
     self.assertEquals(url, sut.url)
Exemple #21
0
 async def test_source_should_encode_full(self):
     source = Source('the_source', 'The Source')
     source.author = 'The Author'
     source.publisher = 'The Publisher'
     source.date = Date(2000, 1, 1)
     source.contained_by = Source('the_containing_source',
                                  'The Containing Source')
     link = Link('https://example.com/the-source')
     link.label = 'The Source Online'
     source.links.add(link)
     source.contains.append(
         Source('the_contained_source', 'The Contained Source'))
     Citation('the_citation', source)
     expected = {
         '$schema':
         '/schema.json#/definitions/source',
         '@context': {
             'name': 'https://schema.org/name',
         },
         '@type':
         'https://schema.org/Thing',
         'id':
         'the_source',
         'name':
         'The Source',
         'author':
         'The Author',
         'publisher':
         'The Publisher',
         'contains': [
             '/en/source/the_contained_source/index.json',
         ],
         'citations': [
             '/en/citation/the_citation/index.json',
         ],
         'containedBy':
         '/en/source/the_containing_source/index.json',
         'date': {
             'year': 2000,
             'month': 1,
             'day': 1,
         },
         'links': [
             {
                 'url': '/en/source/the_source/index.json',
                 'relationship': 'canonical',
                 'mediaType': 'application/json',
             },
             {
                 'url': '/nl/source/the_source/index.json',
                 'relationship': 'alternate',
                 'locale': 'nl-NL',
             },
             {
                 'url': '/en/source/the_source/index.html',
                 'relationship': 'alternate',
                 'mediaType': 'text/html',
             },
             {
                 'url': 'https://example.com/the-source',
                 'label': 'The Source Online',
             },
         ],
     }
     await self.assert_encodes(expected, source, 'source')
Exemple #22
0
 async def test_link_should_encode_minimal(self) -> None:
     link = Link('https://example.com')
     expected = {
         'url': 'https://example.com',
     }
     await self.assert_encodes(expected, link, 'link')
Exemple #23
0
 async def test_place_should_encode_full(self):
     place_id = 'the_place'
     name = 'The Place'
     locale = 'nl-NL'
     latitude = 12.345
     longitude = -54.321
     coordinates = Point(latitude, longitude)
     place = Place(place_id, [PlaceName(name, locale)])
     place.coordinates = coordinates
     Enclosure(place, Place('the_enclosing_place', []))
     Enclosure(Place('the_enclosed_place', []), place)
     link = Link('https://example.com/the-place')
     link.label = 'The Place Online'
     place.links.add(link)
     place.events.append(Event('E1', Birth()))
     expected = {
         '$schema':
         '/schema.json#/definitions/place',
         '@context': {
             'enclosedBy': 'https://schema.org/containedInPlace',
             'encloses': 'https://schema.org/containsPlace',
             'events': 'https://schema.org/event',
             'coordinates': 'https://schema.org/geo',
         },
         '@type':
         'https://schema.org/Place',
         'id':
         place_id,
         'names': [
             {
                 'name': name,
                 'locale': 'nl-NL',
             },
         ],
         'events': [
             '/en/event/E1/index.json',
         ],
         'links': [
             {
                 'url': '/en/place/the_place/index.json',
                 'relationship': 'canonical',
                 'mediaType': 'application/json',
             },
             {
                 'url': '/nl/place/the_place/index.json',
                 'relationship': 'alternate',
                 'locale': 'nl-NL',
             },
             {
                 'url': '/en/place/the_place/index.html',
                 'relationship': 'alternate',
                 'mediaType': 'text/html',
             },
             {
                 'url': 'https://example.com/the-place',
                 'label': 'The Place Online',
             },
         ],
         'coordinates': {
             '@context': {
                 'latitude': 'https://schema.org/latitude',
                 'longitude': 'https://schema.org/longitude',
             },
             '@type': 'https://schema.org/GeoCoordinates',
             'latitude': latitude,
             'longitude': longitude,
         },
         'encloses': [
             '/en/place/the_enclosed_place/index.json',
         ],
         'enclosedBy': [
             '/en/place/the_enclosing_place/index.json',
         ],
     }
     await self.assert_encodes(expected, place, 'place')
Exemple #24
0
    async def load(self) -> None:
        amsterdam = Place('betty-demo-amsterdam', [PlaceName('Amsterdam')])
        amsterdam.coordinates = Point(52.366667, 4.9)
        amsterdam.links.add(Link('https://nl.wikipedia.org/wiki/Amsterdam'))
        self._app.ancestry.entities.append(amsterdam)

        ilpendam = Place('betty-demo-ilpendam', [PlaceName('Ilpendam')])
        ilpendam.coordinates = Point(52.465556, 4.951111)
        ilpendam.links.add(Link('https://nl.wikipedia.org/wiki/Ilpendam'))
        self._app.ancestry.entities.append(ilpendam)

        personal_accounts = Source('betty-demo-personal-accounts',
                                   'Personal accounts')
        self._app.ancestry.entities.append(personal_accounts)

        cite_first_person_account = Citation('betty-demo-first-person-account',
                                             personal_accounts)
        self._app.ancestry.entities.append(cite_first_person_account)

        bevolkingsregister_amsterdam = Source(
            'betty-demo-bevolkingsregister-amsterdam',
            'Bevolkingsregister Amsterdam')
        bevolkingsregister_amsterdam.author = 'Gemeente Amsterdam'
        bevolkingsregister_amsterdam.publisher = 'Gemeente Amsterdam'
        self._app.ancestry.entities.append(bevolkingsregister_amsterdam)

        david_marinus_lankester = Person('betty-demo-david-marinus-lankester')
        PersonName(david_marinus_lankester, 'David Marinus', 'Lankester')
        self._app.ancestry.entities.append(david_marinus_lankester)

        geertruida_van_ling = Person('betty-demo-geertruida-van-ling')
        PersonName(geertruida_van_ling, 'Geertruida', 'Van Ling')
        self._app.ancestry.entities.append(geertruida_van_ling)

        marriage_of_dirk_jacobus_lankester_and_jannigje_palsen = Event(
            'betty-demo-marriage-of-dirk-jacobus-lankester-and-jannigje-palsen',
            Marriage(), Date(1922, 7, 4))
        marriage_of_dirk_jacobus_lankester_and_jannigje_palsen.place = ilpendam
        self._app.ancestry.entities.append(
            marriage_of_dirk_jacobus_lankester_and_jannigje_palsen)

        birth_of_dirk_jacobus_lankester = Event(
            'betty-demo-birth-of-dirk-jacobus-lankester', Birth(),
            Date(1897, 8, 25))
        birth_of_dirk_jacobus_lankester.place = amsterdam
        self._app.ancestry.entities.append(birth_of_dirk_jacobus_lankester)

        death_of_dirk_jacobus_lankester = Event(
            'betty-demo-death-of-dirk-jacobus-lankester', Death(),
            Date(1986, 8, 18))
        death_of_dirk_jacobus_lankester.place = amsterdam
        self._app.ancestry.entities.append(death_of_dirk_jacobus_lankester)

        dirk_jacobus_lankester = Person('betty-demo-dirk-jacobus-lankester')
        PersonName(dirk_jacobus_lankester, 'Dirk Jacobus', '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)
        dirk_jacobus_lankester.parents.append(david_marinus_lankester,
                                              geertruida_van_ling)
        self._app.ancestry.entities.append(dirk_jacobus_lankester)

        birth_of_marinus_david_lankester = Event(
            'betty-demo-birth-of-marinus-david', Birth(),
            DateRange(Date(1874, 1, 15),
                      Date(1874, 3, 21),
                      start_is_boundary=True,
                      end_is_boundary=True))
        birth_of_marinus_david_lankester.place = amsterdam
        self._app.ancestry.entities.append(birth_of_marinus_david_lankester)

        death_of_marinus_david_lankester = Event(
            'betty-demo-death-of-marinus-david', Death(), Date(1971))
        death_of_marinus_david_lankester.place = amsterdam
        self._app.ancestry.entities.append(death_of_marinus_david_lankester)

        marinus_david_lankester = Person('betty-demo-marinus-david-lankester')
        PersonName(marinus_david_lankester, 'Marinus David', 'Lankester')
        Presence(marinus_david_lankester, Subject(),
                 birth_of_marinus_david_lankester)
        Presence(marinus_david_lankester, Subject(),
                 death_of_marinus_david_lankester)
        marinus_david_lankester.parents.append(david_marinus_lankester,
                                               geertruida_van_ling)
        self._app.ancestry.entities.append(marinus_david_lankester)

        birth_of_jacoba_gesina_lankester = Event(
            'betty-demo-birth-of-jacoba-gesina', Birth(), Date(1900, 3, 14))
        birth_of_jacoba_gesina_lankester.place = amsterdam
        self._app.ancestry.entities.append(birth_of_jacoba_gesina_lankester)

        jacoba_gesina_lankester = Person('betty-demo-jacoba-gesina-lankester')
        PersonName(jacoba_gesina_lankester, 'Jacoba Gesina', 'Lankester')
        Presence(jacoba_gesina_lankester, Subject(),
                 birth_of_jacoba_gesina_lankester)
        jacoba_gesina_lankester.parents.append(david_marinus_lankester,
                                               geertruida_van_ling)
        self._app.ancestry.entities.append(jacoba_gesina_lankester)

        jannigje_palsen = Person('betty-demo-jannigje-palsen')
        PersonName(jannigje_palsen, 'Jannigje', 'Palsen')
        Presence(jannigje_palsen, Subject(),
                 marriage_of_dirk_jacobus_lankester_and_jannigje_palsen)
        self._app.ancestry.entities.append(jannigje_palsen)

        marriage_of_johan_de_boer_and_liberta_lankester = Event(
            'betty-demo-marriage-of-johan-de-boer-and-liberta-lankester',
            Marriage(), Date(1953, 6, 19))
        marriage_of_johan_de_boer_and_liberta_lankester.place = amsterdam
        self._app.ancestry.entities.append(
            marriage_of_johan_de_boer_and_liberta_lankester)

        cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam = Citation(
            'betty-demo-birth-of-liberta-lankester-from-bevolkingsregister-amsterdam',
            bevolkingsregister_amsterdam)
        cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam.location = 'Amsterdam'
        self._app.ancestry.entities.append(
            cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam)

        birth_of_liberta_lankester = Event(
            'betty-demo-birth-of-liberta-lankester', Birth(),
            Date(1929, 12, 22))
        birth_of_liberta_lankester.place = amsterdam
        birth_of_liberta_lankester.citations.append(
            cite_birth_of_liberta_lankester_from_bevolkingsregister_amsterdam)
        self._app.ancestry.entities.append(birth_of_liberta_lankester)

        death_of_liberta_lankester = Event(
            'betty-demo-death-of-liberta-lankester', Death(),
            Date(2015, 1, 17))
        death_of_liberta_lankester.place = amsterdam
        death_of_liberta_lankester.citations.append(cite_first_person_account)
        self._app.ancestry.entities.append(death_of_liberta_lankester)

        liberta_lankester = Person('betty-demo-liberta-lankester')
        PersonName(liberta_lankester, 'Liberta', 'Lankester')
        PersonName(liberta_lankester, 'Betty')
        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)
        liberta_lankester.parents.append(dirk_jacobus_lankester,
                                         jannigje_palsen)
        self._app.ancestry.entities.append(liberta_lankester)

        birth_of_johan_de_boer = Event('betty-demo-birth-of-johan-de-boer',
                                       Birth(), Date(1930, 6, 20))
        birth_of_johan_de_boer.place = amsterdam
        self._app.ancestry.entities.append(birth_of_johan_de_boer)

        death_of_johan_de_boer = Event('betty-demo-death-of-johan-de-boer',
                                       Death(), Date(1999, 3, 10))
        death_of_johan_de_boer.place = amsterdam
        death_of_johan_de_boer.citations.append(cite_first_person_account)
        self._app.ancestry.entities.append(death_of_johan_de_boer)

        johan_de_boer = Person('betty-demo-johan-de-boer')
        PersonName(johan_de_boer, 'Johan', 'De Boer')
        PersonName(johan_de_boer, '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)
        self._app.ancestry.entities.append(johan_de_boer)

        parent_of_bart_feenstra_child_of_liberta_lankester = Person(
            'betty-demo-parent-of-bart-feenstra-child-of-liberta-lankester')
        PersonName(parent_of_bart_feenstra_child_of_liberta_lankester,
                   'Bart\'s parent')
        parent_of_bart_feenstra_child_of_liberta_lankester.parents.append(
            johan_de_boer, liberta_lankester)
        self._app.ancestry.entities.append(
            parent_of_bart_feenstra_child_of_liberta_lankester)

        bart_feenstra = Person('betty-demo-bart-feenstra')
        PersonName(bart_feenstra, 'Bart', 'Feenstra')
        bart_feenstra.parents.append(
            parent_of_bart_feenstra_child_of_liberta_lankester)
        self._app.ancestry.entities.append(bart_feenstra)