]> mj.ucw.cz Git - eval.git/commitdiff
Add context manager to ConfigTree.parse
authorTomas Gavenciak <gavento@ucw.cz>
Wed, 22 Sep 2010 21:59:52 +0000 (23:59 +0200)
committerTomas Gavenciak <gavento@ucw.cz>
Wed, 22 Sep 2010 21:59:52 +0000 (23:59 +0200)
Now we can do:

with parse("..."):
  use modified config
  raise exception

Also adapted one test. Yay!

t/moe/config.py
t/moe/config_test.py

index 04e363f1887ef53446392b202a34df97faa00630..abc82692b05aaf02b590325b6ee7f1a6b308847a 100644 (file)
@@ -55,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):
   """
@@ -110,20 +121,29 @@ class ConfigTree(object):
       v = self.lookup(vname, create = True)
       v.remove_operation(o)
 
-  def parse(self, s, source=None, level=0):
-    """Parse `s` (stream/string) into the tree, see `moe.confparser.ConfigParser` for details.
-    Returns list of parset operations: [(varname, `Operation`)]"""
+  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)
-    return p.parse()
+    l = p.parse()
+    if not proxy:
+      return l
+    return ParseProxy(self, l)
 
-  def parse_file(self, filename, desc=None, level=0):
-    """Parse an utf-8 file into the tree, see `moe.confparser.ConfigParser` for details
+  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`>". """
     with open(filename, 'rt') as f:
       if desc: 
        filename += " <" + desc + ">" 
-      return self.parse(f, source=filename, level=level)
+      return self.parse(f, source=filename, level=level, proxy=proxy)
 
 
 class ConfigElem(object):
index 2a0325b8b57e923b9ce76ccad47683e72eb1451e..f1c836d33c204021ce1dfd32dff3ff38f80e9979 100644 (file)
@@ -12,11 +12,7 @@ class TestConfig(unittest.TestCase):
     s.t = cf.ConfigTree()    
 
   def parse(s, string, level=0, fname='test'):
-    cp = ConfigParser(string, s.t, fname, level)
-    ops = cp.parse()
-    cp.p_WS()
-    assert cp.eof()
-    return ops
+    return s.t.parse(string, source=fname, level=level)
 
   def var(s, varname, create=True):
     return s.t.lookup(varname, create=create)
@@ -83,21 +79,32 @@ class TestParser(TestConfig):
     s.assertRaises(ConfigSyntaxError, s.parse, "if 'a'<>'b' {}")
 
   def test_parse_remove(s):
-    s.parse('a="000"')
+    def raise_UserWarning():
+      with s.parse("b='F'", level=99):
+       assert s.val('b') == 'F'
+       raise UserWarning 
+    d0 = s.parse('a="000"')
     d1 = s.parse("a='A'; b='B'; c='C'", level=10)
     d2 = s.parse('c="{a}{a}"; b="XX" ', level=20)
     d3 = s.parse('b+=c ', level=30)
     assert s.val('b') == "XXAA"
     s.t.remove(d2)
     assert s.val('b') == "BC"
-    s.assertRaises(ValueError, s.t.remove, [('d', d1[1][0])])
-    s.assertRaises(ValueError, s.t.remove, [('b', d1[1][0])])
+    s.assertRaises(ValueError, s.t.remove, [('d', d1[0][1])])
+    s.assertRaises(ValueError, s.t.remove, [('b', d1[0][1])])
+    # Try exception in "with parse():" 
+    s.assertRaises(UserWarning, raise_UserWarning)
+    assert s.val('b') == "BC"
     # partially remove d1
     s.t.remove([('c', d1[2][1])])
     # try to remove rest - 'a' and 'b' should get removed
     s.assertRaises(ValueError, s.t.remove, d1)
     assert s.val('a') == "000"
+    # cleanup
     s.t.remove(d3)
+    s.t.remove(d0)
+    for v in 'abcd':
+      assert len(s.var(v).operations) == 0
 
 
 class TestConfigEval(TestConfig):