diff 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
line wrap: on
line diff
--- a/piecrust/configuration.py	Sat Jun 27 22:28:32 2015 -0700
+++ b/piecrust/configuration.py	Sun Jun 28 08:22:39 2015 -0700
@@ -1,7 +1,6 @@
 import re
-import copy
 import logging
-import collections
+import collections.abc
 import yaml
 from yaml.constructor import ConstructorError
 
@@ -15,51 +14,28 @@
     pass
 
 
-class Configuration(object):
+class Configuration(collections.abc.MutableMapping):
     def __init__(self, values=None, validate=True):
         if values is not None:
-            self.setAll(values, validate)
+            self.setAll(values, validate=validate)
         else:
             self._values = None
 
-    def __contains__(self, key):
-        return self.has(key)
-
     def __getitem__(self, key):
-        value = self.get(key)
-        if value is None:
-            raise KeyError()
-        return value
+        self._ensureLoaded()
+        bits = key.split('/')
+        cur = self._values
+        for b in bits:
+            try:
+                cur = cur[b]
+            except KeyError:
+                raise KeyError("No such item: %s" % key)
+        return cur
 
     def __setitem__(self, key, value):
-        return self.set(key, value)
-
-    def setAll(self, values, validate=True):
-        if validate:
-            self._validateAll(values)
-        self._values = values
-
-    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()
-        if key_path is None:
-            return self._values
-        bits = key_path.split('/')
-        cur = self._values
-        for b in bits:
-            cur = cur.get(b)
-            if cur is None:
-                return default_value
-        return cur
-
-    def set(self, key_path, value):
-        self._ensureLoaded()
-        value = self._validateValue(key_path, value)
-        bits = key_path.split('/')
+        value = self._validateValue(key, value)
+        bits = key.split('/')
         bitslen = len(bits)
         cur = self._values
         for i, b in enumerate(bits):
@@ -70,15 +46,31 @@
                     cur[b] = {}
                 cur = cur[b]
 
-    def has(self, key_path):
+    def __delitem__(self, key):
+        raise NotImplementedError()
+
+    def __iter__(self):
+        self._ensureLoaded()
+        return iter(self._values)
+
+    def __len__(self):
         self._ensureLoaded()
-        bits = key_path.split('/')
-        cur = self._values
-        for b in bits:
-            cur = cur.get(b)
-            if cur is None:
-                return False
-        return True
+        return len(self._values)
+
+    def has(self, key):
+        return key in self
+
+    def set(self, key, value):
+        self[key] = value
+
+    def setAll(self, values, validate=False):
+        if validate:
+            self._validateAll(values)
+        self._values = values
+
+    def getAll(self):
+        self._ensureLoaded()
+        return self._values
 
     def merge(self, other):
         self._ensureLoaded()