Advertisement
Guest User

Untitled

a guest
May 23rd, 2019
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.78 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4.  
  5. import textwrap
  6.  
  7.  
  8. class RowMismatchException(Exception):
  9. pass
  10.  
  11.  
  12. class XTable(object):
  13. def __init__(self):
  14. super(XTable, self).__init__()
  15.  
  16. #
  17. # Type: [str]
  18. #
  19. self.set_header([])
  20.  
  21. #
  22. # Type: [[str]]
  23. #
  24. self.rows_ = []
  25.  
  26. def set_header(self, header):
  27. """param header: [str]"""
  28. self.header_ = header[:]
  29. self.column_num_ = len(self.header_)
  30. self.column_widths_ = [10] * self.column_num_
  31. self.column_formats_ = ['l'] * self.column_num_
  32.  
  33. def set_column_width(self, widths):
  34. """param widths: [int]"""
  35. self.column_widths_ = [max(w, 5) for w in widths]
  36.  
  37. def set_column_format(self, formats):
  38. """param formats: [char]"""
  39. self.column_formats_ = formats
  40.  
  41. def add_row(self, row):
  42. """param row: [str]"""
  43. if len(row) != self.column_num_:
  44. raise RowMismatchException('Table column number %d; Row size: %d' %
  45. (self.column_num_, len(row)))
  46. self.rows_.append(row[:])
  47.  
  48. def _line_seprator(self, symbol='-', corner_symbol='+'):
  49. line = [
  50. symbol * self.column_widths_[i] for i in range(self.column_num_)
  51. ]
  52. return '{0}{1}{0}'.format(corner_symbol, corner_symbol.join(line))
  53.  
  54. def _format_column_item(self, item, column_idx):
  55. width = self.column_widths_[column_idx]
  56.  
  57. fmt = self.column_formats_[column_idx]
  58. if fmt == 'l':
  59. return item.ljust(width)
  60. elif fmt == 'c':
  61. return item.center(width)
  62. elif fmt == 'r':
  63. return item.rjust(width)
  64. else:
  65. return item.ljust(width)
  66.  
  67. def _break_row(self, row):
  68. """For each row, e.g., ('abcd' 'efgh' 'I need be broken')
  69. we break the long items into multiple lines.
  70. The result may be [('abcd' 'efgh' 'I need')
  71. ('' '' 'be broken')]
  72. """
  73. all_sub_lines = []
  74. for (idx, item) in enumerate(row):
  75. sub_lines = textwrap.wrap(item,
  76. self.column_widths_[idx],
  77. break_long_words=False)
  78. all_sub_lines.append(sub_lines)
  79.  
  80. #
  81. # For shorter item, we add padding here
  82. #
  83. max_line = max(map(lambda x: len(x), all_sub_lines))
  84. for sub_lines in all_sub_lines:
  85. if len(sub_lines) < max_line:
  86. sub_lines.extend([''] * (max_line - len(sub_lines)))
  87.  
  88. return zip(*all_sub_lines)
  89.  
  90.  
  91. def _format_row(self, row):
  92. """param row: [str]"""
  93. line = [
  94. self._format_column_item(item, idx)
  95. for (idx, item) in enumerate(row)
  96. ]
  97. return '|{0}|'.format('|'.join(line))
  98.  
  99. def to_text(self):
  100. lines = [self._line_seprator('-'),
  101. self._format_row(self.header_),
  102. self._line_seprator('=')]
  103.  
  104. for row in self.rows_:
  105. sub_lines = self._break_row(row)
  106. for r in sub_lines:
  107. lines.append(self._format_row(r))
  108. lines.append(self._line_seprator('-'))
  109.  
  110. return '\n'.join(lines)
  111.  
  112. def dump_text(self):
  113. print self.to_text()
  114.  
  115. def _markdown_line_seprator(self):
  116. line = []
  117.  
  118. for i in range(self.column_num_):
  119. width = self.column_widths_[i]
  120.  
  121. fmt = self.column_formats_[i]
  122. if fmt == 'l':
  123. line.append('-' * width)
  124. elif fmt == 'c':
  125. line.append(':' + '-' * (width - 2) + ':')
  126. elif fmt == 'r':
  127. line.append('-' * (width - 1) + ':')
  128. else:
  129. line.append('-' * width)
  130.  
  131. return '|{0}|'.format('|'.join(line))
  132.  
  133. def to_markdown(self):
  134. lines = [self._format_row(self.header_),
  135. self._markdown_line_seprator()]
  136. for row in self.rows_:
  137. lines.append(self._format_row(row))
  138.  
  139. return '\n'.join(lines)
  140.  
  141. def dump_markdown(self):
  142. print self.to_markdown()
  143.  
  144.  
  145. if __name__ == "__main__":
  146. import random
  147. import string
  148.  
  149. def rand_str(l=10):
  150. """Generate a random string of fixed length"""
  151. letters = string.ascii_lowercase
  152. return ''.join(random.choice(letters) for i in range(l))
  153.  
  154. tb = XTable()
  155.  
  156. column_num = 3
  157. tb.set_header([rand_str(10) for i in range(column_num)])
  158. tb.set_column_width([random.randint(10, 15) for i in range(column_num)])
  159. tb.set_column_format(['l', 'l', 'c'])
  160.  
  161. for i in range(7):
  162. tb.add_row([rand_str(random.randint(2, 8)) for i in range(column_num)])
  163. tb.add_row(['aaaa very long string, here break into multiple lines',
  164. 'a',
  165. 'c'])
  166.  
  167. tb.dump_text()
  168. print ''
  169. tb.dump_markdown()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement