Added a kind of generic module to handle configuration environments.
authorFredrik Tolf <fredrik@dolda2000.com>
Sun, 5 Feb 2012 15:43:47 +0000 (16:43 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Sun, 5 Feb 2012 15:43:47 +0000 (16:43 +0100)
wrw/env.py [new file with mode: 0644]

diff --git a/wrw/env.py b/wrw/env.py
new file mode 100644 (file)
index 0000000..6c7e859
--- /dev/null
@@ -0,0 +1,86 @@
+import threading, weakref
+
+__all__ = ["environment", "root", "get", "binding", "var"]
+
+class stack(object):
+    __slots__ = ["env", "prev"]
+    def __init__(self, env, prev):
+        self.env = env
+        self.prev = prev
+
+class environment(object):
+    __slots__ = ["parent", "map"]
+    def __init__(self, parent = None):
+        self.parent = None
+        self.map = weakref.WeakKeyDictionary()
+
+    def get(self, var):
+        if var in self.map:
+            return self.map[var]
+        if self.parent is None:
+            return None
+        return self.parent.get(var)
+
+    def set(self, var, val):
+        self.map[var] = val
+
+    def __enter__(self):
+        cur = context.env
+        context.prev = stack(cur, context.prev)
+        context.env = self
+        return None
+
+    def __exit__(self, *excinfo):
+        prev = context.prev
+        if prev is None:
+            raise Exception("Unbalanced __enter__/__exit__")
+        context.env = prev.env
+        context.prev = prev.prev
+        return False
+
+root = environment()
+
+class context(threading.local):
+    env = root
+    prev = None
+context = context()
+
+def get():
+    return context.env
+
+class binding(object):
+    __slots__ = ["bindings"]
+    def __init__(self, bindings):
+        if isinstance(bindings, dict):
+            bindings = bindings.items()
+        self.bindings = bindings
+
+    def __enter__(self):
+        cur = context.env
+        new = environment(cur)
+        for var, val in self.bindings:
+            new.map[var] = val
+        context.prev = stack(cur, context.prev)
+        context.env = new
+        return None
+
+    def __exit__(self, *excinfo):
+        prev = context.prev
+        if prev is None:
+            raise Exception("Unbalanced __enter__/__exit__")
+        context.env = prev.env
+        context.prev = prev.prev
+        return False
+
+class var(object):
+    __slots__ = ["__weakref__"]
+    def __init__(self, default = None):
+        if default is not None:
+            root.map[self] = default
+
+    @property
+    def val(self):
+        return context.env.get(self)
+
+    def binding(self, val):
+        return binding([(self, val)])