]> mj.ucw.cz Git - moe.git/commitdiff
Changes to config operations structure.
authorTomas Gavenciak <gavento@matfyz.cz>
Tue, 25 May 2010 01:55:07 +0000 (21:55 -0400)
committerTomas Gavenciak <gavento@matfyz.cz>
Tue, 25 May 2010 02:17:09 +0000 (22:17 -0400)
Changed config operaiton from triplets to a helper class,
added operation level (as priority) instead of index and
optional source. Changed dump format.
Removal now by operation instead of index.

Test updated and passed, but still not full coverage. WIP parser test.

t/moe/conf.py
t/moe/conf.test.py

index 37219ccbcba5db4f10e4f15355d3169f6b47daea..685675446cc94e7da24a8c46e064b5eed0d819d2 100644 (file)
@@ -24,7 +24,7 @@ TODO: Implemet "subtree" listing.
 TODO: Test conditions and unicode
 """
 
-import types, itertools, re
+import types, itertools, re, bisect
 import logging as log
 from confparser import re_VARNAME
 
@@ -185,55 +185,64 @@ class ConfigCondition(ConfigElem):
   def __str__(self):
     return self.str(parents=False)
 
+class Operation(object):
+  "Helper class for operation data. Must not be present in more variables or present multiple times."
+  def __init__(self, operation, condition, expression, level=0, source='?'):
+    # operation is currently 'SET' and 'APPEND'
+    self.operation = operation
+    self.condition = condition
+    self.expression = expression
+    self.level = level
+    self.source = source
+  def __str__(self):
+    return "%s <%d, %s> [%s] %r" % ( {'SET':'=', 'APPEND':'+'}[self.operation], self.level, self.source, 
+      (self.condition and self.condition.str(parents=True)) or '', unicode(self.expression))
+
 class ConfigVar(ConfigElem):
   def __init__(self, name):
     super(ConfigVar, self).__init__(name)
-    # Ordered list of operations
-    # (operation, condition, expression)
-    # operation is currently 'SET' and 'APPEND'
+    # Ordered list of `Operations` (ascending by `level`)
     self.operations = []
-    # Fixed to value (may be None) # TODO
+    # Fixed to value (may be None) 
+    # TODO: fixing
     self.fixed = False
     self.fixed_val = None
   def variables(self):
     "Return a set of variables used in the expressions"
-    return set(sum([ list(e[2].variables()) for e in self.operations ], []))
-  def add_operation(self, operation, condition, expression, index=None):
+    return set(sum([ list(op.expression.variables()) for op in self.operations ], []))
+  def add_operation(self, operation):
     """
-    Inserts a new operation to position `index` (`None` appends).
+    Inserts an operation. The operations are sorted by `level` (ascending), new operation goes last among
+    these with the same level.
     Adds the variable as a dependant of the conditions and variables used in the expressions. 
     """
     # Invalidate cached value
     self.invalidate()
     # Add the operation 
-    expr = (operation, condition, expression)
-    if index:
-      self.operations.insert(index, expr)
-    else:
-      self.operations.append(expr)
+    pos = bisect.bisect_right([o.level for o in self.operations], operation.level)
+    self.operations.insert(pos, operation)
     # Create dependencies
-    for v in expression.variables():
+    for v in operation.expression.variables():
       v.dependants.add(self)
-    if condition:
-      condition.dependants.add(self)
-  def remove_operation(self, index):
+    if operation.condition:
+      operation.condition.dependants.add(self)
+  def remove_operation(self, operation):
     """
-    Remove the operation at given index.
+    Remove the Operation.
     Also removes the variable as dependant from all conditions and variables used in this 
-    operation that are no longer used.
+    operation that are no longer used. 
     """
     # Invalidate cached value
     self.invalidate()
     # Remove the operation 
-    operation, condition, expression =  self.operations[index] 
-    self.operations.pop(index)
+    self.operations.remove(operation)
     # Remove dependencies on variables unused in other operations
     vs = self.variables()
-    for v in expression.variables():
+    for v in operation.expression.variables():
       if v not in vs:
        v.dependants.remove(self)
     # Remove the dependency on the conditions (if not used in another operation)
-    if condition and condition not in [e[1] for e in self.operations]:
+    if operation.condition and operation.condition not in [op.condition for op in self.operations]:
       condition.dependants.remove(self)
   def evaluate(self, depth=0):
     """
@@ -248,11 +257,11 @@ class ConfigVar(ConfigElem):
     val = []
     # Scan for last applicable expression - try each starting from the end, concatenate extensions
     for i in range(len(self.operations)-1, -1, -1):
-      operation, condition, expr = self.operations[i]
+      op = self.operations[i]
       # Check the guarding condition
-      if (not condition) or condition.value(depth+1):
-       val.insert(0, expr.evaluate(depth+1))
-       if operation == 'SET':
+      if (not op.condition) or op.condition.value(depth+1):
+       val.insert(0, op.expression.evaluate(depth+1))
+       if op.operation == 'SET':
          return u''.join(val)
     return None
   def dump(self, prefix=''):
@@ -267,8 +276,9 @@ class ConfigVar(ConfigElem):
     except ConfigError: 
       pass
     yield prefix+u'%s = %r' % (self.name, v)
-    for operation, condition, expr in self.operations:
-      yield prefix+u'  %s [%s] %s' % (operation, condition and condition.str(parents=True), expr)
+    for op in self.operations:
+      #yield prefix+u'  %s [%s] %s' % (op.operation, op.condition and op.condition.str(parents=True), op.expression)
+      yield prefix + u'  ' + unicode(op)
 
 class ConfigExpression(object):
   """
index a630e61619f0ddd83a6cd9eb2ed6811e9f86e59b..6c69a8c90853b073d4e69610e7e3b51add1a6ef2 100644 (file)
@@ -1,31 +1,46 @@
-import conf
+import conf, confparser
 import logging as log
-log.getLogger().setLevel(log.DEBUG)
+import unittest
+
+#log.getLogger().setLevel(log.DEBUG)
 
 vcnt = 3
 
 def cs(s):
   return conf.ConfigExpression([s], s)
 
+# WIP
+class Test(unittest.TestCase):
+  def setUp(self):
+    self.t = conf.ConfigTree()    
+  def parse(self, s, level=0, fname='test'):
+    c=confparser.ConfigParser(s, self.t, fname, level)
+    c.parse()
+    c.p_WS()
+    assert c.eof()
+  s1 = r"""a="1";b='2';c.d='\n';e="{a}{b}";e+='{c.d}';a+="\"\n\{\}";f+='Z{a.b}'#comment"""
+  def test_parser_nows(self):
+    self.parse(s1)
+    
 root = conf.ConfigTree()
 
 for i in range(vcnt):
-  root.lookup('a.v%d'%i).add_operation('SET', None, cs('A%d'%i))
+  root.lookup('a.v%d'%i).add_operation(conf.Operation('SET', None, cs('A%d'%i)))
   b = root.lookup('b.v%d'%i)
-  b.add_operation('APPEND', None, cs(' <FOO>'))
-  b.add_operation('SET', None, conf.ConfigExpression([root.lookup('a.v%d'%i)], '{a.v%d}'%i))
-  b.add_operation('APPEND', None, cs(' <BAR>'))
+  b.add_operation(conf.Operation('APPEND', None, cs(' <FOO>')))
+  b.add_operation(conf.Operation('SET', None, conf.ConfigExpression([root.lookup('a.v%d'%i)], '{a.v%d}'%i)))
+  b.add_operation(conf.Operation('APPEND', None, cs(' <BAR>')))
   if i<vcnt-1: 
-    b.add_operation('APPEND', [], conf.ConfigExpression([' [', root.lookup('b.v%d'%(i+1)), ']'], ' [{b.v%d}]'%(i+1)))
+    b.add_operation(conf.Operation('APPEND', None, conf.ConfigExpression([' [', root.lookup('b.v%d'%(i+1)), ']'], ' [{b.v%d}]'%(i+1))))
 print '\n'.join(root.dump())
 
 b0 = root.lookup('b.v0')
-b0.remove_operation(1)
-b0.add_operation('SET', None, cs('NEW-B0'))
-root.lookup('b.v2').add_operation('APPEND', None, cs(' <NEW-B3>'))
-root.lookup('a.v1').add_operation('APPEND', None, cs(' <NEW-A1>'))
+b0.remove_operation(b0.operations[1])
+b0.add_operation(conf.Operation('SET', None, cs('NEW-B0')))
+root.lookup('b.v2').add_operation(conf.Operation('APPEND', None, cs(' <NEW-B3>')))
+root.lookup('a.v1').add_operation(conf.Operation('APPEND', None, cs(' <NEW-A1>')))
 print '\n'.join(root.dump())
 
-root.lookup('a.v0').add_operation('SET', [], cs('<OVERRIDE-A0>'))
+root.lookup('a.v0').add_operation(conf.Operation('SET', None, cs('<OVERRIDE-A0>')))
 print '\n'.join(root.dump())
 print 'maxdepth: %d'%conf.debug_maxdepth