Skip to content

Commit

Permalink
call evaluate_settings_once optionally when accessing settings
Browse files Browse the repository at this point in the history
Note:

This is dangerous in multithreading environments so a good solution is
required
  • Loading branch information
devkral committed Jan 6, 2025
1 parent 43cbc77 commit 951ba2e
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
### Added

- Add `evaluate_settings_once`.
- Add parameter `evaluate_settings_once_on_access`.

### Changed

Expand Down
5 changes: 5 additions & 0 deletions docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ It is internally used by `evaluate_settings_once` and will also set the `setting
Internally it is a property which sets the right flag. Either on the ContextVar or on the instance.
It is resetted when assigning settings and initial False for `with_settings`.


### `evaluate_settings_once_on_access` parameter

You can also call

## Other settings types

All of the assignment examples are also possible as settings_path parameter.
Expand Down
3 changes: 3 additions & 0 deletions monkay/_monkay_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

class MonkaySettings(Generic[SETTINGS]):
package: str | None
evaluate_settings_once_on_access: bool
_settings_evaluated: bool = False
settings_preloads_name: str
settings_extensions_name: str
Expand Down Expand Up @@ -73,6 +74,8 @@ def settings(self) -> SETTINGS:
raise RuntimeError(
"Settings are not set yet. Returned settings are None or settings_path is empty."
)
if self.evaluate_settings_once_on_access:
self.evaluate_settings_once(on_conflict="keep")
return settings

@settings.setter
Expand Down
5 changes: 4 additions & 1 deletion monkay/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(
settings_ctx_name: str = "monkay_settings_ctx",
extensions_applied_ctx_name: str = "monkay_extensions_applied_ctx",
skip_all_update: bool = False,
evaluate_settings_once_on_access: bool = False,
skip_getattr_fixup: bool = False,
evaluate_settings: bool = True,
pre_add_lazy_import_hook: None | PRE_ADD_LAZY_IMPORT_HOOK = None,
Expand All @@ -64,6 +65,7 @@ def __init__(
self.package = package or None

self._cached_imports: dict[str, Any] = {}
self.evaluate_settings_once_on_access = evaluate_settings_once_on_access
self.pre_add_lazy_import_hook = pre_add_lazy_import_hook
self.post_add_lazy_import_hook = post_add_lazy_import_hook
self.uncached_imports = set(uncached_imports)
Expand Down Expand Up @@ -132,6 +134,8 @@ def evaluate_settings(
*,
on_conflict: Literal["error", "keep", "replace"] = "keep",
) -> None:
# set flag early so extensions can use settings when using evaluate_settings_once_on_access
self.settings_evaluated = True
preloads = None
if self.settings_preloads_name:
preloads = get_value_from_settings(self.settings, self.settings_preloads_name)
Expand All @@ -148,7 +152,6 @@ def evaluate_settings(
if self.settings_extensions_name:
for extension in get_value_from_settings(self.settings, self.settings_extensions_name):
self.add_extension(extension, use_overwrite=True, on_conflict=on_conflict)
self.settings_evaluated = True

def evaluate_settings_once(
self,
Expand Down
22 changes: 22 additions & 0 deletions tests/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ def test_settings_overwrite():
assert mod.monkay.settings is not old_settings


def test_settings_on_access():
import tests.targets.module_full as mod

assert mod.monkay.settings_evaluated
mod.monkay.evaluate_settings_once_on_access = True

old_settings = mod.monkay.settings
settings_path = mod.monkay._settings_definition
assert isinstance(settings_path, str)

assert "tests.targets.module_settings_preloaded" not in sys.modules
new_settings = old_settings.model_copy(
update={"preloads": ["tests.targets.module_settings_preloaded"]}
)
with mod.monkay.with_settings(new_settings) as yielded:
assert not mod.monkay.settings_evaluated
assert "tests.targets.module_settings_preloaded" not in sys.modules
# evaluates settings
assert mod.monkay.settings is yielded
assert "tests.targets.module_settings_preloaded" in sys.modules


@pytest.mark.parametrize("transform", [lambda x: x, lambda x: x.model_dump()])
@pytest.mark.parametrize("mode", ["error", "replace", "keep"])
def test_settings_overwrite_evaluate_modes(mode, transform):
Expand Down

0 comments on commit 951ba2e

Please sign in to comment.