comparison piecrust/configuration.py @ 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 45aba3cb7228
children bdeeee777f85
comparison
equal deleted inserted replaced
366:81d2fd526c82 367:734f2abf361c
1 import re 1 import re
2 import copy
2 import logging 3 import logging
3 import collections 4 import collections
4 import yaml 5 import yaml
5 from yaml.constructor import ConstructorError 6 from yaml.constructor import ConstructorError
6 7
7 8
8 logger = logging.getLogger(__name__) 9 logger = logging.getLogger(__name__)
10
11 default_allowed_types = (dict, list, tuple, int, bool, str)
9 12
10 13
11 class ConfigurationError(Exception): 14 class ConfigurationError(Exception):
12 pass 15 pass
13 16
34 def setAll(self, values, validate=True): 37 def setAll(self, values, validate=True):
35 if validate: 38 if validate:
36 self._validateAll(values) 39 self._validateAll(values)
37 self._values = values 40 self._values = values
38 41
39 def getAll(self): 42 def getDeepcopy(self, validate_types=False):
40 return self.get() 43 if validate_types:
44 self.validateTypes()
45 return copy.deepcopy(self.get())
41 46
42 def get(self, key_path=None, default_value=None): 47 def get(self, key_path=None, default_value=None):
43 self._ensureLoaded() 48 self._ensureLoaded()
44 if key_path is None: 49 if key_path is None:
45 return self._values 50 return self._values
86 raise Exception( 91 raise Exception(
87 "Unsupported value type to merge: %s" % type(other)) 92 "Unsupported value type to merge: %s" % type(other))
88 93
89 merge_dicts(self._values, other_values, 94 merge_dicts(self._values, other_values,
90 validator=self._validateValue) 95 validator=self._validateValue)
96
97 def validateTypes(self, allowed_types=default_allowed_types):
98 self._validateDictTypesRecursive(self._values, allowed_types)
99
100 def _validateDictTypesRecursive(self, d, allowed_types):
101 for k, v in d.items():
102 if not isinstance(k, str):
103 raise ConfigurationError("Key '%s' is not a string." % k)
104 self._validateTypeRecursive(v, allowed_types)
105
106 def _validateListTypesRecursive(self, l, allowed_types):
107 for v in l:
108 self._validateTypeRecursive(v, allowed_types)
109
110 def _validateTypeRecursive(self, v, allowed_types):
111 if v is None:
112 return
113 if not isinstance(v, allowed_types):
114 raise ConfigurationError(
115 "Value '%s' is of forbidden type: %s" % (v, type(v)))
116 if isinstance(v, dict):
117 self._validateDictTypesRecursive(v, allowed_types)
118 elif isinstance(v, list):
119 self._validateListTypesRecursive(v, allowed_types)
91 120
92 def _ensureLoaded(self): 121 def _ensureLoaded(self):
93 if self._values is None: 122 if self._values is None:
94 self._load() 123 self._load()
95 124