diff --git a/csvkit/utilities/csvlook.py b/csvkit/utilities/csvlook.py index c4dc04de9..4873c2cb6 100644 --- a/csvkit/utilities/csvlook.py +++ b/csvkit/utilities/csvlook.py @@ -5,17 +5,19 @@ import six from csvkit import CSVKitReader -from csvkit.cli import CSVKitUtility +from csvkit.cli import CSVKitUtility from csvkit.headers import make_default_headers class CSVLook(CSVKitUtility): description = 'Render a CSV file in the console as a fixed-width table.' def add_arguments(self): - pass + self.argparser.add_argument('-w', '--wrap', dest='wrapwidth', type=int, + help='Columns wrapwidth (allows to view long fields in multilines).', default=60) def main(self): rows = CSVKitReader(self.input_file, **self.reader_kwargs) + max_chars = self.args.wrapwidth # Make a default header row if none exists if self.args.no_header_row: @@ -42,15 +44,16 @@ def main(self): # Insert the column names at the top rows.insert(0, column_names) + # Work out column widths widths = [] - for row in rows: for i, v in enumerate(row): + lv = min(len(v), max_chars) try: - if len(v) > widths[i]: - widths[i] = len(v) + if lv > widths[i]: + widths[i] = lv except IndexError: - widths.append(len(v)) + widths.append(lv) # Dashes span each width with '+' character at intersection of # horizontal and vertical dividers. @@ -59,14 +62,18 @@ def main(self): self.output_file.write('%s\n' % divider) for i, row in enumerate(rows): - output = [] + # Each row is made of inner rows because of text wrapping + row = [d or '' for d in row] + n_inner_rows = int(max([len(d)-1 for d in row]) / max_chars) + 1 + inner_rows = [[d[j*max_chars:(j+1)*max_chars] for d in row] + for j in range(n_inner_rows)] - for j, d in enumerate(row): - if d is None: - d = '' - output.append(' %s ' % six.text_type(d).ljust(widths[j])) + for inner_row in inner_rows: + output = [] + for j, d in enumerate(inner_row): + output.append(' %s ' % six.text_type(d).ljust(widths[j])) - self.output_file.write('| %s |\n' % ('|'.join(output))) + self.output_file.write('| %s |\n' % ('|'.join(output))) if (i == 0 or i == len(rows) - 1): self.output_file.write('%s\n' % divider) @@ -74,7 +81,7 @@ def main(self): def launch_new_instance(): utility = CSVLook() utility.main() - + if __name__ == "__main__": launch_new_instance() diff --git a/examples/wrapping.csv b/examples/wrapping.csv new file mode 100644 index 000000000..ee4bd66e9 --- /dev/null +++ b/examples/wrapping.csv @@ -0,0 +1,4 @@ +a,b,c +1,0123456789,3 +1,01234567890,5 +1,012345678,7 diff --git a/tests/test_utilities/test_csvlook.py b/tests/test_utilities/test_csvlook.py index 734f23a6d..24da8cb00 100644 --- a/tests/test_utilities/test_csvlook.py +++ b/tests/test_utilities/test_csvlook.py @@ -60,3 +60,23 @@ def test_unicode(self): self.assertEqual(next(input_file), u'| 4 | 5 | ʤ |\n') self.assertEqual(next(input_file), '|----+---+----|\n') + def test_wrapping(self): + args = ['-w', '5', 'examples/wrapping.csv', ] + output_file = six.StringIO() + utility = CSVLook(args, output_file) + + utility.main() + + input_file = six.StringIO(output_file.getvalue()) + + self.assertEqual(next(input_file), '|----+-------+----|\n') + self.assertEqual(next(input_file), '| a | b | c |\n') + self.assertEqual(next(input_file), '|----+-------+----|\n') + self.assertEqual(next(input_file), '| 1 | 01234 | 3 |\n') + self.assertEqual(next(input_file), '| | 56789 | |\n') + self.assertEqual(next(input_file), '| 1 | 01234 | 5 |\n') + self.assertEqual(next(input_file), '| | 56789 | |\n') + self.assertEqual(next(input_file), '| | 0 | |\n') + self.assertEqual(next(input_file), '| 1 | 01234 | 7 |\n') + self.assertEqual(next(input_file), '| | 5678 | |\n') + self.assertEqual(next(input_file), '|----+-------+----|\n')