NOTE: All expanded data should be (or is converted to) unicode
-TODO: Fixing value of variables.
TODO: Cleanup of unused undefined variables.
TODO: Better variable name checking (no name '.'-structural prefix of another)
TODO: Implemet "subtree" listing.
-TODO: Test conditions and unicode
+TODO: Test fixing, conditions and unicode
"""
import types, itertools, re, bisect
class VariableNameError(ConfigError):
pass
+class VariableFixedError(ConfigError):
+ pass
+
class CyclicConfigError(ConfigError):
pass
# Ordered list of `Operations` (ascending by `level`)
self.operations = []
# 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(op.expression.variables()) for op in self.operations ], []))
+ def fix(self):
+ """
+ Fixes the value of the variable. Exception is raised should the variable
+ evaluate to a different value while fixed.
+ """
+ if self.fixed:
+ return
+ self.fixed = True
+ self.fixed_val = self.value()
+ def unfix(self):
+ "Set the variable to be 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)
+ return val
def add_operation(self, operation):
"""
Inserts an operation. The operations are sorted by `level` (ascending), new operation goes last among