cinap_lenrekadd hg and python4bb9e2215 years agoHistory
634 lines · 16.3 KB · Python
RawDownload
""" CommandLine - Get and parse command line options     NOTE: This still is very much work in progress !!!     Different version are likely to be incompatible.     TODO:     * Incorporate the changes made by (see Inbox)    * Add number range option using srange() """ __copyright__ = """\Copyright (c), 1997-2006, Marc-Andre Lemburg (mal@lemburg.com)Copyright (c), 2000-2006, eGenix.com Software GmbH (info@egenix.com)See the documentation for further information on copyrights,or contact the author. All Rights Reserved.""" __version__ = '1.2' import sys, getopt, string, glob, os, re, exceptions, traceback ### Helpers def _getopt_flags(options):     """ Convert the option list to a getopt flag string and long opt        list     """    s = []    l = []    for o in options:        if o.prefix == '-':            # short option            s.append(o.name)            if o.takes_argument:                s.append(':')        else:            # long option            if o.takes_argument:                l.append(o.name+'=')            else:                l.append(o.name)    return string.join(s,''),l def invisible_input(prompt='>>> '):     """ Get raw input from a terminal without echoing the characters to        the terminal, e.g. for password queries.     """    import getpass    entry = getpass.getpass(prompt)    if entry is None:        raise KeyboardInterrupt    return entry def fileopen(name, mode='wb', encoding=None):     """ Open a file using mode.         Default mode is 'wb' meaning to open the file for writing in        binary mode. If encoding is given, I/O to and from the file is        transparently encoded using the given encoding.         Files opened for writing are chmod()ed to 0600.     """    if name == 'stdout':        return sys.stdout    elif name == 'stderr':        return sys.stderr    elif name == 'stdin':        return sys.stdin    else:        if encoding is not None:            import codecs            f = codecs.open(name, mode, encoding)        else:            f = open(name, mode)        if 'w' in mode:            os.chmod(name, 0600)        return f def option_dict(options):     """ Return a dictionary mapping option names to Option instances.    """    d = {}    for option in options:        d[option.name] = option    return d # Aliasgetpasswd = invisible_input _integerRE = re.compile('\s*(-?\d+)\s*$')_integerRangeRE = re.compile('\s*(-?\d+)\s*-\s*(-?\d+)\s*$') def srange(s,            split=string.split,integer=_integerRE,           integerRange=_integerRangeRE):     """ Converts a textual representation of integer numbers and ranges        to a Python list.         Supported formats: 2,3,4,2-10,-1 - -3, 5 - -2         Values are appended to the created list in the order specified        in the string.     """    l = []    append = l.append    for entry in split(s,','):        m = integer.match(entry)        if m:            append(int(m.groups()[0]))            continue        m = integerRange.match(entry)        if m:            start,end = map(int,m.groups())            l[len(l):] = range(start,end+1)    return l def abspath(path,             expandvars=os.path.expandvars,expanduser=os.path.expanduser,            join=os.path.join,getcwd=os.getcwd):     """ Return the corresponding absolute path for path.         path is expanded in the usual shell ways before        joining it with the current working directory.     """    try:        path = expandvars(path)    except AttributeError:        pass    try:        path = expanduser(path)    except AttributeError:        pass    return join(getcwd(), path) ### Option classes class Option:     """ Option base class. Takes no argument.     """    default = None    helptext = ''    prefix = '-'    takes_argument = 0    has_default = 0    tab = 15     def __init__(self,name,help=None):         if not name[:1] == '-':            raise TypeError,'option names must start with "-"'        if name[1:2] == '-':            self.prefix = '--'            self.name = name[2:]        else:            self.name = name[1:]        if help:            self.help = help     def __str__(self):         o = self        name = o.prefix + o.name        if o.takes_argument:            name = name + ' arg'        if len(name) > self.tab:            name = name + '\n' + ' ' * (self.tab + 1 + len(o.prefix))        else:            name = '%-*s ' % (self.tab, name)        description = o.help        if o.has_default:            description = description + ' (%s)' % o.default        return '%s %s' % (name, description) class ArgumentOption(Option):     """ Option that takes an argument.         An optional default argument can be given.     """    def __init__(self,name,help=None,default=None):         # Basemethod        Option.__init__(self,name,help)         if default is not None:            self.default = default            self.has_default = 1        self.takes_argument = 1 class SwitchOption(Option):     """ Options that can be on or off. Has an optional default value.     """    def __init__(self,name,help=None,default=None):         # Basemethod        Option.__init__(self,name,help)         if default is not None:            self.default = default            self.has_default = 1 ### Application baseclass class Application:     """ Command line application interface with builtin argument        parsing.     """    # Options the program accepts (Option instances)    options = []     # Standard settings; these are appended to options in __init__    preset_options = [SwitchOption('-v',                                   'generate verbose output'),                      SwitchOption('-h',                                   'show this help text'),                      SwitchOption('--help',                                   'show this help text'),                      SwitchOption('--debug',                                   'enable debugging'),                      SwitchOption('--copyright',                                   'show copyright'),                      SwitchOption('--examples',                                   'show examples of usage')]     # The help layout looks like this:    # [header]   - defaults to ''    #    # [synopsis] - formatted as '<self.name> %s' % self.synopsis    #    # options:    # [options]  - formatted from self.options    #    # [version]  - formatted as 'Version:\n %s' % self.version, if given    #    # [about]    - defaults to ''    #    # Note: all fields that do not behave as template are formatted    #       using the instances dictionary as substitution namespace,    #       e.g. %(name)s will be replaced by the applications name.    #     # Header (default to program name)    header = ''     # Name (defaults to program name)    name = ''     # Synopsis (%(name)s is replaced by the program name)    synopsis = '%(name)s [option] files...'     # Version (optional)    version = ''     # General information printed after the possible options (optional)    about = ''     # Examples of usage to show when the --examples option is given (optional)    examples = ''     # Copyright to show    copyright = __copyright__     # Apply file globbing ?    globbing = 1     # Generate debug output ?    debug = 0     # Generate verbose output ?    verbose = 0     # Internal errors to catch    InternalError = exceptions.Exception     # Instance variables:    values = None       # Dictionary of passed options (or default values)                        # indexed by the options name, e.g. '-h'    files = None        # List of passed filenames    optionlist = None   # List of passed options     def __init__(self,argv=None):         # Setup application specs        if argv is None:            argv = sys.argv        self.filename = os.path.split(argv[0])[1]        if not self.name:            self.name = os.path.split(self.filename)[1]        else:            self.name = self.name        if not self.header:            self.header = self.name        else:            self.header = self.header         # Init .arguments list        self.arguments = argv[1:]         # Setup Option mapping        self.option_map = option_dict(self.options)         # Append preset options        for option in self.preset_options:            if not self.option_map.has_key(option.name):                self.add_option(option)         # Init .files list        self.files = []         # Start Application        try:            # Process startup            rc = self.startup()            if rc is not None:                raise SystemExit,rc             # Parse command line            rc = self.parse()            if rc is not None:                raise SystemExit,rc             # Start application            rc = self.main()            if rc is None:                rc = 0         except SystemExit,rc:            pass         except KeyboardInterrupt:            print            print '* User Break'            print            rc = 1         except self.InternalError:            print            print '* Internal Error (use --debug to display the traceback)'            if self.debug:                print                traceback.print_exc(20, sys.stdout)            elif self.verbose:                print '  %s: %s' % sys.exc_info()[:2]            print            rc = 1         raise SystemExit,rc     def add_option(self, option):         """ Add a new Option instance to the Application dynamically.             Note that this has to be done *before* .parse() is being            executed.         """        self.options.append(option)        self.option_map[option.name] = option     def startup(self):         """ Set user defined instance variables.             If this method returns anything other than None, the            process is terminated with the return value as exit code.         """        return None     def exit(self, rc=0):         """ Exit the program.             rc is used as exit code and passed back to the calling            program. It defaults to 0 which usually means: OK.         """        raise SystemExit, rc     def parse(self):         """ Parse the command line and fill in self.values and self.files.             After having parsed the options, the remaining command line            arguments are interpreted as files and passed to .handle_files()            for processing.             As final step the option handlers are called in the order            of the options given on the command line.         """        # Parse arguments        self.values = values = {}        for o in self.options:            if o.has_default:                values[o.prefix+o.name] = o.default            else:                values[o.prefix+o.name] = 0        flags,lflags = _getopt_flags(self.options)        try:            optlist,files = getopt.getopt(self.arguments,flags,lflags)            if self.globbing:                l = []                for f in files:                    gf = glob.glob(f)                    if not gf:                        l.append(f)                    else:                        l[len(l):] = gf                files = l            self.optionlist = optlist            self.files = files + self.files        except getopt.error,why:            self.help(why)            sys.exit(1)         # Call file handler        rc = self.handle_files(self.files)        if rc is not None:            sys.exit(rc)         # Call option handlers        for optionname, value in optlist:             # Try to convert value to integer            try:                value = string.atoi(value)            except ValueError:                pass             # Find handler and call it (or count the number of option            # instances on the command line)            handlername = 'handle' + string.replace(optionname, '-', '_')            try:                handler = getattr(self, handlername)            except AttributeError:                if value == '':                    # count the number of occurances                    if values.has_key(optionname):                        values[optionname] = values[optionname] + 1                    else:                        values[optionname] = 1                else:                    values[optionname] = value            else:                rc = handler(value)                if rc is not None:                    raise SystemExit, rc         # Apply final file check (for backward compatibility)        rc = self.check_files(self.files)        if rc is not None:            sys.exit(rc)     def check_files(self,filelist):         """ Apply some user defined checks on the files given in filelist.             This may modify filelist in place. A typical application            is checking that at least n files are given.             If this method returns anything other than None, the            process is terminated with the return value as exit code.         """        return None     def help(self,note=''):         self.print_header()        if self.synopsis:            print 'Synopsis:'            # To remain backward compatible:            try:                synopsis = self.synopsis % self.name            except (NameError, KeyError, TypeError):                synopsis = self.synopsis % self.__dict__

Lines 1–500 of 634.