Skip to content

Commit

Permalink
Make Configuration.load() an instance method
Browse files Browse the repository at this point in the history
  • Loading branch information
bartfeenstra committed Jun 26, 2024
1 parent bc15a29 commit 342c98c
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 401 deletions.
14 changes: 2 additions & 12 deletions betty/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,20 +151,10 @@ def update(self, other: Self) -> None:
self._dispatch_change()

@override
@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
if configuration is None:
configuration = cls()
def load(self, dump: Dump) -> None:
assert_record(
OptionalField(
"locale", assert_str() | assert_setattr(configuration, "locale")
)
OptionalField("locale", assert_str() | assert_setattr(self, "locale"))
)(dump)
return configuration

@override
def dump(self) -> VoidableDump:
Expand Down
103 changes: 43 additions & 60 deletions betty/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from betty.serde.dump import Dumpable, Dump, minimize, VoidableDump, Void
from betty.serde.error import SerdeErrorCollection
from betty.serde.format import FormatRepository
from betty.serde.load import Assertion, assert_dict, assert_mapping, assert_sequence
from betty.serde.load import assert_dict, assert_sequence

if TYPE_CHECKING:
from _weakref import ReferenceType
Expand Down Expand Up @@ -90,38 +90,35 @@ def remove_on_change(self, listener: ConfigurationListener) -> None:
"""
self._on_change_listeners.append(self._prepare_listener(listener))

def update(self, other: Self) -> None:
def clone(self) -> Self:
"""
Update this configuration with the values from ``other``.
Clone the configuration into a new instance.
This is a deep clone/copy for any data structures that are copied by
reference and are owned by this instance, including but not limited to:
- other :py:class:`betty.config.Configuration` instances
- standard Python data structures such as lists and dictionaries
Data structures that are copied by reference by are **not** owned by this
instance **MUST NOT** be cloned/copied.
Clones **MUST** be identical. This means that any dependencies, including
environment variables, **MUST** be injected.
"""
raise NotImplementedError(repr(self))

@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
def update(self, other: Self) -> None:
"""
Load dumped configuration into a new configuration instance.
Update this configuration with the values from ``other``.
"""
raise NotImplementedError(repr(cls))
raise NotImplementedError(repr(self))

@classmethod
def assert_load(
cls: type[_ConfigurationT], configuration: _ConfigurationT | None = None
) -> Assertion[Dump, _ConfigurationT]:
"""
Assert that the dumped configuration can be loaded.
def load(self, dump: Dump) -> None:
"""
Load dumped configuration.
def _assert_load(dump: Dump) -> _ConfigurationT:
return cls.load(dump, configuration)

_assert_load.__qualname__ = (
f"{_assert_load.__qualname__} for {cls.__module__}.{cls.__qualname__}.load"
)
return _assert_load
:return: A new instance of self, with the configuration from the dump loaded into it.
"""
raise NotImplementedError(repr(self))


_ConfigurationT = TypeVar("_ConfigurationT", bound=Configuration)
Expand Down Expand Up @@ -213,13 +210,11 @@ async def read(self, configuration_file_path: Path | None = None) -> None:
configuration_file_path=str(self.configuration_file_path.resolve()),
)
):
loaded_configuration = self.load(
self.load(
formats.format_for(self.configuration_file_path.suffix[1:]).load(
read_configuration
),
self,
)
)
self.update(loaded_configuration)

