]> mj.ucw.cz Git - moe.git/blobdiff - t/moe/config.py
Added unfix(), corrected fix()
[moe.git] / t / moe / config.py
index f24e1ef8f357748b41b13f2b8cff20419cfb90d7..e6ce045913797a4ff411ee84357fe543f1ab9a1d 100644 (file)
@@ -1,10 +1,6 @@
 """
-config.py
----------
-
 Lazy conditional string evaluation module for Moe configuration variables.
 
-
 * Each variable has ordered list of operations (definitions), each defining operation either 
   assigns (SET) or appends (APPEND) value of an expression to the variable. Each operation may be guarded by condition(s). 
 
@@ -59,6 +55,17 @@ class VariableFixedError(ConfigError):
 class CyclicConfigError(ConfigError):
   pass
 
+class ParseProxy(list):
+  """Proxy helper class around values returned by `parse` and `parse_file`, 
+  useful in "with" constructs."""
+  def __init__(self, config, parsed_ops):
+    super(ParseProxy, self).__init__(parsed_ops)  
+    self.config = config
+  def __enter__(self):
+    pass
+  def __exit__(self, etype, value, traceback):
+    self.config.remove(list(self))
+
 
 class ConfigTree(object):
   """
@@ -98,19 +105,52 @@ class ConfigTree(object):
       self.variables[k].dump(prefix) for k in sorted(self.variables.keys())
       ])
 
-  def parse(self, s, source=None, level=0):
-    """Parse `s` (stream/string) into the tree, see `moe.confparser.ConfigParser` for details."""
-    import moe.confparser
-    p = moe.confparser.ConfigParser(text, self, source=source, level=level)
-    p.parse()
-
-  def parse_file(self, filename, desc=None, level=0):
-    """Parse an utf-8 file into the tree, see `moe.confparser.ConfigParser` for details. 
+  def fix(self, keys):
+    "Fix value of variable or list of variables. Fixing undefined variable raises `UndefinedError`."
+    if isinstance(keys, types.StringTypes):
+      keys = [keys]
+    for key in keys:
+      self.lookup(key, create=False).fix()
+  
+  def unfix(self, keys):
+    "Unfix value of variable or list of variables. Unfixing undefined variable raises `UndefinedError`."
+    if isinstance(keys, types.StringTypes):
+      keys = [keys]
+    for key in keys:
+      self.lookup(key, create=False).unfix()
+
+  def remove(self, parsed):
+    """Given a list [(varname, `Operation`)] as returned by `parse` or `parse_file`, 
+    removes the operations from the respective variables config tree.
+    Variables/operations not present int the tree raise ValueError.
+    """
+    for vname, o in parsed:
+      v = self.lookup(vname, create = True)
+      v.remove_operation(o)
+
+  def parse(self, s, source=None, level=0, proxy=True):
+    """Parse `s` (stream/string) into the tree, see `moe.config_parser.ConfigParser` for details.
+    Returns list of parset operations: [(varname, `Operation`)].
+    By default returns a proxy list-like object that can be used in "with" constructs:
+      
+      with config.parse("TEST='1'"):
+       print config['TEST']
+       raise StupidError
+    """
+    import moe.config_parser
+    p = moe.config_parser.ConfigParser(s, self, source=source, level=level)
+    l = p.parse()
+    if not proxy:
+      return l
+    return ParseProxy(self, l)
+
+  def parse_file(self, filename, desc=None, level=0, proxy=True):
+    """Parse an utf-8 file into the tree using func:`parse`. 
     Names the source "`filename` <`desc`>". """
-    f = open(filename, 'rt')
-    if desc: 
-      filename += " <" + desc + ">" 
-    self.parse(f, source=filename, level=level)
+    with open(filename, 'rt') as f:
+      if desc: 
+       filename += " <" + desc + ">" 
+      return self.parse(f, source=filename, level=level, proxy=proxy)
 
 
 class ConfigElem(object):
@@ -265,7 +305,9 @@ class ConfigVar(ConfigElem):
 
   def variables(self):
     "Return a set of variables used in the expressions"
-    return set(sum([ list(op.expression.variables()) for op in self.operations ], []))
+    if not self.operations:
+      return set([])
+    return set.union(*[ op.expression.variables() for op in self.operations ])
 
   def fix(self):
     """
@@ -278,14 +320,14 @@ class ConfigVar(ConfigElem):
     self.fixed = True
 
   def unfix(self):
-    "Set the variable to be modifiable again."
+    "Make the variable modifiable again."
     self.fixed = False
 
   def value(self, depth=0):
     "Handle the case when fixed, raise exc. on different evaluation"
     val = super(ConfigVar,self).value(depth)
     if self.fixed and self.fixed_val != val:
-      raise VariableFixedError("value of var %s was fixed to %r but evaluated to %r", self.name, self.fixed_val, val)
+      raise VariableFixedError("value of var %r was fixed to %r but evaluated to %r", self.name, self.fixed_val, val)
     return val
 
   def add_operation(self, operation):
@@ -315,7 +357,7 @@ class ConfigVar(ConfigElem):
     self.invalidate()
     # Remove the operation 
     self.operations.remove(operation)
-    # Remove dependencies on variables unused in other operations
+    # Remove dependencies on variables unused in other defining operations
     vs = self.variables()
     for v in operation.expression.variables():
       if v not in vs:
@@ -380,8 +422,8 @@ class ConfigExpression(object):
          self.exprlist[i] = unicode(e, 'ascii')
 
   def variables(self):
-    "Return an iterator of variables user in the expression"
-    return itertools.ifilter(lambda e: isinstance(e, ConfigVar), self.exprlist)
+    "Return a set of variables used in the expression"
+    return set([e for e in self.exprlist if isinstance(e, ConfigVar)])
 
   def __str__(self):
     return self.original