Welcome, guest | Sign In | My Account | Store | Cart
# -*- coding: iso-8859-1 -*-
"""
Handling of arguments: options, arguments, file(s) content iterator

For small scripts that:
- read some command line options
- read some command line positional arguments
- iterate over all lines of some files given on the command line, or stdin if none given
- give usage message if positional arguments are missing
- give usage message if input files are missing and stdin is not redirected
"""

__author__ = 'Peter Kleiweg'
__version__ = '0.2'
__date__ = '2004/08/28'

import os, sys, getopt

class Args:
    """
    Perform common tasks on command line arguments
    
    Instance data:
    progname (string) -- name of program
    opt (dictionary) -- options with values
    infile (string) -- name of current file being processed
    lineno (int) -- line number of last line read in current file
    linesum (int) -- total of lines read
    """

    def __init__(self, usage='Usage: %(progname)s [opt...] [file...]'):
        "init, usage string: embed program name as %(progname)s"
        self.progname = os.path.basename(sys.argv[0])
        self.opt = {}
        self.infile = None
        self.lineno = 0
        self.linesum = 0
        self._argv = sys.argv[1:]
        self._usage = usage

    def __iter__(self):
        "iterator: set-up"
        if self._argv:
            self.infile = self._argv.pop(0)
            self._in = open(self.infile, 'r')
            self._stdin = False
        else:
            if sys.stdin.isatty():
                self.usage()  # Doesn't return
            self.infile = '<stdin>'
            self._in = sys.stdin
            self._stdin = True
        return self

    def next(self):
        "iterator: get next line, possibly from next file"
        while True:
            line = self._in.readline()
            if line:
                self.lineno += 1
                self.linesum += 1
                return line

            if self._stdin:
                break

            self._in.close()
            try:
                self.infile = self._argv.pop(0)
            except IndexError:
                break
            self.lineno = 0
            self._in = open(self.infile, 'r')

        self.lineno = -1
        self.infile = None
        raise StopIteration

    def getopt(self, shortopts, longopts=[]):
        "get options and merge into dict 'opt'"
        try:
            options, self._argv = getopt.getopt(self._argv, shortopts, longopts)
        except getopt.GetoptError:
            self.usage()
        self.opt.update(dict(options))

    def shift(self):
        "pop first of remaining arguments (shift)"
        try:
            return self._argv.pop(0)
        except IndexError:
            self.usage()

    def pop(self):
        "pop last of remaining arguments"
        try:
            return self._argv.pop()
        except IndexError:
            self.usage()

    def warning(self, text):
        "print warning message to stderr, possibly with filename and lineno"
        if self.lineno > 0:
            print >> sys.stderr, '%s:%i: warning: %s' % (self.infile, self.lineno, text)
        else:
            print >> sys.stderr, '\nWarning %s: %s\n' % (self.progname, text)

    def error(self, text):
        "print error message to stderr, possibly with filename and lineno, and exit"
        if self.lineno > 0:
            print >> sys.stderr, '%s:%i: %s' % (self.infile, self.lineno, text)
        else:
            print >> sys.stderr, '\nError %s: %s\n' % (self.progname, text)
        sys.exit(1)

    def usage(self):
        "print usage message, and exit"
        print >> sys.stderr
        print >> sys.stderr, self._usage % {'progname': self.progname}
        print >> sys.stderr        
        sys.exit(1)


if __name__ == '__main__':

    a = Args('Usage: %(progname)s [-a value] [-b value] [-c] word [file...]')

    a.opt['-a'] = 'option a'    # set some default option values
    a.opt['-b'] = 'option b'    #
    a.getopt('a:b:c')           # get user supplied option values

    word = a.shift()            # get the first of the remaining arguments
                                # use a.pop() to get the last instead

    for line in a:              # iterate over the contents of all remaining arguments (file names)
        if a.lineno == 1:
            print 'starting new file:', a.infile
        a.warning(line.rstrip())

    print 'Options:', a.opt
    print 'Word:', word
    print 'Total number of lines:', a.linesum

    print 'Command line:', sys.argv     # unchanged

    a.warning('warn 1')         # print a warning
    a.error('error')            # print an error message and exit
    a.warning('warn 2')         # this won't show

History

  • revision 4 (19 years ago)
  • previous revisions are not available