def __del__(self) -> None:
if (
Expand Down Expand Up @@ -377,9 +372,13 @@ def to_keys(self, *indices: int | slice) -> Iterator[_ConfigurationKeyT]:
for index in sorted(unique_indices):
yield self.to_key(index)

@classmethod
def _item_type(cls) -> type[_ConfigurationT]:
raise NotImplementedError(repr(cls))
def load_item(self, dump: Dump) -> _ConfigurationT:
"""
Create and load a new item from the given dump, or raise an assertion error.
:raise betty.serde.load.AssertionFailed: Raised when the dump is invalid and cannot be loaded.
"""
raise NotImplementedError(repr(self))

def keys(self) -> Iterator[_ConfigurationKeyT]:
"""
Expand Down Expand Up @@ -492,19 +491,8 @@ def update(self, other: Self) -> None:
self.append(*other)

@override
@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
if configuration is None:
configuration = cls()
else:
configuration._clear_without_dispatch()
with SerdeErrorCollection().assert_valid():
configuration.append(*assert_sequence(cls._item_type().load)(dump))
return configuration
def load(self, dump: Dump) -> None:
self.append(*assert_sequence(self.load_item)(dump))

@override
def dump(self) -> VoidableDump:
Expand Down Expand Up @@ -644,20 +632,16 @@ def replace(self, *values: _ConfigurationT) -> None:
self.move_to_beginning(*other_keys)

@override
@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
if configuration is None:
configuration = cls()
dict_dump = assert_dict()(dump)
mapping = assert_mapping(cls._item_type().load)(
{key: cls._load_key(value, key) for key, value in dict_dump.items()}
def load(self, dump: Dump) -> None:
self.clear()
self.append(
*assert_sequence(self.load_item)(
[
self._load_key(item_value_dump, item_key_dump)
for item_key_dump, item_value_dump in assert_dict()(dump).items()
]
)
)
configuration.replace(*mapping.values())
return configuration

@override
def dump(self) -> VoidableDump:
Expand Down Expand Up @@ -749,13 +733,12 @@ def _move_by_offset(
def _get_key(self, configuration: _ConfigurationT) -> _ConfigurationKeyT:
raise NotImplementedError(repr(self))

@classmethod
def _load_key(
cls,
self,
item_dump: Dump,
key_dump: str,
) -> Dump:
raise NotImplementedError(repr(cls))
raise NotImplementedError(repr(self))

def _dump_key(self, item_dump: VoidableDump) -> tuple[VoidableDump, str]:
raise NotImplementedError(repr(self))
Expand Down
63 changes: 9 additions & 54 deletions betty/extension/cotton_candy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,8 @@ def update(self, other: Self) -> None:
self.hex = other.hex

@override
@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
hex_value = assert_str()(dump)
if configuration is None:
configuration = cls(hex_value)
else:
configuration.hex = hex_value
return configuration
def load(self, dump: Dump) -> None:
self._hex = assert_str()(dump)

@override
def dump(self) -> VoidableDump:
Expand Down Expand Up @@ -193,50 +183,15 @@ def logo(self, logo: Path | None) -> None:
self._dispatch_change()

@override
@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
if configuration is None:
configuration = cls()
def load(self, dump: Dump) -> None:
assert_record(
OptionalField(
"featured_entities",
configuration._featured_entities.assert_load(
configuration._featured_entities
),
),
OptionalField(
"primary_inactive_color",
configuration._primary_inactive_color.assert_load(
configuration._primary_inactive_color
),
),
OptionalField(
"primary_active_color",
configuration._primary_active_color.assert_load(
configuration._primary_active_color
),
),
OptionalField(
"link_inactive_color",
configuration._link_inactive_color.assert_load(
configuration._link_inactive_color
),
),
OptionalField(
"link_active_color",
configuration._link_active_color.assert_load(
configuration._link_active_color
),
),
OptionalField(
"logo", assert_path() | assert_setattr(configuration, "logo")
),
OptionalField("featured_entities", self.featured_entities.load),
OptionalField("primary_inactive_color", self.primary_inactive_color.load),
OptionalField("primary_active_color", self.primary_active_color.load),
OptionalField("link_inactive_color", self.link_inactive_color.load),
OptionalField("link_active_color", self.link_active_color.load),
OptionalField("logo", assert_path() | assert_setattr(self, "logo")),
)(dump)
return configuration

@override
def dump(self) -> VoidableDump:
Expand Down
38 changes: 8 additions & 30 deletions betty/extension/gramps/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,10 @@ def file_path(self, file_path: Path | None) -> None:
self._file_path = file_path

@override
@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
if configuration is None:
configuration = cls()
def load(self, dump: Dump) -> None:
assert_record(
RequiredField(
"file", assert_path() | assert_setattr(configuration, "file_path")
)
RequiredField("file", assert_path() | assert_setattr(self, "file_path"))
)(dump)
return configuration

@override
def dump(self) -> VoidableDump:
Expand All @@ -84,9 +74,10 @@ class FamilyTreeConfigurationSequence(ConfigurationSequence[FamilyTreeConfigurat
"""

@override
@classmethod
def _item_type(cls) -> type[FamilyTreeConfiguration]:
return FamilyTreeConfiguration
def load_item(self, dump: Dump) -> FamilyTreeConfiguration:
item = FamilyTreeConfiguration()
item.load(dump)
return item


class GrampsConfiguration(Configuration):
Expand Down Expand Up @@ -115,21 +106,8 @@ def update(self, other: Self) -> None:
self._family_trees.update(other._family_trees)

@override
@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
if configuration is None:
configuration = cls()
assert_record(
OptionalField(
"family_trees",
configuration._family_trees.assert_load(configuration.family_trees),
)
)(dump)
return configuration
def load(self, dump: Dump) -> None:
assert_record(OptionalField("family_trees", self.family_trees.load))(dump)

@override
def dump(self) -> VoidableDump:
Expand Down
15 changes: 3 additions & 12 deletions betty/extension/nginx/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,26 +66,17 @@ def update(self, other: Self) -> None:
self._dispatch_change()

@override
@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
if configuration is None:
configuration = cls()
def load(self, dump: Dump) -> None:
assert_record(
OptionalField(
"https",
assert_or(assert_bool(), assert_none())
| assert_setattr(configuration, "https"),
assert_or(assert_bool(), assert_none()) | assert_setattr(self, "https"),
),
OptionalField(
"www_directory_path",
assert_str() | assert_setattr(configuration, "www_directory_path"),
assert_str() | assert_setattr(self, "www_directory_path"),
),
)(dump)
return configuration

@override
def dump(self) -> VoidableDump:
Expand Down
12 changes: 2 additions & 10 deletions betty/extension/wikipedia/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,13 @@ def update(self, other: Self) -> None:
self._dispatch_change()

@override
@classmethod
def load(
cls,
dump: Dump,
configuration: Self | None = None,
) -> Self:
if configuration is None:
configuration = cls()
def load(self, dump: Dump) -> None:
assert_record(
OptionalField(
"populate_images",
assert_bool() | assert_setattr(configuration, "populate_images"),
assert_bool() | assert_setattr(self, "populate_images"),
)
)(dump)
return configuration

@override
def dump(self) -> VoidableDump:
Expand Down
Loading

0 comments on commit 342c98c

Please sign in to comment.