+#------------------------------------------------------------------#
+# #
+# COMMAND LINE ARGUMENTS PARSER #
+# #
+#------------------------------------------------------------------#
+
+#===================================================================
+# class OptBaseError : base parse error
+#===================================================================
+class OptBaseError(Exception):
+ """
+ Base option parsing exception class
+ """
+ def __init__(self, msg):
+ self.msg = msg
+ def __str__ (self):
+ return self.msg
+
+#===================================================================
+# class OptError : bad option error
+#===================================================================
+class OptError(OptBaseError):
+ """
+ Bad option exception class
+ """
+ def __init__ (self, msg, option):
+ self.msg = msg
+ self.option = option
+ def __str__ (self):
+ if self.option:
+ opt_prs = "<unknown>"
+ if self.option.short_opt and self.option.long_opt:
+ opt_prs = "%s/%s"%(self.option.short_opt,self.option.long_opt)
+ elif self.option.short_opt:
+ opt_prs = "%s"%(self.option.short_opt)
+ elif self.option.long_opt:
+ opt_prs = "%s"%(self.option.long_opt)
+ return "option %s: %s"%(opt_prs, self.msg)
+ return self.msg
+
+#===================================================================
+# class ArgError : bad option argument error
+#===================================================================
+class ArgError(OptBaseError):
+ """
+ Bad argument exception class
+ """
+ pass
+
+#===================================================================
+# class ValError : bad command line parameter error
+#===================================================================
+class ValError(OptBaseError):
+ """
+ Bad parameter exception class
+ """
+ pass
+
+#===================================================================
+# class ArgOption : command line option
+#===================================================================
+class ArgOption:
+ """
+ Option class
+ """
+ attrs = ["short_opt", "long_opt", "dest", "action", "type", "default", "metavar", "help"]
+ actions = ["store", "store_true", "store_false"]
+ types = ["string", "int", "float", "bool"]
+ def __init__(self, *args, **kwargs):
+ # set defaults
+ for attr in self.attrs: setattr(self, attr, None)
+ # parse arguments
+ for i in range(len(args)):
+ if i > len(self.attrs)-1:
+ msg = "Wrong number of parameters is given (maximum is %d)" % len(self.attrs)
+ raise OptBaseError(msg)
+ setattr(self, self.attrs[i], args[i])
+ for arg in kwargs:
+ if arg not in self.attrs:
+ msg = "Invalid argument: %s" % arg
+ raise OptBaseError(msg)
+ setattr(self, arg, kwargs[arg])
+ # check short option key
+ if self.short_opt and \
+ not re.match("^-[a-zA-Z]$",self.short_opt):
+ msg = "invalid short option key; "
+ msg += "should be of the form -x (x is letter)"
+ raise OptError(msg, self)
+ # check long option key
+ if self.long_opt and \
+ not re.match("^--[a-zA-Z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*$",self.long_opt):
+ msg = "invalid long option key; "
+ msg += "should be of the form --word[[-word]...] "
+ msg += "(word is letters and digits sequence)"
+ raise OptError(msg, self)
+ # check that at least one option key is defined
+ if not self.short_opt and not self.long_opt:
+ msg = "invalid option; neither short nor long option key is defined"
+ raise OptError(msg, self)
+ # destination
+ if not self.dest and self.long_opt:
+ self.dest = self.long_opt[2:].replace('-','_')
+ if not self.dest and self.short_opt:
+ self.dest = self.short_opt[1:]
+ # action
+ if not self.action:
+ self.action = "store"
+ if self.action not in self.actions:
+ msg = "invalid action: %s" % self.action
+ raise OptError(msg, self)
+ # type
+ if not self.type:
+ if self.action in ["store_true","store_false"]: self.type = "bool"
+ else: self.type = "string"
+ if self.type not in self.types:
+ msg = "invalid type: %s" % self.type
+ raise OptError(msg, self)
+ if self.action in ["store_true","store_false"] and self.type != "bool":
+ msg = "invalid type: %s : should be 'bool' or None" % self.type
+ raise OptError(msg, self)
+ # default
+ if self.default is not None:
+ try:
+ if self.type == "string": self.default = str(self.default)
+ if self.type == "int": self.default = int(self.default)
+ if self.type == "float": self.default = float(self.default)
+ if self.type == "bool": self.default = boolean(self.default)
+ except :
+ msg = "invalid default value type: should be %s" % self.type
+ raise OptError(msg, self)
+ pass
+ # metavar
+ if not self.metavar:
+ self.metavar = self.dest.upper()
+ # help
+ if not self.help:
+ self.help = ""
+ pass
+
+ def to_string(self):
+ """
+ Returns string representation of the option
+ """
+ opts = []
+ opt = self.short_opt
+ if opt and self.action == "store" and self.metavar: opt += " %s" % self.metavar
+ if opt: opts.append(opt)
+ opt = self.long_opt
+ if opt and self.action == "store" and self.metavar: opt += "=%s" % self.metavar
+ if opt: opts.append(opt)
+ return (", ").join(opts)
+
+#===================================================================
+# class Values : resulting option values
+#===================================================================
+class Values:
+ """
+ Values class
+ """
+ def __init__(self):
+ pass
+
+#===================================================================
+# class ArgParser : command line arguments parser
+#===================================================================
+class ArgParser:
+ """
+ Arguments parser class
+ """
+ def __init__(self):
+ self.options = []
+ pass
+
+ def add_option(self, *args, **kwargs):
+ """Register an option"""
+ o = ArgOption(*args, **kwargs)
+ self._check_option(o)
+ self.options.append(o)
+ pass
+
+ def parse_args(self, args = None):
+ """Parse an arguments"""
+ if not args: args = sys.argv[1:]
+ values = Values()
+ for o in self.options:
+ if o.default is not None:
+ setattr(values, o.dest, o.default)
+ elif not hasattr(values,o.dest):
+ setattr(values, o.dest, None)
+ try:
+ (values, args) = self._process_args(values, args)
+ except (ArgError, ValError), e:
+ self._error(e.msg)
+
+ return (values, args)
+
+ def print_usage(self):
+ """Print usage"""
+ print "usage: %s [options]" % os.path.basename(sys.argv[0])
+ pass
+
+ def print_help(self):
+ """Print help"""
+ self.print_usage()
+ print ""
+ olen = 0
+ _maxwidth, _indent = 79, 2
+ if len(self.options):
+ for option in self.options:
+ if olen < len(option.to_string()): olen = len(option.to_string())
+ print "options:"
+ for option in self.options:
+ strings = []
+ for hs in option.help.split("\n"):
+ s = ""
+ for w in hs.split():
+ if len("%s %s" % (s,w)) > _maxwidth:
+ strings.append(s.strip()); s = ""
+ s = "%s %s" % (s,w)
+ if s.strip(): strings.append(s.strip())
+ if not strings: strings[:0] = [""]
+ print "%s%s%s" % (option.to_string(), " "*(_indent+olen-len(option.to_string())), strings[0])
+ for i in range(1, len(strings)):
+ print "%s%s" % (" "*(olen+_indent), strings[i])
+ pass
+
+ def _check_option(self, option):
+ o = self._get_option(option.short_opt)
+ if not o: o = self._get_option(option.long_opt)
+ if o:
+ msg = "option conflicts with previously defined option(s)"
+ raise OptError(msg, option)
+ pass
+
+ def _get_option(self, opt_key):
+ if opt_key:
+ for o in self.options:
+ if opt_key in [o.short_opt, o.long_opt]: return o
+ return None
+
+ def _error(self, msg):
+ self.print_usage()
+ sys.exit("\n%s: error: %s\n" % (os.path.basename(sys.argv[0]), msg))
+ pass
+
+ def _check_value(self, option, value):
+ o = self._get_option(option)
+ try:
+ if o.type == "string": return str(value)
+ if o.type == "int": return int(value)
+ if o.type == "float": return float(value)
+ if o.type == "bool": return boolean(value)
+ except:
+ msg = "invalid value type for option %s: %s; " % (option, value)
+ msg += "should be %s" % o.type
+ raise ValError(msg)
+ raise OptBaseError("unknown error")
+
+ def _process_args(self, values, args):
+ res_args = []
+ cur_opt = None
+ rargs = []
+ for index in range(len(args)):
+ a = args[index]
+ if cur_opt and cur_opt[1].action == "store":
+ setattr(values, cur_opt[1].dest, self._check_value(cur_opt[0], a))
+ cur_opt = None
+ continue
+ if a == "-":
+ rargs = args[index+1:]
+ break
+ elif re.match("^-[a-zA-Z].*", a):
+ for i in range(1,len(a)):
+ if cur_opt and cur_opt[1].action == "store":
+ setattr(values, cur_opt[1].dest, self._check_value(cur_opt[0], a[i:]))
+ cur_opt = None
+ break
+ o = self._get_option("-%s"%a[i])
+ if not o:
+ raise ArgError("no such option: -%s"%a[i])
+ if o.action == "store_true":
+ setattr(values, o.dest, True)
+ elif o.action == "store_false":
+ setattr(values, o.dest, False)
+ else:
+ cur_opt = ("-%s"%a[i], o)
+ pass
+ elif re.match("^--[a-zA-Z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*", a):
+ oname = ("%s="%a).split("=")[0]
+ ovalue = ("%s="%a).split("=")[1]
+ o = self._get_option(oname)
+ if not o:
+ raise ArgError("no such option: %s" % oname)
+ if o.action == "store_true":
+ if ovalue:
+ raise ValError("option %s does not take a value" % oname)
+ setattr(values, o.dest, True)
+ elif o.action == "store_false":
+ if ovalue:
+ raise ValError("option %s does not take a value" % oname)
+ setattr(values, o.dest, False)
+ else:
+ if ovalue:
+ setattr(values, o.dest, self._check_value(oname, ovalue))
+ else:
+ cur_opt = (oname, o)
+ pass
+ elif a.startswith("-"):
+ raise ArgError("bad formatted option: %s" % a)
+ else:
+ rargs = args[index:]
+ break
+ if cur_opt and cur_opt[1].action == "store":
+ raise ValError("option %s requires value" % cur_opt[0])
+ return (values, rargs)
+
+#------------------------------------------------------------------#
+# #
+# XML CONFIGURATION FILES PARSER #
+# #
+#------------------------------------------------------------------#