Skip to content

Commit

Permalink
Make Configurable require Configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
bartfeenstra committed Oct 19, 2024
1 parent 01c80be commit e5158e5
Show file tree
Hide file tree
Showing 11 changed files with 39 additions and 67 deletions.
3 changes: 1 addition & 2 deletions betty/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ def __init__(
cache_factory: Callable[[Self], Cache[Any]],
fetcher: Fetcher | None = None,
):
super().__init__()
self._configuration = configuration
super().__init__(configuration=configuration)
self._assets: AssetRepository | None = None
self._localization_initialized = False
self._localizer: Localizer | None = None
Expand Down
10 changes: 4 additions & 6 deletions betty/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from collections.abc import Callable
from contextlib import chdir
from typing import Generic, TypeVar, TypeAlias, TYPE_CHECKING
from typing import Generic, TypeVar, TypeAlias, TYPE_CHECKING, Any

import aiofiles
from aiofiles.os import makedirs
Expand Down Expand Up @@ -42,17 +42,15 @@ class Configurable(Generic[_ConfigurationT]):
Any configurable object.
"""

_configuration: _ConfigurationT
def __init__(self, *args: Any, configuration: _ConfigurationT, **kwargs: Any):
super().__init__(*args, **kwargs)
self._configuration = configuration

@property
def configuration(self) -> _ConfigurationT:
"""
The object's configuration.
"""
if not hasattr(self, "_configuration"):
raise RuntimeError(
f"{self} has no configuration. {type(self)}.__init__() must ensure it is set."
)
return self._configuration


Expand Down
3 changes: 1 addition & 2 deletions betty/project/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,8 @@ def __init__(
*,
ancestry: Ancestry,
):
super().__init__()
super().__init__(configuration=configuration)
self._app = app
self._configuration = configuration
self._ancestry = ancestry

self._assets: AssetRepository | None = None
Expand Down
11 changes: 1 addition & 10 deletions betty/project/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,7 @@ def __init__(
super().__init__()
self._extension_type = extension_type
self._enabled = enabled
if extension_configuration is None and issubclass(
extension_type, ConfigurableExtension
):
extension_configuration = extension_type.default_configuration()
self._set_extension_configuration(extension_configuration)
self._extension_configuration = extension_configuration

@property
def extension_type(self) -> type[Extension]:
Expand All @@ -296,11 +292,6 @@ def extension_configuration(self) -> Configuration | None:
"""
return self._extension_configuration

def _set_extension_configuration(
self, extension_configuration: Configuration | None
) -> None:
self._extension_configuration = extension_configuration

