Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

- Added noheader CSV and TSV output formats.

## Version 2.4.0

(released on 2025-03-10)
Expand Down
11 changes: 6 additions & 5 deletions cli_helpers/tabular_output/delimited_output_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from cli_helpers.utils import filter_dict_by_key
from .preprocessors import bytes_to_string, override_missing_value

supported_formats = ("csv", "csv-tab")
supported_formats = ("csv", "csv-tab", "csv-noheader", "csv-tab-noheader")
preprocessors = (override_missing_value, bytes_to_string)


Expand All @@ -35,9 +35,9 @@ def adapter(data, headers, table_format="csv", **kwargs):
"skipinitialspace",
"strict",
)
if table_format == "csv":
if table_format in ("csv", "csv-noheader"):
delimiter = ","
elif table_format == "csv-tab":
elif table_format in ("csv-tab", "csv-tab-noheader"):
delimiter = "\t"
else:
raise ValueError("Invalid table_format specified.")
Expand All @@ -47,8 +47,9 @@ def adapter(data, headers, table_format="csv", **kwargs):

l = linewriter()
writer = csv.writer(l, **ckwargs)
writer.writerow(headers)
yield l.line
if "noheader" not in table_format:
writer.writerow(headers)
yield l.line

for row in data:
l.reset()
Expand Down
14 changes: 10 additions & 4 deletions cli_helpers/tabular_output/tsv_output_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@
from itertools import chain
from cli_helpers.utils import replace

supported_formats = ("tsv",)
supported_formats = ("tsv", "tsv_noheader")
preprocessors = (override_missing_value, bytes_to_string, convert_to_string)


def adapter(data, headers, **kwargs):
def adapter(data, headers, table_format="tsv", **kwargs):
"""Wrap the formatting inside a function for TabularOutputFormatter."""
for row in chain((headers,), data):
yield "\t".join((replace(r, (("\n", r"\n"), ("\t", r"\t"))) for r in row))
if table_format == "tsv":
for row in chain((headers,), data):
yield "\t".join((replace(r, (("\n", r"\n"), ("\t", r"\t"))) for r in row))
elif table_format == "tsv_noheader":
for row in data:
yield "\t".join((replace(r, (("\n", r"\n"), ("\t", r"\t"))) for r in row))
else:
raise ValueError(f"Invalid table_format specified: {table_format}.")
30 changes: 30 additions & 0 deletions tests/tabular_output/test_delimited_output_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,36 @@ def test_csv_wrapper():
list(output)


def test_csv_noheader_wrapper():
"""Test the delimited output adapter without headers."""
# Test comma-delimited output.
data = [["abc", "1"], ["d", "456"]]
headers = ["letters", "number"]
output = delimited_output_adapter.adapter(
iter(data),
headers,
table_format="csv-noheader",
dialect="unix",
)
assert "\n".join(output) == dedent(
'''\
"abc","1"\n\
"d","456"'''
)

# Test tab-delimited output.
data = [["abc", "1"], ["d", "456"]]
headers = ["letters", "number"]
output = delimited_output_adapter.adapter(
iter(data), headers, table_format="csv-tab-noheader", dialect="unix"
)
assert "\n".join(output) == dedent(
'''\
"abc"\t"1"\n\
"d"\t"456"'''
)


def test_unicode_with_csv():
"""Test that the csv wrapper can handle non-ascii characters."""
data = [["观音", "1"], ["Ποσειδῶν", "456"]]
Expand Down
13 changes: 13 additions & 0 deletions tests/tabular_output/test_tsv_output_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ def test_tsv_wrapper():
)


def test_tsv_headerless_wrapper():
"""Test the tsv headerless_output adapter."""
# Test tab-delimited output.
data = [["ab\r\nc", "1"], ["d", "456"]]
headers = ["letters", "number"]
output = tsv_output_adapter.adapter(iter(data), headers, table_format="tsv_noheader")
assert "\n".join(output) == dedent(
"""\
ab\r\\nc\t1\n\
d\t456"""
)


def test_unicode_with_tsv():
"""Test that the tsv wrapper can handle non-ascii characters."""
data = [["观音", "1"], ["Ποσειδῶν", "456"]]
Expand Down
Loading