"""Integrate Betty with `Wikipedia <https://wikipedia.org>`_."""
from __future__ import annotations
import logging
from asyncio import gather
from pathlib import Path
from typing import TYPE_CHECKING, Self, final
from jinja2 import pass_context
from typing_extensions import override
from betty.concurrent import RateLimiter
from betty.fetch import FetchError
from betty.jinja2 import Filters, Globals, Jinja2Provider, context_localizer
from betty.locale import negotiate_locale
from betty.locale.localizable import _
from betty.plugin import ShorthandPluginBase
from betty.project.extension import ConfigurableExtension
from betty.project.extension.wikipedia.config import WikipediaConfiguration
from betty.project.load import PostLoadAncestryEvent
from betty.service import service
from betty.wikipedia import NotAPageError, parse_page_url
from betty.wikipedia.client import RATE_LIMIT, Client, Summary
from betty.wikipedia.copyright_notice import WikipediaContributors
from betty.wikipedia.populator import Populator
if TYPE_CHECKING:
from collections.abc import Iterable
from jinja2.runtime import Context
from betty.ancestry.link import Link
from betty.copyright_notice import CopyrightNotice
from betty.event_dispatcher import EventHandlerRegistry
from betty.project import Project
async def _populate_ancestry(event: PostLoadAncestryEvent) -> None:
project = event.project
extensions = await project.extensions
wikipedia = extensions[Wikipedia]
populator = Populator(
project.ancestry,
list(project.configuration.locales.keys()),
await project.localizers,
await wikipedia.client,
await project.copyright_notice_repository.new_target(WikipediaContributors),
)
await populator.populate()
[docs]
@final
class Wikipedia(
ShorthandPluginBase, ConfigurableExtension[WikipediaConfiguration], Jinja2Provider
):
"""
Integrates Betty with `Wikipedia <https://wikipedia.org>`_.
"""
@service
async def rate_limiter(self) -> RateLimiter:
"""
The Wikipedia API rate limiter.
"""
return RateLimiter(
RATE_LIMIT, manager=self._project.app.multiprocessing_manager
)
@service
async def client(self) -> Client:
"""
The Wikipedia query API client.
"""
return Client(await self.project.app.fetcher, await self.rate_limiter)
@override
@property
def globals(self) -> Globals:
return {
"wikipedia_contributors_copyright_notice": self._wikipedia_contributors_copyright_notice
}
@override
@property
def filters(self) -> Filters:
return {
"wikipedia": self.filter_wikipedia_links,
}
[docs]
@pass_context
async def filter_wikipedia_links(
self, context: Context, links: Iterable[Link]
) -> Iterable[Summary]:
"""
Given a sequence of links, return any Wikipedia summaries for them.
"""
return filter(
None,
await gather(
*(
self._filter_wikipedia_link(
context_localizer(context).locale,
link,
)
for link in links
)
),
)