# HG changeset patch # User Ludovic Chabant # Date 1430703749 25200 # Node ID 734f2abf361cccfc629fb244e91faf648f40793b # Parent 81d2fd526c82cbf321697ebb672757451d0869de 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. diff -r 81d2fd526c82 -r 734f2abf361c piecrust/configuration.py --- 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()