From 12e658a549fddec45c611fe3a23bf85b723822e8 Mon Sep 17 00:00:00 2001 From: Tiago Requeijo Date: Sat, 1 Aug 2020 11:14:32 -0400 Subject: [PATCH] Added an interpolate keyword to the as_dict and as_attrdict methods --- config/configuration.py | 36 +++++++++++++++----- config/configuration_set.py | 8 ++--- tests/test_datatypes.py | 2 +- tests/test_interpolation.py | 67 +++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 13 deletions(-) diff --git a/config/configuration.py b/config/configuration.py index 77e0ffd..3ee9a1f 100644 --- a/config/configuration.py +++ b/config/configuration.py @@ -150,7 +150,7 @@ def __getitem__(self, item: str) -> Union["Configuration", Any]: # noqa: D105 if v == {}: raise KeyError(item) if isinstance(v, dict): - return Configuration(v) + return Configuration(v, interpolate=self._interpolate) elif self._interpolate is not False: d = self.as_dict() d.update(cast(Dict[str, str], self._interpolate)) @@ -171,17 +171,37 @@ def get(self, key: str, default: Any = None) -> Union[dict, Any]: """ return self.as_dict().get(key, default) - def as_dict(self) -> dict: + def as_dict(self, interpolation: bool = False, nested: bool = False) -> dict: """Return the representation as a dictionary.""" - return self._config + if not interpolation: + result = self._config + else: + interpolated_copy = Configuration(cast(dict, self), interpolate=True) + result = {} + for k in interpolated_copy.keys(levels=1): + v = interpolated_copy[cast(str, k)] + if isinstance(v, Configuration): + v = v.as_dict(interpolation=True) + result[k] = v # type: ignore + result = Configuration(result).as_dict() + if nested: + result = { + k: ( + v + if not isinstance(v, (dict, Configuration)) + else Configuration(cast(dict, v)).as_dict(nested=True) + ) + for k, v in Configuration(result).items(levels=1) + } + return result - def as_attrdict(self) -> AttributeDict: + def as_attrdict( + self, interpolation: bool = False, nested: bool = False + ) -> AttributeDict: """Return the representation as an attribute dictionary.""" + d = self.as_dict(interpolation=interpolation, nested=nested) return AttributeDict( - { - x: Configuration(v).as_attrdict() if isinstance(v, dict) else v - for x, v in self.items(levels=1) - } + {x: AttributeDict(v) if isinstance(v, dict) else v for x, v in d.items()} ) def get_bool(self, item: str) -> bool: diff --git a/config/configuration_set.py b/config/configuration_set.py index 677b689..386ac24 100644 --- a/config/configuration_set.py +++ b/config/configuration_set.py @@ -69,14 +69,14 @@ def _from_configs(self, attr: str, *args: Any, **kwargs: dict) -> Any: result: dict = {} for v in values[::-1]: result.update(v) - return Configuration(result) + return Configuration(result, interpolate=self._interpolate) elif isinstance(values[0], Configuration): result = {} for v in values[::-1]: if not isinstance(v, Configuration): continue result.update(v) - return Configuration(result) + return Configuration(result, interpolate=self._interpolate) elif self._interpolate is not False: d = [d.as_dict() for d in self._configs] d[0].update(cast(Dict[str, str], self._interpolate)) @@ -125,12 +125,12 @@ def get(self, key: str, default: Any = None) -> Union[dict, Any]: except Exception: return default - def as_dict(self) -> dict: + def as_dict(self, interpolation: bool = False, nested: bool = False) -> dict: """Return the representation as a dictionary.""" result = {} for config_ in self._configs[::-1]: result.update(config_.as_dict()) - return result + return Configuration(result).as_dict(interpolation=interpolation, nested=nested) def get_dict(self, item: str) -> dict: """ diff --git a/tests/test_datatypes.py b/tests/test_datatypes.py index ee5481a..66e5e16 100644 --- a/tests/test_datatypes.py +++ b/tests/test_datatypes.py @@ -42,7 +42,7 @@ def test_attribute_dict_1(): # type: ignore } cfg = config_from_dict(definitions, interpolate=True) - d = cfg.as_attrdict() + d = cfg.as_attrdict(nested=True) assert isinstance(d, dict) assert isinstance(d, AttributeDict) diff --git a/tests/test_interpolation.py b/tests/test_interpolation.py index 65bb18e..4a2a3c2 100644 --- a/tests/test_interpolation.py +++ b/tests/test_interpolation.py @@ -6,6 +6,12 @@ VALUES = {"var1": "This {var2}", "var2": "is a {var3}", "var3": "test"} FAILS = {"var1": "This will fail {var2}", "var2": "{var3}", "var3": "{var1}"} MULTI = {"var1": "This is a {var2} {var3}", "var2": "repeat {var3}", "var3": "test"} +MULTI_NESTED = { + "var1": "This is a {var2} {var3}", + "var2": "repeat {var3}", + "var3": "test", + "var4": {"a": "a{b}", "b": "b"}, +} ARRAY = { "var1": ["This is a {var2} {var3}", "{var2}", "{var3}"], "var2": "repeat {var3}", @@ -269,3 +275,64 @@ def test_interpolation_same_variable_4(): # type: ignore ) assert cfg.var2 == "test/a/b" # var2(2) --> var1(2) --> var1(1) --> var2(1) assert cfg.var1 == "test/a" # var1(2) --> var1(1) --> var2(1) + + +def test_as_dict_interpolation(): # type: ignore + cfg = config_from_dict(MULTI_NESTED, lowercase_keys=True, interpolate=True) + + assert cfg["var4"] == {"a": "a{b}", "b": "b"} + assert cfg["var4"].a == "ab" + + assert cfg.as_dict(interpolation=False) == { + "var1": "This is a {var2} {var3}", + "var2": "repeat {var3}", + "var3": "test", + "var4.a": "a{b}", + "var4.b": "b", + } + + assert cfg.as_dict(interpolation=True) == { + "var1": "This is a repeat test test", + "var2": "repeat test", + "var3": "test", + "var4.a": "ab", + "var4.b": "b", + } + + +def test_as_attrdict_interpolation(): # type: ignore + cfg = config_from_dict(MULTI_NESTED, lowercase_keys=True, interpolate=True) + + assert cfg["var4"] == {"a": "a{b}", "b": "b"} + assert cfg["var4"].a == "ab" + + d = cfg.as_attrdict(interpolation=False) + assert d.var1 == "This is a {var2} {var3}" + assert d.var2 == "repeat {var3}" + assert d.var3 == "test" + + d = cfg.as_attrdict(interpolation=True) + assert d.var1 == "This is a repeat test test" + assert d.var2 == "repeat test" + assert d.var3 == "test" + + +def test_as_dict_interpolation_set(): # type: ignore + cfg = config(SET1, SET2, lowercase_keys=True, interpolate=True) + + assert cfg["var3"] == "test" + assert cfg["var2"] == "is a test" + assert cfg["var1"] == "This is a test" + assert cfg.var1 == "This is a test" + + assert cfg.as_dict(interpolation=False) == { + "var1": "This {var2}", + "var2": "is a {var3}", + "var3": "test", + } + + assert cfg.as_dict(interpolation=True) == { + "var1": "This is a test", + "var2": "is a test", + "var3": "test", + }