From 9c622b57d5831cd7fe17d3012c338705fe4790d7 Mon Sep 17 00:00:00 2001 From: Unrud Date: Wed, 15 Jan 2020 03:20:48 +0100 Subject: [PATCH] Allow callable in configuration for plugin.type Example: ```python3 \# Load default configuration my_config = config.load() \# Pass a class directly my_config.update({"auth": {"type": MyAuth}}) \# Pass an object directly my_rights = MyRights() my_config.update({"rights": {"type": lambda config: my_rights}}) app = Application(my_config) ```` --- radicale/config.py | 14 ++++++++++---- radicale/tests/test_base.py | 7 +++++++ radicale/utils.py | 3 +++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/radicale/config.py b/radicale/config.py index 79a3f69..c0a89f9 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -81,6 +81,12 @@ def list_of_ip_address(value): return [ip_address(s.strip()) for s in value.split(",")] +def str_or_callable(value): + if callable(value): + return value + return str(value) + + def unspecified_type(value): return value @@ -150,7 +156,7 @@ DEFAULT_CONFIG_SCHEMA = OrderedDict([ ("type", { "value": "none", "help": "authentication method", - "type": str, + "type": str_or_callable, "internal": auth.INTERNAL_TYPES}), ("htpasswd_filename", { "value": "/etc/radicale/users", @@ -172,7 +178,7 @@ DEFAULT_CONFIG_SCHEMA = OrderedDict([ ("type", { "value": "owner_only", "help": "rights backend", - "type": str, + "type": str_or_callable, "internal": rights.INTERNAL_TYPES}), ("file", { "value": "/etc/radicale/rights", @@ -182,7 +188,7 @@ DEFAULT_CONFIG_SCHEMA = OrderedDict([ ("type", { "value": "multifilesystem", "help": "storage backend", - "type": str, + "type": str_or_callable, "internal": storage.INTERNAL_TYPES}), ("filesystem_folder", { "value": "/var/lib/radicale/collections", @@ -204,7 +210,7 @@ DEFAULT_CONFIG_SCHEMA = OrderedDict([ ("type", { "value": "internal", "help": "web interface backend", - "type": str, + "type": str_or_callable, "internal": web.INTERNAL_TYPES})])), ("logging", OrderedDict([ ("level", { diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py index fc1fdf6..00b1bd6 100644 --- a/radicale/tests/test_base.py +++ b/radicale/tests/test_base.py @@ -30,6 +30,7 @@ import tempfile import defusedxml.ElementTree as DefusedET import pytest +import radicale.tests.custom.storage_simple_sync from radicale import Application, config, storage, xmlutils from radicale.tests import BaseTest from radicale.tests.helpers import get_file_content @@ -1495,3 +1496,9 @@ class TestCustomStorageSystem(BaseFileSystemTest): if s.startswith("test_") and ("_sync_" in s or s.endswith("_sync")): locals()[s] = getattr(BaseRequestsMixIn, s) del s + + +class TestCustomStorageSystemCallable(BaseFileSystemTest): + """Test custom backend loading with ``callable``.""" + storage_type = radicale.tests.custom.storage_simple_sync.Storage + test_add_event = BaseRequestsMixIn.test_add_event diff --git a/radicale/utils.py b/radicale/utils.py index 74b9bad..656912d 100644 --- a/radicale/utils.py +++ b/radicale/utils.py @@ -23,6 +23,9 @@ from radicale.log import logger def load_plugin(internal_types, module_name, class_name, configuration): type_ = configuration.get(module_name, "type") + if callable(type_): + logger.info("%s type is %r", module_name, type_) + return type_(configuration) if type_ in internal_types: module = "radicale.%s.%s" % (module_name, type_) else: