changeset 367:734f2abf361c

config: Add method to deep-copy a config and validate its contents. Deep-copying will be problematic if non-basic types are in there, so there's a new method to check that this is OK.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 03 May 2015 18:42:29 -0700
parents 81d2fd526c82
children 2408eb6f4da8
files piecrust/configuration.py
diffstat 1 files changed, 31 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/piecrust/configuration.py	Sun May 03 18:40:38 2015 -0700
+++ b/piecrust/configuration.py	Sun May 03 18:42:29 2015 -0700
@@ -1,4 +1,5 @@
 import re
+import copy
 import logging
 import collections
 import yaml
@@ -7,6 +8,8 @@
 
 logger = logging.getLogger(__name__)
 
+default_allowed_types = (dict, list, tuple, int, bool, str)
+
 
 class ConfigurationError(Exception):
     pass
@@ -36,8 +39,10 @@
             self._validateAll(values)
         self._values = values
 
-    def getAll(self):
-        return self.get()
+    def getDeepcopy(self, validate_types=False):
+        if validate_types:
+            self.validateTypes()
+        return copy.deepcopy(self.get())
 
     def get(self, key_path=None, default_value=None):
         self._ensureLoaded()
@@ -89,6 +94,30 @@
         merge_dicts(self._values, other_values,
                     validator=self._validateValue)
 
+    def validateTypes(self, allowed_types=default_allowed_types):
+        self._validateDictTypesRecursive(self._values, allowed_types)
+
+    def _validateDictTypesRecursive(self, d, allowed_types):
+        for k, v in d.items():
+            if not isinstance(k, str):
+                raise ConfigurationError("Key '%s' is not a string." % k)
+            self._validateTypeRecursive(v, allowed_types)
+
+    def _validateListTypesRecursive(self, l, allowed_types):
+        for v in l:
+            self._validateTypeRecursive(v, allowed_types)
+
+    def _validateTypeRecursive(self, v, allowed_types):
+        if v is None:
+            return
+        if not isinstance(v, allowed_types):
+            raise ConfigurationError(
+                    "Value '%s' is of forbidden type: %s" % (v, type(v)))
+        if isinstance(v, dict):
+            self._validateDictTypesRecursive(v, allowed_types)
+        elif isinstance(v, list):
+            self._validateListTypesRecursive(v, allowed_types)
+
     def _ensureLoaded(self):
         if self._values is None:
             self._load()