Skip to content

Commit

Permalink
FileBasedConfiguration must no longer create its own project directories
Browse files Browse the repository at this point in the history
  • Loading branch information
bartfeenstra committed Jul 6, 2024
1 parent fa921af commit dca53b1
Show file tree
Hide file tree
Showing 47 changed files with 1,706 additions and 1,582 deletions.
22 changes: 5 additions & 17 deletions betty/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
from betty.locale import LocalizerRepository, get_data, DEFAULT_LOCALE, Localizer
from betty.locale.localizable import _
from betty.serde.dump import minimize, void_none, Dump, VoidableDump
from betty.warnings import deprecate

if TYPE_CHECKING:
from betty.cache import Cache
Expand All @@ -48,33 +47,22 @@ class AppConfiguration(FileBasedConfiguration):

def __init__(
self,
configuration_directory_path: Path | None = None,
configuration_file_path: Path,
*,
locale: str | None = None,
):
if configuration_directory_path is None:
deprecate(
f"Initializing {type(self)} without a configuration directory path is deprecated as of Betty 0.3.3, and will be removed in Betty 0.4.x.",
stacklevel=2,
)
configuration_directory_path = CONFIGURATION_DIRECTORY_PATH
super().__init__()
self._configuration_directory_path = configuration_directory_path
super().__init__(configuration_file_path)
self._locale: str | None = locale

@override
@property
def configuration_file_path(self) -> Path:
return self._configuration_directory_path / "app.json"
return self._configuration_file_path

@configuration_file_path.setter
def configuration_file_path(self, __: Path) -> None:
pass

@configuration_file_path.deleter
def configuration_file_path(self) -> None:
pass

