aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configlib/model.py6
-rw-r--r--configlib/model_impl.py29
-rw-r--r--tests/test_something.py12
3 files changed, 44 insertions, 3 deletions
diff --git a/configlib/model.py b/configlib/model.py
index 5f5c694..0bc94e1 100644
--- a/configlib/model.py
+++ b/configlib/model.py
@@ -11,6 +11,12 @@ from typing import Type, Union, AnyStr, TextIO
from configlib.util import snake_case
+class InvalidConfigEscapeException(Exception):
+ """
+ Some config uses an invalid escape like `$invalidescapecode:argument`
+ """
+
+
class InvalidConfigTypingException(Exception):
"""
The typing found in the given class is missing arguments.
diff --git a/configlib/model_impl.py b/configlib/model_impl.py
index dc8cde0..d18611f 100644
--- a/configlib/model_impl.py
+++ b/configlib/model_impl.py
@@ -1,10 +1,11 @@
"""
Implementations for the modules of :module:`configlib.model`
"""
-
+import os
from typing import Type, Dict, List
-from .model import Config, ConfigValueMissingException, InvalidConfigTypingException
+from .model import Config, ConfigValueMissingException, InvalidConfigTypingException, \
+ InvalidConfigEscapeException
from .util import snake_case
@@ -57,6 +58,23 @@ def parse_dict_impl(val_type: Type[object], val, path) -> dict:
return dic
+_ESCAPES = {
+ 'env': os.environ.get,
+}
+
+
+def _resolve_string(val: str):
+ if val[0] != '$':
+ return val
+ if val[1] == '$':
+ return val[1:]
+ descriptor, arg, *_ = val[1:].split(':', 2) + ['']
+ escape = _ESCAPES.get(descriptor)
+ if not escape:
+ raise InvalidConfigEscapeException(descriptor)
+ return escape(arg)
+
+
# noinspection PyUnresolvedReferences
def parse_single_item(val_type: Type[object], val, path):
"""
@@ -67,8 +85,13 @@ def parse_single_item(val_type: Type[object], val, path):
:param path: the path inside the config. used for error reporting
:return: the parsed something
"""
+ if isinstance(val, str):
+ if len(val) > 2 and val[0] == '$':
+ val = _resolve_string(val)
+
if issubclass(val_type, (str, int, float)):
- return val
+ # noinspection PyArgumentList
+ return val_type(val)
if isinstance(val_type, List):
if len(val_type.__args__) != 1:
raise InvalidConfigTypingException(path + ': List must be supplied exactly one type')
diff --git a/tests/test_something.py b/tests/test_something.py
index 8091f46..7bb979a 100644
--- a/tests/test_something.py
+++ b/tests/test_something.py
@@ -1,4 +1,5 @@
import json
+import os
from unittest import TestCase
from configlib.model_impl import BaseConfig
@@ -19,6 +20,12 @@ test_dict = {
'a': 1
}
}
+env_dict = {
+ 'something': '$env:ENVVAR',
+ 'ye': {
+ 'a': 1
+ }
+}
def verify_test_dict(conf):
@@ -37,3 +44,8 @@ class TestSomething(TestCase):
def test_text(self):
conf: SomeConfig = SomeConfig.loads(json.dumps(test_dict))
verify_test_dict(conf)
+
+ def test_environ(self):
+ os.environ['ENVVAR'] = 'hmm'
+ conf: SomeConfig = SomeConfig.parse_dict(env_dict)
+ verify_test_dict(conf)