1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
import math
import sys
from babel.numbers import format_decimal
from agate import config, utils
from agate.data_types import Number, Text
def print_table(self, max_rows=20, max_columns=6, output=sys.stdout, max_column_width=20, locale=None,
max_precision=3):
"""
Print a text-based view of the data in this table.
The output of this method is GitHub Flavored Markdown (GFM) compatible.
:param max_rows:
The maximum number of rows to display before truncating the data. This
defaults to :code:`20` to prevent accidental printing of the entire
table. Pass :code:`None` to disable the limit.
:param max_columns:
The maximum number of columns to display before truncating the data.
This defaults to :code:`6` to prevent wrapping in most cases. Pass
:code:`None` to disable the limit.
:param output:
A file-like object to print to.
:param max_column_width:
Truncate all columns to at most this width. The remainder will be
replaced with ellipsis.
:param locale:
Provide a locale you would like to be used to format the output.
By default it will use the system's setting.
:max_precision:
Puts a limit on the maximum precision displayed for number types.
Numbers with lesser precision won't be affected.
This defaults to :code:`3`. Pass :code:`None` to disable limit.
"""
if max_rows is None:
max_rows = len(self._rows)
if max_columns is None:
max_columns = len(self._columns)
if max_precision is None:
max_precision = float('inf')
ellipsis = config.get_option('ellipsis_chars')
truncation = config.get_option('text_truncation_chars')
len_truncation = len(truncation)
h_line = config.get_option('horizontal_line_char')
v_line = config.get_option('vertical_line_char')
locale = locale or config.get_option('default_locale')
rows_truncated = max_rows < len(self._rows)
columns_truncated = max_columns < len(self._column_names)
column_names = []
for column_name in self.column_names[:max_columns]:
if max_column_width is not None and len(column_name) > max_column_width:
column_names.append('%s%s' % (column_name[:max_column_width - len_truncation], truncation))
else:
column_names.append(column_name)
if columns_truncated:
column_names.append(ellipsis)
widths = [len(n) for n in column_names]
number_formatters = []
formatted_data = []
# Determine correct number of decimal places for each Number column
for i, c in enumerate(self._columns):
if i >= max_columns:
break
if isinstance(c.data_type, Number):
max_places = utils.max_precision(c[:max_rows])
add_ellipsis = False
if max_places > max_precision:
add_ellipsis = True
max_places = max_precision
number_formatters.append(utils.make_number_formatter(max_places, add_ellipsis))
else:
number_formatters.append(None)
# Format data and display column widths
for i, row in enumerate(self._rows):
if i >= max_rows:
break
formatted_row = []
for j, v in enumerate(row):
if j >= max_columns:
v = ellipsis
elif v is None:
v = ''
elif number_formatters[j] is not None and not math.isinf(v):
v = format_decimal(
v,
format=number_formatters[j],
locale=locale
)
else:
v = str(v)
if max_column_width is not None and len(v) > max_column_width:
v = '%s%s' % (v[:max_column_width - len_truncation], truncation)
if len(v) > widths[j]:
widths[j] = len(v)
formatted_row.append(v)
if j >= max_columns:
break
formatted_data.append(formatted_row)
def write(line):
output.write(line + '\n')
def write_row(formatted_row):
"""
Helper function that formats individual rows.
"""
row_output = []
for j, d in enumerate(formatted_row):
# Text is left-justified, all other values are right-justified
if isinstance(self._column_types[j], Text):
output = ' %s ' % d.ljust(widths[j])
else:
output = ' %s ' % d.rjust(widths[j])
row_output.append(output)
text = v_line.join(row_output)
write(f'{v_line}{text}{v_line}')
divider = '{v_line} {columns} {v_line}'.format(
v_line=v_line,
columns=' | '.join(h_line * w for w in widths)
)
# Headers
write_row(column_names)
write(divider)
# Rows
for formatted_row in formatted_data:
write_row(formatted_row)
# Row indicating data was truncated
if rows_truncated:
write_row([ellipsis for n in column_names])
|