Skip to content

Commit

Permalink
Merge pull request #12 from lzakharov/no-header-support
Browse files Browse the repository at this point in the history
Support --no-header-row flag
  • Loading branch information
lzakharov authored Sep 8, 2023
2 parents 9eb4e07 + e0379ac commit 69f9f41
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 14 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 Lev Zakharov
Copyright (c) 2023 Lev Zakharov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,26 +87,24 @@ You can also specify delimiter, quotation characters and alignment (see [Help](h
To view help run `csv2md -h`:

```commandline
usage: csv2md [-h] [-d DELIMITER] [-q QUOTECHAR]
[-c [CENTER_ALIGNED_COLUMNS [CENTER_ALIGNED_COLUMNS ...]]]
[-r [RIGHT_ALIGNED_COLUMNS [RIGHT_ALIGNED_COLUMNS ...]]]
[CSV_FILE [CSV_FILE ...]]
usage: csv2md [-h] [-d DELIMITER] [-q QUOTECHAR] [-c [CENTER_ALIGNED_COLUMNS ...]] [-r [RIGHT_ALIGNED_COLUMNS ...]] [-H] [CSV_FILE ...]
Parse CSV files into Markdown tables.
positional arguments:
CSV_FILE One or more CSV files to parse
optional arguments:
options:
-h, --help show this help message and exit
-d DELIMITER, --delimiter DELIMITER
delimiter character. Default is ','
-q QUOTECHAR, --quotechar QUOTECHAR
quotation character. Default is '"'
-c [CENTER_ALIGNED_COLUMNS [CENTER_ALIGNED_COLUMNS ...]], --center-aligned-columns [CENTER_ALIGNED_COLUMNS [CENTER_ALIGNED_COLUMNS ...]]
-c [CENTER_ALIGNED_COLUMNS ...], --center-aligned-columns [CENTER_ALIGNED_COLUMNS ...]
column numbers with center alignment (from zero)
-r [RIGHT_ALIGNED_COLUMNS [RIGHT_ALIGNED_COLUMNS ...]], --right-aligned-columns [RIGHT_ALIGNED_COLUMNS [RIGHT_ALIGNED_COLUMNS ...]]
-r [RIGHT_ALIGNED_COLUMNS ...], --right-aligned-columns [RIGHT_ALIGNED_COLUMNS ...]
column numbers with right alignment (from zero)
-H, --no-header-row specify that the input CSV file has no header row. Will create default headers in Excel format (a,b,c,...)
```

## Running Tests
Expand All @@ -126,4 +124,4 @@ Feel free to also ask questions on the tracker.

## License

Copyright (c) 2018 Lev Zakharov. Licensed under [the MIT License](https://raw.githubusercontent.com/lzakharov/csv2md/master/LICENSE).
Copyright (c) 2023 Lev Zakharov. Licensed under [the MIT License](https://raw.githubusercontent.com/lzakharov/csv2md/master/LICENSE).
6 changes: 4 additions & 2 deletions csv2md/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,18 @@ def main():
type=int, default=[], help='column numbers with center alignment (from zero)')
parser.add_argument('-r', '--right-aligned-columns', metavar='RIGHT_ALIGNED_COLUMNS', nargs='*',
type=int, default=[], help='column numbers with right alignment (from zero)')
parser.add_argument('-H', '--no-header-row', dest='no_header_row', action='store_true',
help='specify that the input CSV file has no header row. Will create default headers in Excel format (a,b,c,...)')
args = parser.parse_args()

if not args.files:
table = Table.parse_csv(sys.stdin, args.delimiter, args.quotechar)
print(table.markdown(args.center_aligned_columns, args.right_aligned_columns))
print(table.markdown(args.center_aligned_columns, args.right_aligned_columns, args.no_header_row))
return

for file in args.files:
table = Table.parse_csv(file, args.delimiter, args.quotechar)
print(table.markdown(args.center_aligned_columns, args.right_aligned_columns))
print(table.markdown(args.center_aligned_columns, args.right_aligned_columns, args.no_header_row))


if __name__ == '__main__':
Expand Down
20 changes: 18 additions & 2 deletions csv2md/table.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import csv

from .utils import column_letter


class Table:
def __init__(self, cells):
self.cells = cells
self.widths = list(map(max, zip(*[list(map(len, row)) for row in cells])))

def markdown(self, center_aligned_columns=None, right_aligned_columns=None):
def markdown(self, center_aligned_columns=None, right_aligned_columns=None, no_header_row=False):
if len(self.cells) == 0:
return ''

def ljust_row(row):
return [cell.ljust(width) for cell, width in zip(row, self.widths)]

def format_row(row):
return '| ' + ' | '.join(row) + ' |'

rows = [format_row([cell.ljust(width) for cell, width in zip(row, self.widths)]) for row in self.cells]
rows = [format_row(ljust_row(row)) for row in self.cells]
separators = ['-' * width for width in self.widths]

if right_aligned_columns is not None:
Expand All @@ -20,10 +28,18 @@ def format_row(row):
for column in center_aligned_columns:
separators[column] = ':' + ('-' * (self.widths[column] - 2)) + ':'

if no_header_row:
width = len(self.cells[0])
rows.insert(0, format_row(ljust_row(self.make_default_headers(width))))

rows.insert(1, format_row(separators))

return '\n'.join(rows)

@staticmethod
def parse_csv(file, delimiter=',', quotechar='"'):
return Table(list(csv.reader(file, delimiter=delimiter, quotechar=quotechar)))

@staticmethod
def make_default_headers(n):
return tuple(map(column_letter, range(n)))
26 changes: 26 additions & 0 deletions csv2md/test_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,23 @@
'| 1996 | Jeep | Grand Cherokee | MUST SELL! air, moon roof, loaded | 4799.00 |'
)

normal_md_with_default_columns = (
'| a | b | c | d | e |\n'
'| ---- | ----- | -------------------------- | --------------------------------- | ------- |\n'
'| year | make | model | description | price |\n'
'| 1997 | Ford | E350 | ac, abs, moon | 3000.00 |\n'
'| 1999 | Chevy | Venture «Extended Edition» | | 4900.00 |\n'
'| 1996 | Jeep | Grand Cherokee | MUST SELL! air, moon roof, loaded | 4799.00 |'
)


class TestTable(TestCase):
def test_markdown_empty_table(self):
expected = ''
table = Table([])
actual = table.markdown()
self.assertEqual(expected, actual)

def test_markdown(self):
expected = normal_md
table = Table(normal_cells)
Expand All @@ -56,6 +71,12 @@ def test_markdown_with_alignment(self):
actual = table.markdown([1, 2], [4])
self.assertEqual(expected, actual)

def test_markdown_with_default_columns(self):
expected = normal_md_with_default_columns
table = Table(normal_cells)
actual = table.markdown(no_header_row=True)
self.assertEqual(expected, actual)

def test_parse_csv(self):
expected_cells = normal_cells
expected_widths = normal_widths
Expand All @@ -70,3 +91,8 @@ def test_parse_csv_with_custom_delimiter(self):
self.assertEqual(expected_cells, actual.cells)
self.assertEqual(expected_widths, actual.widths)

def test_make_default_headers(self):
expected = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', 'aa', 'bb', 'cc', 'dd', 'ee', 'ff', 'gg')
self.assertEqual(Table.make_default_headers(33), expected)
10 changes: 10 additions & 0 deletions csv2md/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from unittest import TestCase

from .utils import column_letter


class TestUtils(TestCase):
def test_column_letter(self):
self.assertEqual(column_letter(0), 'a')
self.assertEqual(column_letter(4), 'e')
self.assertEqual(column_letter(30), 'ee')
7 changes: 7 additions & 0 deletions csv2md/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import string

def column_letter(index):
"""Returns the column letter in Excel format."""
letters = string.ascii_lowercase
count = len(letters)
return letters[index % count] * ((index // count) + 1)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

setup(
name='csv2md',
version='1.1.2',
version='1.2.0',
description='Command line tool for converting CSV files into Markdown tables.',
long_description=readme,
author='Lev Zakharov',
Expand Down

0 comments on commit 69f9f41

Please sign in to comment.