@property
def locale(self) -> str | None:
"""
Expand Down Expand Up @@ -148,7 +136,7 @@ async def new_from_environment(cls) -> AsyncIterator[Self]:
Create a new application from the environment.
"""
yield cls(
AppConfiguration(CONFIGURATION_DIRECTORY_PATH),
AppConfiguration(CONFIGURATION_DIRECTORY_PATH / "app.json"),
Path(environ.get("BETTY_CACHE_DIRECTORY", HOME_DIRECTORY_PATH / "cache")),
cache_factory=lambda app: PickledFileCache[Any](
app.localizer, app._cache_directory_path
Expand All @@ -169,7 +157,7 @@ async def new_temporary(cls) -> AsyncIterator[Self]:
TemporaryDirectory() as cache_directory_path_str,
):
yield cls(
AppConfiguration(Path(configuration_directory_path_str)),
AppConfiguration(Path(configuration_directory_path_str) / "app.json"),
Path(cache_directory_path_str),
cache_factory=lambda app: NoOpCache(),
)
Expand Down
4 changes: 3 additions & 1 deletion betty/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ def _project(
) -> Project:
_init_ctx_app(ctx)
app = ctx.obj["app"]
project = Project(app)
project: Project = ctx.with_resource( # type: ignore[attr-defined]
SynchronizedContextManager(Project.new_temporary(app))
)
wait_to_thread(_read_project_configuration(project, configuration_file_path))
ctx.with_resource( # type: ignore[attr-defined]
SynchronizedContextManager(project)
Expand Down
35 changes: 4 additions & 31 deletions betty/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
from collections import OrderedDict
from collections.abc import Callable
from contextlib import chdir
from pathlib import Path
from reprlib import recursive_repr
from tempfile import TemporaryDirectory
from typing import (
Generic,
Iterable,
Expand All @@ -24,7 +22,6 @@
Any,
Sequence,
overload,
cast,
Self,
TypeAlias,
TYPE_CHECKING,
Expand All @@ -45,6 +42,7 @@
from betty.typing import Void

if TYPE_CHECKING:
from pathlib import Path
from _weakref import ReferenceType


Expand Down Expand Up @@ -112,10 +110,9 @@ class FileBasedConfiguration(Configuration):
Any configuration that is stored in a file on disk.
"""

def __init__(self):
def __init__(self, configuration_file_path: Path):
super().__init__()
self._configuration_directory: TemporaryDirectory | None = None # type: ignore[type-arg]
self._configuration_file_path: Path | None = None
self._configuration_file_path = configuration_file_path
self._autowrite = False

@property
Expand Down Expand Up @@ -196,28 +193,12 @@ async def read(self, configuration_file_path: Path | None = None) -> None:
)
)

def __del__(self) -> None:
if (
hasattr(self, "_configuration_directory")
and self._configuration_directory is not None
):
self._configuration_directory.cleanup()

@property
def configuration_file_path(self) -> Path:
"""
The path to the configuration's file.
"""
if self._configuration_file_path is None:
if self._configuration_directory is None:
self._configuration_directory = TemporaryDirectory()
wait_to_thread(
self._write(
Path(self._configuration_directory.name)
/ f"{type(self).__name__}.json"
)
)
return cast(Path, self._configuration_file_path)
return self._configuration_file_path

@configuration_file_path.setter
def configuration_file_path(self, configuration_file_path: Path) -> None:
Expand All @@ -227,14 +208,6 @@ def configuration_file_path(self, configuration_file_path: Path) -> None:
formats.format_for(configuration_file_path.suffix[1:])
self._configuration_file_path = configuration_file_path

@configuration_file_path.deleter
def configuration_file_path(self) -> None:
if self._autowrite:
raise RuntimeError(
"Cannot remove the configuration file path while autowrite is enabled."
)
self._configuration_file_path = None


ConfigurationKey: TypeAlias = SupportsIndex | Hashable | type[Any]
_ConfigurationKeyT = TypeVar("_ConfigurationKeyT", bound=ConfigurationKey)
Expand Down
76 changes: 38 additions & 38 deletions betty/extension/demo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,43 +512,43 @@ async def demo_project(app: App) -> AsyncIterator[Project]:
"""
from betty.extension import CottonCandy

project = Project(app)
project.configuration.name = Demo.name()
project.configuration.extensions.append(ExtensionConfiguration(Demo))
project.configuration.extensions.append(
ExtensionConfiguration(
CottonCandy,
extension_configuration=CottonCandyConfiguration(
featured_entities=[
EntityReference(Place, "betty-demo-amsterdam"),
EntityReference(Person, "betty-demo-liberta-lankester"),
EntityReference(Place, "betty-demo-netherlands"),
],
async with Project.new_temporary(app) as project:
project.configuration.name = Demo.name()
project.configuration.extensions.append(ExtensionConfiguration(Demo))
project.configuration.extensions.append(
ExtensionConfiguration(
CottonCandy,
extension_configuration=CottonCandyConfiguration(
featured_entities=[
EntityReference(Place, "betty-demo-amsterdam"),
EntityReference(Person, "betty-demo-liberta-lankester"),
EntityReference(Place, "betty-demo-netherlands"),
],
),
)
)
# Include all of the translations Betty ships with.
project.configuration.locales.replace(
LocaleConfiguration(
"en-US",
alias="en",
),
LocaleConfiguration(
"nl-NL",
alias="nl",
),
LocaleConfiguration(
"fr-FR",
alias="fr",
),
LocaleConfiguration(
"uk",
alias="uk",
),
LocaleConfiguration(
"de-DE",
alias="de",
),
)
)
# Include all of the translations Betty ships with.
project.configuration.locales.replace(
LocaleConfiguration(
"en-US",
alias="en",
),
LocaleConfiguration(
"nl-NL",
alias="nl",
),
LocaleConfiguration(
"fr-FR",
alias="fr",
),
LocaleConfiguration(
"uk",
alias="uk",
),
LocaleConfiguration(
"de-DE",
alias="de",
),
)
async with project:
yield project
async with project:
yield project
6 changes: 4 additions & 2 deletions betty/extension/nginx/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ async def start(self) -> None:
TemporaryDirectory() # type: ignore[arg-type]
)

isolated_project = await self._exit_stack.enter_async_context(
Project(self._project.app, ancestry=self._project.ancestry)
isolated_project: Project = await self._exit_stack.enter_async_context(
Project.new_temporary(self._project.app, ancestry=self._project.ancestry)
)
isolated_project.configuration.autowrite = False
isolated_project.configuration.configuration_file_path = (
Expand All @@ -55,6 +55,8 @@ async def start(self) -> None:
# Work around https://github.com/bartfeenstra/betty/issues/1056.
isolated_project.extensions[Nginx].configuration.https = False

await self._exit_stack.enter_async_context(isolated_project)

nginx_configuration_file_path = Path(output_directory_path_str) / "nginx.conf"
docker_directory_path = Path(output_directory_path_str)
dockerfile_file_path = docker_directory_path / "Dockerfile"
Expand Down
24 changes: 12 additions & 12 deletions betty/extension/webpack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,18 @@ async def _prebuild_webpack_assets() -> None:
"""
async with App.new_temporary() as app, app:
job_context = Context()
project = Project(app)
project.configuration.extensions.enable(Webpack)
project.configuration.extensions.enable(
*{
extension_type
for extension_type in discover_extension_types()
if issubclass(extension_type, WebpackEntryPointProvider)
}
)
async with project:
webpack = project.extensions[Webpack]
await webpack.prebuild(job_context=job_context)
async with Project.new_temporary(app) as project:
project.configuration.extensions.enable(Webpack)
project.configuration.extensions.enable(
*{
extension_type
for extension_type in discover_extension_types()
if issubclass(extension_type, WebpackEntryPointProvider)
}
)
async with project:
webpack = project.extensions[Webpack]
await webpack.prebuild(job_context=job_context)


class WebpackEntryPointProvider:
Expand Down
16 changes: 7 additions & 9 deletions betty/gui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from betty.gui.text import Text
from betty.gui.window import BettyMainWindow
from betty.locale.localizable import plain, Localizable, _
from betty.project import Project
from betty.project import Project, ProjectConfiguration


class BettyPrimaryWindow(BettyMainWindow):
Expand Down Expand Up @@ -214,10 +214,9 @@ def open_project(self) -> None:
)
if not configuration_file_path_str:
return
project = Project(self._app)
wait_to_thread(
project.configuration.read(Path(configuration_file_path_str))
)
configuration = ProjectConfiguration(Path(configuration_file_path_str))
wait_to_thread(configuration.read())
project = Project(self._app, configuration)
project_window = ProjectWindow(project)
project_window.show()
self.close()
Expand All @@ -237,10 +236,9 @@ def new_project(self) -> None:
)
if not configuration_file_path_str:
return
project = Project(self._app)
wait_to_thread(
project.configuration.write(Path(configuration_file_path_str))
)
configuration = ProjectConfiguration(Path(configuration_file_path_str))
wait_to_thread(configuration.write())
project = Project(self._app, configuration)
project_window = ProjectWindow(project)
project_window.show()
self.close()
Expand Down
Loading

0 comments on commit dca53b1

Please sign in to comment.