Advertisement
Guest User

columnizer.py

a guest
Feb 15th, 2013
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.43 KB | None | 0 0
  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