From: Tomas Gavenciak Date: Tue, 25 May 2010 01:55:07 +0000 (-0400) Subject: Changes to config operations structure. X-Git-Tag: python-dummy-working~57 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=39d68d7ef0f2c30bea24993f9e39292e56903f9e;p=moe.git Changes to config operations structure. 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. --- diff --git a/t/moe/conf.py b/t/moe/conf.py index 37219cc..6856754 100644 --- a/t/moe/conf.py +++ b/t/moe/conf.py @@ -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): """ diff --git a/t/moe/conf.test.py b/t/moe/conf.test.py index a630e61..6c69a8c 100644 --- a/t/moe/conf.test.py +++ b/t/moe/conf.test.py @@ -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(' ')) - b.add_operation('SET', None, conf.ConfigExpression([root.lookup('a.v%d'%i)], '{a.v%d}'%i)) - b.add_operation('APPEND', None, cs(' ')) + b.add_operation(conf.Operation('APPEND', None, cs(' '))) + 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(' '))) if i')) -root.lookup('a.v1').add_operation('APPEND', None, cs(' ')) +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(' '))) +root.lookup('a.v1').add_operation(conf.Operation('APPEND', None, cs(' '))) print '\n'.join(root.dump()) -root.lookup('a.v0').add_operation('SET', [], cs('')) +root.lookup('a.v0').add_operation(conf.Operation('SET', None, cs(''))) print '\n'.join(root.dump()) print 'maxdepth: %d'%conf.debug_maxdepth