bpeterso2000
5/5/2014 - 4:36 AM

Emulating cat to demo creating Unix command look & feel with argparse

Emulating cat to demo creating Unix command look & feel with argparse

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
argparse Unix command demo
--------------------------
Simple demonstration of using argparse to emulated a Unix command's look & feel
Demonstrates stdin.

Emulates Unix 'cat' <GNU textutils> written by Torborjn Ganlund and
Richard M. Stallman.  Note: Emulating the command is not all that useful
except that it provides something to compare against when demonstrating
argparse basics.
"""

__version__ = '0.1'
__author__ = '<author name(s)>'
__copyright__ = 'Copyright (c) <year> <person/organization>'
__license__ = '''
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.'''

import argparse
import fileinput
import sys
from glob import glob
from itertools import chain


def readlines(filenames, number):
    if filenames:
        filenames = chain.from_iterable(glob(i) for i in filenames)
    for line in fileinput.input(filenames):
        yield line


def squeeze_blanks(lines):
    for line in lines:
        if line.strip():
            yield line


def number_nonblanks(lines):
    linenum = 0
    for line in lines:
        if line.strip():
            linenum += 1
            yield '{} {}'.format(linenum, line)
        else:
            yield line


def number(lines):
    for line in lines:
        yield '{} {}'.format(fileinput.lineno(), line)


def show_ends(lines):
    for line in lines:
        yield line + '$'


def get_char(ord_):
    if ord_ >= 0o40 and ord_ < 0o177:
        # printable character
        result = chr(ord_)
    elif ord_ > 0o177:
        # meta-character
        result = 'M-' + chr(ord_ + 0o200)
    else:
        # control character
        result = '^' + chr(ord_ + 0o100)
    return result


def show_nonprinting(lines):
    for line in lines:
        yield ''.join([get_char(oct(ord(i))) for i in line])


def main(args):
    lines = readlines(args.filenames, args.number)
    if args.squeeze_blank:
        lines = (i for i in lines if i.strip())
    if args.number_nonblank and not (args.squeeze_blank and args.number):
        lines = number_nonblanks(lines)
    elif args.number:
        lines = ('{} {}'.format(fileinput.lineno(), i) for i in lines)
    if args.show_ends:
        lines = (i + '$' for i in lines)
    if args.show_tabs:
        lines = (i.replace('\t', '^I') for i in lines)
    if args.show_nonprinting:
        lines = show_nonprinting(lines)
    for line in lines:
        sys.stdout.write(line)


if __name__ == '__main__':

# epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
    description = 'Concatenate FILE(s), or standard input, to standard output.'
    epilog = ('With no FILE, or when FILE is -, read standard input.\n\n'
              'Report bugs to <bpeterso2000@yahoo.com>')
    formatter = argparse.RawDescriptionHelpFormatter
    parser = argparse.ArgumentParser(description=description, epilog=epilog,
                                     formatter_class=formatter)
    version = ("%(prog)s {version}\n{author}\n\n{copyright}\n{license}")
    version = version.format(version=__version__, author=__author__,
                             copyright=__copyright__, license=license)
    parser.add_argument('--version', action='version', version=version,
                        help='display this help and exit')
    parser.add_argument('-A', '--show-all', action='store_true',
                        dest='show_all', help='equivalent to -vET')
    parser.add_argument('-b', '--number-nonblank', action='store_true',
                        dest='number_nonblank',
                        help='number nonblank output lines')
    parser.add_argument('-e', action='store_true',
                        help='equivalent to -vE')
    parser.add_argument('-E', '--show-ends', action='store_true',
                        dest='show_ends', help='display $ at end of each line')
    parser.add_argument('-n', '--number', action='store_true',
                        help='number all output lines')
    parser.add_argument('-s', '--squeeze-blank', action='store_true',
                        dest='squeeze_blank',
                        help='never more than one single blank line')
    parser.add_argument('-t', action='store_true',
                        help='equivalent to -vT')
    parser.add_argument('-T', '--show-tabs', action='store_true',
                        dest='show_tabs', help='display TAB characters as ^I')
    parser.add_argument('-u', action=None, help='(ignored)')
    parser.add_argument('-v', '--show-nonprinting', action='store_true',
                        dest='show_nonprinting',
                        help='use ^ and M- notation, except for LFD and TAB')
    parser.add_argument('filenames', nargs='*')
    args = parser.parse_args()
    print(args)
    for option, flags in {'show-all': 'vET', 'e': 'vE', 't': 'vT'}.items():
        if option in vars(args):
            for flag in flags:
                setattr(args, flag, True)
    main(args)