@override
def load(self, dump: Dump) -> None:
assert_record(
Expand Down
17 changes: 4 additions & 13 deletions betty/project/extension/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from __future__ import annotations

from abc import abstractmethod
from typing import TypeVar, TYPE_CHECKING, Generic, Self, Sequence

from typing_extensions import override
Expand Down Expand Up @@ -113,23 +112,15 @@ class Theme(Extension):


class ConfigurableExtension(
Extension, Generic[_ConfigurationT], Configurable[_ConfigurationT]
Configurable[_ConfigurationT], Extension, Generic[_ConfigurationT]
):
"""
A configurable extension.
"""

def __init__(self, project: Project):
super().__init__(project)
self._configuration = self.default_configuration()

@classmethod
@abstractmethod
def default_configuration(cls) -> _ConfigurationT:
"""
Get this extension's default configuration.
"""
pass
# @todo We need this?
def __init__(self, project: Project, *, configuration: _ConfigurationT):
super().__init__(project, configuration=configuration)


async def sort_extension_type_graph(
Expand Down
16 changes: 9 additions & 7 deletions betty/project/extension/cotton_candy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,14 @@ class CottonCandy(
_plugin_description = _("Cotton Candy is Betty's default theme.")

@private
def __init__(self, project: Project, public_css_paths: Sequence[str]):
super().__init__(project)
def __init__(
self,
project: Project,
public_css_paths: Sequence[str],
*,
configuration: CottonCandyConfiguration,
):
super().__init__(project, configuration=configuration)
self._public_css_paths = public_css_paths

@override
Expand All @@ -137,6 +143,7 @@ async def new_for_project(cls, project: Project) -> Self:
return cls(
project,
[static_url_generator.generate("/css/cotton-candy.css")],
configuration=CottonCandyConfiguration(),
)

@override
Expand Down Expand Up @@ -180,11 +187,6 @@ def webpack_entry_point_cache_keys(self) -> Sequence[str]:
def public_css_paths(self) -> Sequence[str]:
return self._public_css_paths

@override
@classmethod
def default_configuration(cls) -> CottonCandyConfiguration:
return CottonCandyConfiguration()

@override
@property
def filters(self) -> Filters:
Expand Down
9 changes: 5 additions & 4 deletions betty/project/extension/gramps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@

from __future__ import annotations

from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Self
from typing import final

from typing_extensions import override

from betty.project.extension.gramps.config import GrampsConfiguration
from betty.gramps.loader import GrampsLoader
from betty.locale.localizable import static, _
from betty.plugin import ShorthandPluginBase
from betty.project.extension import ConfigurableExtension
from betty.project.extension.gramps.config import GrampsConfiguration
from betty.project.load import LoadAncestryEvent

if TYPE_CHECKING:
from betty.project import Project
from betty.event_dispatcher import EventHandlerRegistry


Expand Down Expand Up @@ -65,8 +66,8 @@ class Gramps(ShorthandPluginBase, ConfigurableExtension[GrampsConfiguration]):

@override
@classmethod
def default_configuration(cls) -> GrampsConfiguration:
return GrampsConfiguration()
async def new_for_project(cls, project: Project) -> Self:
return cls(project, configuration=GrampsConfiguration())

@override
def register_event_handlers(self, registry: EventHandlerRegistry) -> None:
Expand Down
10 changes: 4 additions & 6 deletions betty/project/extension/wikipedia/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ def __init__(
self,
project: Project,
wikipedia_contributors_copyright_notice: CopyrightNotice,
*,
configuration: WikipediaConfiguration,
):
super().__init__(project)
super().__init__(project, configuration=configuration)
self._wikipedia_contributors_copyright_notice = (
wikipedia_contributors_copyright_notice
)
Expand All @@ -67,6 +69,7 @@ async def new_for_project(cls, project: Project) -> Self:
return cls(
project,
await project.copyright_notices.new_target("wikipedia-contributors"),
configuration=WikipediaConfiguration(),
)

_plugin_id = "wikipedia"
Expand Down Expand Up @@ -147,8 +150,3 @@ async def _filter_wikipedia_link(self, locale: str, link: Link) -> Summary | Non
@classmethod
def assets_directory_path(cls) -> Path | None:
return Path(__file__).parent / "assets"

@override
@classmethod
def default_configuration(cls) -> WikipediaConfiguration:
return WikipediaConfiguration()
6 changes: 3 additions & 3 deletions betty/test_utils/project/extension/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Test utilities for :py:mod:`betty.project.extension`.
"""

from typing import TypeVar, Generic
from typing import TypeVar, Generic, Self

from typing_extensions import override

Expand Down Expand Up @@ -122,5 +122,5 @@ class DummyConfigurableExtension(

@override
@classmethod
def default_configuration(cls) -> DummyConfigurableExtensionConfiguration:
return DummyConfigurableExtensionConfiguration()
async def new_for_project(cls, project: Project) -> Self:
return cls(project, configuration=DummyConfigurableExtensionConfiguration())
13 changes: 3 additions & 10 deletions betty/tests/config/test___init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,11 @@

class TestConfigurable:
class _DummyConfigurable(Configurable[DummyConfiguration]):
def __init__(self, configuration: DummyConfiguration | None = None):
if configuration is not None:
self._configuration = configuration
pass

def test_configuration_without_configuration(self) -> None:
sut = self._DummyConfigurable()
with pytest.raises(RuntimeError):
sut.configuration # noqa B018

def test_configuration_with_configuration(self) -> None:
def test_configuration(self) -> None:
configuration = DummyConfiguration()
sut = self._DummyConfigurable(configuration)
sut = self._DummyConfigurable(configuration=configuration)
assert sut.configuration is configuration


Expand Down
8 changes: 4 additions & 4 deletions betty/tests/project/test___init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ async def test___iter___with_extensions_in_a_single_batch(
) -> None:
async with Project.new_temporary(new_temporary_app) as project, project:
extension_one = DummyExtension(project)
extension_two = DummyConfigurableExtension(project)
extension_two = await DummyConfigurableExtension.new_for_project(project)
sut = ProjectExtensions([[extension_one, extension_two]])
actual = [list(batch) for batch in iter(sut)]
assert len(actual) == 1
Expand All @@ -635,7 +635,7 @@ async def test___iter___with_extensions_in_multiple_batches(
) -> None:
async with Project.new_temporary(new_temporary_app) as project, project:
extension_one = DummyExtension(project)
extension_two = DummyConfigurableExtension(project)
extension_two = await DummyConfigurableExtension.new_for_project(project)
sut = ProjectExtensions([[extension_one], [extension_two]])
actual = [list(batch) for batch in iter(sut)]
assert len(actual) == 2
Expand All @@ -653,7 +653,7 @@ async def test_flatten_with_extensions_in_a_single_batch(
) -> None:
async with Project.new_temporary(new_temporary_app) as project, project:
extension_one = DummyExtension(project)
extension_two = DummyConfigurableExtension(project)
extension_two = await DummyConfigurableExtension.new_for_project(project)
sut = ProjectExtensions([[extension_one, extension_two]])
actual = list(sut.flatten())
assert len(actual) == 2
Expand All @@ -665,7 +665,7 @@ async def test_flatten_with_extensions_in_multiple_batches(
) -> None:
async with Project.new_temporary(new_temporary_app) as project, project:
extension_one = DummyExtension(project)
extension_two = DummyConfigurableExtension(project)
extension_two = await DummyConfigurableExtension.new_for_project(project)
sut = ProjectExtensions([[extension_one], [extension_two]])
actual = list(sut.flatten())
assert len(actual) == 2
Expand Down

0 comments on commit e5158e5

Please sign in to comment.