Advertisement
Guest User

columnizer.py

a guest
Feb 15th, 2013
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. from __future__ import division
  2.  
  3. from collections import namedtuple
  4. from itertools import count
  5. from math import ceil
  6.  
  7. try:
  8.     range = xrange
  9. except NameError:
  10.     pass
  11.  
  12. def columnize(items, spacing=2, max_line_width=80):
  13.     line_properties = get_line_properties(items, spacing, max_line_width)
  14.     formatter = Formatter(line_properties, items)
  15.     return '\n'.join(formatter.line_strings)
  16.  
  17. def get_line_properties(items, spacing, max_line_width):
  18.     for value in (spacing, max_line_width):
  19.         if not isinstance(value, int) or value < 0:
  20.             msg = 'spacing and max_line_width must be non-negative integers'
  21.             raise ValueError(msg)
  22.     item_widths = [len(item) for item in items]
  23.     if max(item_widths) >= max_line_width:
  24.         return LineProperties([max_line_width], spacing)
  25.     num_items = len(item_widths)
  26.     for chunk_size in count(1):
  27.         column_widths = [max(item_widths[i : i + chunk_size])
  28.                          for i in range(0, num_items, chunk_size)]
  29.         line_width = sum(column_widths) + (len(column_widths) - 1) * spacing
  30.         if line_width <= max_line_width:
  31.             break
  32.     return LineProperties(column_widths, spacing)
  33.  
  34. LineProperties = namedtuple('LineProperties', 'column_widths, spacing')
  35.  
  36. class Formatter(object):
  37.     def __init__(self, line_properties, items=[]):
  38.         self.line_properties = line_properties
  39.         self.items = items
  40.  
  41.     @property
  42.     def line_strings(self):
  43.         num_lines = int(ceil(len(self.items) / self.num_columns))
  44.         template = self.get_line_template()
  45.         for i in range(num_lines):
  46.             line_items = self.items[i::num_lines]
  47.             try:
  48.                 yield template % tuple(line_items)
  49.             except TypeError:
  50.                 # raised if last line contains too few items for line template
  51.                 # -> re-generate template for real number of items
  52.                 template = self.get_line_template(len(line_items))
  53.                 yield template % tuple(line_items)
  54.  
  55.     @property
  56.     def num_columns(self):
  57.         return len(self.line_properties.column_widths)
  58.  
  59.     def get_line_template(self, max_items=-1):
  60.         if max_items < 0 or max_items > self.num_columns:
  61.             max_items = self.num_columns
  62.         specs = ('%%-%ds' % width
  63.                  for width in self.line_properties.column_widths[:max_items])
  64.         return (self.line_properties.spacing * ' ').join(specs)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement