diff --git a/betty/extension/demo/__init__.py b/betty/extension/demo/__init__.py index cdaa61fd4..b66e0e8f5 100644 --- a/betty/extension/demo/__init__.py +++ b/betty/extension/demo/__init__.py @@ -14,7 +14,7 @@ from betty.model.ancestry import Place, PlaceName, Person, Presence, Subject, PersonName, Link, Source, Citation, Event, \ Enclosure from betty.model.event_type import Marriage, Birth, Death -from betty.project import LocaleConfiguration, ExtensionConfiguration, EntityReference, ProjectConfiguration +from betty.project import LocaleConfiguration, ExtensionConfiguration, EntityReference, Project from betty.serve import Server, AppServer, NoPublicUrlBecauseServerNotStartedError @@ -29,12 +29,12 @@ def _load(self, *entities: Entity) -> None: self._app.project.ancestry.add(*entities) @classmethod - def project_configuration(cls) -> ProjectConfiguration: + def project(cls) -> Project: from betty.extension import CottonCandy, Demo - configuration = ProjectConfiguration() - configuration.extensions.append(ExtensionConfiguration(Demo)) - configuration.extensions.append(ExtensionConfiguration(CottonCandy, True, CottonCandyConfiguration( + project = Project(project_id=cls.name()) + project.configuration.extensions.append(ExtensionConfiguration(Demo)) + project.configuration.extensions.append(ExtensionConfiguration(CottonCandy, True, CottonCandyConfiguration( featured_entities=[ EntityReference(Place, 'betty-demo-amsterdam'), EntityReference(Person, 'betty-demo-liberta-lankester'), @@ -42,13 +42,13 @@ def project_configuration(cls) -> ProjectConfiguration: ], ))) # Include all of the translations Betty ships with. - configuration.locales.replace( + project.configuration.locales.replace( LocaleConfiguration('en-US', 'en'), LocaleConfiguration('nl-NL', 'nl'), LocaleConfiguration('fr-FR', 'fr'), LocaleConfiguration('uk', 'uk'), ) - return configuration + return project async def load(self) -> None: netherlands = Place( @@ -381,9 +381,8 @@ class DemoServer(Server): def __init__(self): from betty.extension import Demo - self._app = App() + self._app = App(None, Demo.project()) super().__init__(self._app.localizer) - self._app.project.configuration.update(Demo.project_configuration()) self._server: Server | None = None self._exit_stack = AsyncExitStack() diff --git a/betty/extension/npm/__init__.py b/betty/extension/npm/__init__.py index f69b435fc..2cf62efa5 100644 --- a/betty/extension/npm/__init__.py +++ b/betty/extension/npm/__init__.py @@ -1,6 +1,5 @@ from __future__ import annotations -import hashlib import logging import os import shutil @@ -198,7 +197,7 @@ async def install(self, extension_type: type[NpmBuilder & Extension], working_di def _get_cached_assets_build_directory_path(self, extension_type: type[NpmBuilder & Extension]) -> Path: path = self.cache_directory_path / extension_type.name() if extension_type.npm_cache_scope() == CacheScope.PROJECT: - path /= hashlib.md5(str(self.app.project.configuration.configuration_file_path).encode('utf-8')).hexdigest() + path /= self.app.project.id return path async def ensure_assets(self, extension: NpmBuilder & Extension) -> Path: diff --git a/betty/project.py b/betty/project.py index aaa1c8ab5..7f7bf3afe 100644 --- a/betty/project.py +++ b/betty/project.py @@ -1,5 +1,6 @@ from __future__ import annotations +import hashlib from contextlib import suppress from pathlib import Path from reprlib import recursive_repr @@ -769,19 +770,28 @@ def dump(self) -> VoidableDictDump[Dump]: class Project(Configurable[ProjectConfiguration]): - def __init__(self): + def __init__( + self, + *, + project_id: str | None = None, + ): super().__init__() + self._id = project_id self._configuration = ProjectConfiguration() self._ancestry = Ancestry() - def __getstate__(self) -> tuple[VoidableDump, Path, Ancestry]: - return self._configuration.dump(), self._configuration.configuration_file_path, self._ancestry + def __getstate__(self) -> tuple[str | None, VoidableDump, Path, Ancestry]: + return self._id, self._configuration.dump(), self._configuration.configuration_file_path, self._ancestry - def __setstate__(self, state: tuple[Dump, Path, Ancestry]) -> None: - dump, configuration_file_path, self._ancestry = state + def __setstate__(self, state: tuple[str | None, Dump, Path, Ancestry]) -> None: + self._id, dump, configuration_file_path, self._ancestry = state self._configuration = ProjectConfiguration.load(dump) self._configuration.configuration_file_path = configuration_file_path + @property + def id(self) -> str: + return self._id or hashlib.md5(str(self.configuration.configuration_file_path).encode('utf-8')).hexdigest() + @property def ancestry(self) -> Ancestry: return self._ancestry