Sfoglia il codice sorgente

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)
````
Unrud 6 anni fa
parent
commit
9c622b57d5
3 ha cambiato i file con 20 aggiunte e 4 eliminazioni
  1. 10 4
      radicale/config.py
  2. 7 0
      radicale/tests/test_base.py
  3. 3 0
      radicale/utils.py

+ 10 - 4
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", {

+ 7 - 0
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

+ 3 - 0
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: