apt like column output - python library
Question: Debian's apt tool outputs results in uniform width columns. For instance, try
running "aptitude search svn" .. and all names appear in the first column of
the same width.

Now if you resize the terminal, the column width is adjusted accordingly.

Is there a Python library that enables one to do this? Note that the library
has to be aware of the terminal width and take a table as input - which could
be, for instance, `[('rapidsvn', 'A GUI client for subversion'), ...]` .. and
you may also specify a max-width for the first column (or any column). Also
note how the string in the second column below is trimmed if exceeds the
terminal width .. thus not introducing the undesired second line.

    
    
    $ aptitude search svn
    [...]
    p   python-svn-dbg                    - A(nother) Python interface to Subversion (d
    v   python2.5-svn                     -                                            
    v   python2.6-svn                     -                                            
    p   rapidsvn                          - A GUI client for subversion                
    p   statsvn                           - SVN repository statistics                  
    p   svn-arch-mirror                   - one-way mirroring from Subversion to Arch r
    p   svn-autoreleasedeb                - Automatically release/upload debian package
    p   svn-buildpackage                  - helper programs to maintain Debian packages
    p   svn-load                          - An enhanced import facility for Subversion 
    p   svn-workbench                     - A Workbench for Subversion                 
    p   svnmailer                         - extensible Subversion commit notification t
    p   websvn                            - interface for subversion repositories writt
    $
    

**EDIT** : (in response to Alex's answer below) ... the output will be similar
to 'aptitude search' in that 1) only the last column (which is the only column
with the longest string in a row) is to be trimmed, 2) there are typically 2-4
columns only, but the last column ("description") is expected to take at least
half the terminal width. 3) all rows contain equal number of columns, 4) all
entries are strings only


Answer: **Update** : The `colprint` routine is now available in the
[applib](http://code.activestate.com/pypm/applib/) Python library [hosted in
GitHub](https://github.com/ActiveState/applib/blob/master/applib/textui.py#L213).

Here's the complete program for those of you interested:

    
    
    # This function was written by Alex Martelli
    # http://stackoverflow.com/questions/1396820/
    def colprint(table, totwidth=None):
        """Print the table in terminal taking care of wrapping/alignment
    
        - `table`:    A table of strings. Elements must not be `None`
        - `totwidth`: If None, console width is used
        """
        if not table: return
        if totwidth is None:
            totwidth = find_console_width()
            totwidth -= 1 # for not printing an extra empty line on windows
        numcols = max(len(row) for row in table)
        # ensure all rows have >= numcols columns, maybe empty
        padded = [row+numcols*('',) for row in table]
        # compute col widths, including separating space (except for last one)
        widths = [ 1 + max(len(x) for x in column) for column in zip(*padded)]
        widths[-1] -= 1
        # drop or truncate columns from the right in order to fit
        while sum(widths) > totwidth:
            mustlose = sum(widths) - totwidth
            if widths[-1] <= mustlose:
                del widths[-1]
            else:
                widths[-1] -= mustlose
                break
        # and finally, the output phase!
        for row in padded:
            print(''.join([u'%*s' % (-w, i[:w])
                           for w, i in zip(widths, row)]))
    
    def find_console_width():
        if sys.platform.startswith('win'):
            return _find_windows_console_width()
        else:
            return _find_unix_console_width()
    def _find_unix_console_width():
        """Return the width of the Unix terminal
    
        If `stdout` is not a real terminal, return the default value (80)
        """
        import termios, fcntl, struct, sys
    
        # fcntl.ioctl will fail if stdout is not a tty
        if not sys.stdout.isatty():
            return 80
    
        s = struct.pack("HHHH", 0, 0, 0, 0)
        fd_stdout = sys.stdout.fileno()
        size = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
        height, width = struct.unpack("HHHH", size)[:2]
        return width
    def _find_windows_console_width():
        """Return the width of the Windows console
    
        If the width cannot be determined, return the default value (80)
        """
        # http://code.activestate.com/recipes/440694/
        from ctypes import windll, create_string_buffer
        STDIN, STDOUT, STDERR = -10, -11, -12
    
        h = windll.kernel32.GetStdHandle(STDERR)
        csbi = create_string_buffer(22)
        res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
    
        if res:
            import struct
            (bufx, bufy, curx, cury, wattr,
             left, top, right, bottom,
             maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
            sizex = right - left + 1
            sizey = bottom - top + 1
        else:
            sizex, sizey = 80, 25
    
        return sizex
    

