comparison piecrust/configuration.py @ 440:32c7c2d219d2

performance: Refactor how data is managed to reduce copying. * Make use of `collections.abc.Mapping` to better identify things that are supposed to look like dictionaries. * Instead of handling "overlay" of data in a dict tree in each different data object, make all objects `Mapping`s and handle merging at a higher level with the new `MergedMapping` object. * Since this new object is read-only, remove the need for deep-copying of app and page configurations. * Split data classes into separate modules.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 28 Jun 2015 08:22:39 -0700
parents bdeeee777f85
children 1359b2b0cc73
comparison
equal deleted inserted replaced
439:c0700c6d9545 440:32c7c2d219d2
1 import re 1 import re
2 import copy
3 import logging 2 import logging
4 import collections 3 import collections.abc
5 import yaml 4 import yaml
6 from yaml.constructor import ConstructorError 5 from yaml.constructor import ConstructorError
7 6
8 7
9 logger = logging.getLogger(__name__) 8 logger = logging.getLogger(__name__)
13 12
14 class ConfigurationError(Exception): 13 class ConfigurationError(Exception):
15 pass 14 pass
16 15
17 16
18 class Configuration(object): 17 class Configuration(collections.abc.MutableMapping):
19 def __init__(self, values=None, validate=True): 18 def __init__(self, values=None, validate=True):
20 if values is not None: 19 if values is not None:
21 self.setAll(values, validate) 20 self.setAll(values, validate=validate)
22 else: 21 else:
23 self._values = None 22 self._values = None
24 23
25 def __contains__(self, key):
26 return self.has(key)
27
28 def __getitem__(self, key): 24 def __getitem__(self, key):
29 value = self.get(key) 25 self._ensureLoaded()
30 if value is None: 26 bits = key.split('/')
31 raise KeyError()
32 return value
33
34 def __setitem__(self, key, value):
35 return self.set(key, value)
36
37 def setAll(self, values, validate=True):
38 if validate:
39 self._validateAll(values)
40 self._values = values
41
42 def getDeepcopy(self, validate_types=False):
43 if validate_types:
44 self.validateTypes()
45 return copy.deepcopy(self.get())
46
47 def get(self, key_path=None, default_value=None):
48 self._ensureLoaded()
49 if key_path is None:
50 return self._values
51 bits = key_path.split('/')
52 cur = self._values 27 cur = self._values
53 for b in bits: 28 for b in bits:
54 cur = cur.get(b) 29 try:
55 if cur is None: 30 cur = cur[b]
56 return default_value 31 except KeyError:
32 raise KeyError("No such item: %s" % key)
57 return cur 33 return cur
58 34
59 def set(self, key_path, value): 35 def __setitem__(self, key, value):
60 self._ensureLoaded() 36 self._ensureLoaded()
61 value = self._validateValue(key_path, value) 37 value = self._validateValue(key, value)
62 bits = key_path.split('/') 38 bits = key.split('/')
63 bitslen = len(bits) 39 bitslen = len(bits)
64 cur = self._values 40 cur = self._values
65 for i, b in enumerate(bits): 41 for i, b in enumerate(bits):
66 if i == bitslen - 1: 42 if i == bitslen - 1:
67 cur[b] = value 43 cur[b] = value
68 else: 44 else:
69 if b not in cur: 45 if b not in cur:
70 cur[b] = {} 46 cur[b] = {}
71 cur = cur[b] 47 cur = cur[b]
72 48
73 def has(self, key_path): 49 def __delitem__(self, key):
74 self._ensureLoaded() 50 raise NotImplementedError()
75 bits = key_path.split('/') 51
76 cur = self._values 52 def __iter__(self):
77 for b in bits: 53 self._ensureLoaded()
78 cur = cur.get(b) 54 return iter(self._values)
79 if cur is None: 55
80 return False 56 def __len__(self):
81 return True 57 self._ensureLoaded()
58 return len(self._values)
59
60 def has(self, key):
61 return key in self
62
63 def set(self, key, value):
64 self[key] = value
65
66 def setAll(self, values, validate=False):
67 if validate:
68 self._validateAll(values)
69 self._values = values
70
71 def getAll(self):
72 self._ensureLoaded()
73 return self._values
82 74
83 def merge(self, other): 75 def merge(self, other):
84 self._ensureLoaded() 76 self._ensureLoaded()
85 77
86 if isinstance(other, dict): 78 if isinstance(other, dict):