import types, itertools, re, bisect
import logging as log
-from confparser import re_VARNAME
"Allowed depth of recursion - includes ALL recursive calls, so should quite high."
c_maxdepth = 256
"Maximum attained depth of recursion - for debug/testing"
debug_maxdepth = 0
+"Variable name regexp, dots (separators) must be separated from edges and each other."
+re_VARNAME = re.compile(r'\A([A-Za-z0-9_-]+\.)*[A-Za-z0-9_-]+\Z')
+
def check_depth(depth):
"Helper to check for recursion depth."
global debug_maxdepth
if depth > c_maxdepth:
- raise ConfigError('Too deep recursion in config evaluation (cyclic substitution?)')
+ raise CyclicConfigError('Too deep recursion in config evaluation (cyclic substitution?)')
if depth > debug_maxdepth:
debug_maxdepth = depth
class ConfigError(Exception):
pass
+class UndefinedError(ConfigError):
+ pass
+
+class VariableNameError(ConfigError):
+ pass
+
+class CyclicConfigError(ConfigError):
+ pass
+
class ConfigTree(object):
"""
Lookup and return a variable.
If not found and `create` set, check the name and transparently create a new one.
"""
- if not key in self.variables:
- if not create:
- raise ConfigError('Config variable %r undefined.', key)
+ if key not in self.variables:
if not re_VARNAME.match(key):
- raise ConfigError('Invalid variable identifier %r in config', key)
+ raise VariableNameError('Invalid variable identifier %r in config', key)
+ if not create:
+ raise UndefinedError('Config variable %r undefined.', key)
self.variables[key] = ConfigVar(key)
return self.variables[key]
def dump(self, prefix=''):
self.cached_val = self.evaluate(depth=depth+1)
self.cached = True
if self.cached_val == None:
- raise ConfigError("Unable to evaluate %r."%(self.name,))
+ raise UndefinedError("Unable to evaluate %r."%(self.name,))
return self.cached_val
def __str__(self):
return self.name
import traceback
import conf
-class ConfigSyntaxError(Exception):
- # TODO: choose a better superclass
+class ConfigSyntaxError(conf.ConfigError):
def __init__(self, msg, fname='<unknown>', line=None, column=None):
self.msg = msg
self.fname = fname
def __str__(self):
return('ConfigSyntaxError %s:%d:%d: %s'%(self.fname, self.line, self.column, self.msg))
-"Variable name regexp, dots (separators) must be separated from edges and each other."
-re_VARNAME = re.compile(r'\A([A-Za-z0-9_-]+\.)*[A-Za-z0-9_-]+\Z')
-
class ConfigParser(object):
c_varname_sep = u'.'
c_comment = u'#'
def next(self, l = 1):
"Eat and return next `l` unicode characters. Raise exception on EOF."
if not self.preread(l):
- raise ConfigSyntaxError("Unexpected end of file")
+ self.syntax_error("Unexpected end of file")
s = self.buf[self.bufpos:self.bufpos+l]
self.bufpos += l
rnl = s.rfind('\n')
while self.peek().isalnum() or self.peek() in u'-_.':
vnl.append(self.next())
vn = u''.join(vnl)
- if not re_VARNAME.match(vn):
+ if not conf.re_VARNAME.match(vn):
self.syntax_error('Invalid variable name %r', vn)
return vn
def p_EXPRESSION(self):