Skip to content

Commit e647025

Browse files
committed
Respect padding in pipe/github separator rows
Follow up on #410; Refs #260 and #261.
1 parent 268615a commit e647025

File tree

4 files changed

+51
-39
lines changed

4 files changed

+51
-39
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ corresponds to the `pipe` format with the same alignment colons:
238238
```pycon
239239
>>> print(tabulate(table, headers, tablefmt="github"))
240240
| item | qty |
241-
|:-------|------:|
241+
| :----- | ----: |
242242
| spam | 42 |
243243
| eggs | 451 |
244244
| bacon | 0 |
@@ -487,7 +487,7 @@ indicate column alignment:
487487
```pycon
488488
>>> print(tabulate(table, headers, tablefmt="pipe"))
489489
| item | qty |
490-
|:-------|------:|
490+
| :----- | ----: |
491491
| spam | 42 |
492492
| eggs | 451 |
493493
| bacon | 0 |
@@ -931,7 +931,7 @@ spam
931931
>>> print(tabulate(table, headers, tablefmt="pipe"))
932932
| item | qty |
933933
| name | |
934-
|:-------|------:|
934+
| :----- | ----: |
935935
| eggs | 451 |
936936
| more | 42 |
937937
| spam | |

tabulate/__init__.py

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -131,26 +131,37 @@ def _is_separating_line(row):
131131
)
132132

133133

134-
def _pipe_segment_with_colons(align, colwidth):
134+
def _pipe_segment_with_colons(align, colwidth, padding=0):
135135
"""Return a segment of a horizontal line with optional colons which
136-
indicate column's alignment (as in `pipe` output format)."""
136+
indicate column's alignment (as in `pipe` output format).
137+
138+
When ``padding`` is non-zero, the segment respects the format's padding by
139+
placing spaces at the padding positions instead of filling the entire width
140+
with dashes. This makes separator rows consistent with data rows, which
141+
already honour padding via ``_pad_row``.
142+
"""
137143
w = colwidth
144+
pad = " " * padding
145+
# Width available for dashes and alignment colons.
146+
dw = w - 2 * padding
138147
if align in ["right", "decimal"]:
139-
return ("-" * (w - 1)) + ":"
148+
return pad + ("-" * (dw - 1)) + ":" + pad
140149
elif align == "center":
141-
return ":" + ("-" * (w - 2)) + ":"
150+
return pad + ":" + ("-" * (dw - 2)) + ":" + pad
142151
elif align == "left":
143-
return ":" + ("-" * (w - 1))
152+
return pad + ":" + ("-" * (dw - 1)) + pad
144153
else:
145-
return "-" * w
154+
return pad + ("-" * dw) + pad
146155

147156

148-
def _pipe_line_with_colons(colwidths, colaligns):
157+
def _pipe_line_with_colons(colwidths, colaligns, padding=0):
149158
"""Return a horizontal line with optional colons to indicate column's
150159
alignment (as in `pipe` output format)."""
151160
if not colaligns: # e.g. printing an empty data frame (github issue #15)
152161
colaligns = [""] * len(colwidths)
153-
segments = "|".join(_pipe_segment_with_colons(a, w) for a, w in zip(colaligns, colwidths))
162+
segments = "|".join(
163+
_pipe_segment_with_colons(a, w, padding) for a, w in zip(colaligns, colwidths)
164+
)
154165
return f"|{segments}|"
155166

156167

@@ -168,7 +179,7 @@ def _grid_segment_with_colons(colwidth, align):
168179
return "=" * width
169180

170181

171-
def _grid_line_with_colons(colwidths, colaligns):
182+
def _grid_line_with_colons(colwidths, colaligns, **kwargs):
172183
"""Return a horizontal line with optional colons to indicate column's alignment
173184
in a grid table."""
174185
if not colaligns:
@@ -200,7 +211,7 @@ def _textile_row_with_attrs(cell_values, colwidths, colaligns):
200211
return f"|{values}|"
201212

202213

203-
def _html_begin_table_without_header(colwidths_ignore, colaligns_ignore):
214+
def _html_begin_table_without_header(colwidths_ignore, colaligns_ignore, **kwargs):
204215
# this table header will be suppressed if there is a header row
205216
return "<table>\n<tbody>"
206217

@@ -242,7 +253,7 @@ def _moin_row_with_attrs(celltag, cell_values, colwidths, colaligns, header=""):
242253
return "".join(values_with_attrs) + "||"
243254

244255

245-
def _latex_line_begin_tabular(colwidths, colaligns, booktabs=False, longtable=False):
256+
def _latex_line_begin_tabular(colwidths, colaligns, booktabs=False, longtable=False, **kwargs):
246257
alignment = {"left": "l", "right": "r", "center": "c", "decimal": "r"}
247258
tabular_columns_fmt = "".join([alignment.get(a, "l") for a in colaligns])
248259
return "\n".join(
@@ -255,7 +266,7 @@ def _latex_line_begin_tabular(colwidths, colaligns, booktabs=False, longtable=Fa
255266
)
256267

257268

258-
def _asciidoc_row(is_header, *args):
269+
def _asciidoc_row(is_header, *args, **kwargs):
259270
"""handle header and data rows for asciidoc format"""
260271

261272
def make_header_line(is_header, colwidths, colaligns):
@@ -2063,7 +2074,7 @@ def tabulate(
20632074
>>> print(tabulate([["spam", 41.9999], ["eggs", "451.0"]],
20642075
... ["strings", "numbers"], "pipe"))
20652076
| strings | numbers |
2066-
|:----------|----------:|
2077+
| :-------- | --------: |
20672078
| spam | 41.9999 |
20682079
| eggs | 451 |
20692080
@@ -2077,7 +2088,7 @@ def tabulate(
20772088
eggs | 451
20782089
20792090
>>> print(tabulate([["spam", 41.9999], ["eggs", "451.0"]], tablefmt="pipe"))
2080-
|:-----|---------:|
2091+
| :--- | -------: |
20812092
| spam | 41.9999 |
20822093
| eggs | 451 |
20832094
@@ -2578,21 +2589,21 @@ def _append_multiline_row(
25782589
return lines
25792590

25802591

2581-
def _build_line(colwidths, colaligns, linefmt):
2592+
def _build_line(colwidths, colaligns, linefmt, padding=0):
25822593
"Return a string which represents a horizontal line."
25832594
if not linefmt:
25842595
return None
25852596
if callable(linefmt):
2586-
return linefmt(colwidths, colaligns)
2597+
return linefmt(colwidths, colaligns, padding=padding)
25872598
else:
25882599
begin, fill, sep, end = linefmt
25892600
cells = [fill * w for w in colwidths]
25902601
rowfmt = DataRow(begin, sep, end)
25912602
return _build_simple_row(cells, rowfmt)
25922603

25932604

2594-
def _append_line(lines, colwidths, colaligns, linefmt):
2595-
lines.append(_build_line(colwidths, colaligns, linefmt))
2605+
def _append_line(lines, colwidths, colaligns, linefmt, padding=0):
2606+
lines.append(_build_line(colwidths, colaligns, linefmt, padding=padding))
25962607
return lines
25972608

25982609

@@ -2629,12 +2640,12 @@ def _format_table(
26292640
padded_headers = pad_row(headers, pad)
26302641

26312642
if fmt.lineabove and "lineabove" not in hidden:
2632-
_append_line(lines, padded_widths, colaligns, fmt.lineabove)
2643+
_append_line(lines, padded_widths, colaligns, fmt.lineabove, padding=pad)
26332644

26342645
if padded_headers:
26352646
append_row(lines, padded_headers, padded_widths, headersaligns, headerrow)
26362647
if fmt.linebelowheader and "linebelowheader" not in hidden:
2637-
_append_line(lines, padded_widths, colaligns, fmt.linebelowheader)
2648+
_append_line(lines, padded_widths, colaligns, fmt.linebelowheader, padding=pad)
26382649

26392650
if rows and fmt.linebetweenrows and "linebetweenrows" not in hidden:
26402651
# initial rows with a line below
@@ -2648,7 +2659,7 @@ def _format_table(
26482659
fmt.datarow,
26492660
rowalign=ralign,
26502661
)
2651-
_append_line(lines, padded_widths, colaligns, fmt.linebetweenrows)
2662+
_append_line(lines, padded_widths, colaligns, fmt.linebetweenrows, padding=pad)
26522663
# the last row without a line below
26532664
append_row(
26542665
lines,
@@ -2670,12 +2681,12 @@ def _format_table(
26702681
# test to see if either the 1st column or the 2nd column (account for showindex) has
26712682
# the SEPARATING_LINE flag
26722683
if _is_separating_line(row):
2673-
_append_line(lines, padded_widths, colaligns, separating_line)
2684+
_append_line(lines, padded_widths, colaligns, separating_line, padding=pad)
26742685
else:
26752686
append_row(lines, pad_row(row, pad), padded_widths, colaligns, fmt.datarow)
26762687

26772688
if fmt.linebelow and "linebelow" not in hidden:
2678-
_append_line(lines, padded_widths, colaligns, fmt.linebelow)
2689+
_append_line(lines, padded_widths, colaligns, fmt.linebelow, padding=pad)
26792690

26802691
if headers or rows:
26812692
output = "\n".join(lines)

test/test_output.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -369,9 +369,9 @@ def test_simple_headerless_with_sep_line_with_padding_in_tablefmt():
369369
"Output: simple without headers with sep line with padding in tablefmt"
370370
expected = "\n".join(
371371
[
372-
"|:-----|---------:|",
372+
"| :--- | -------: |",
373373
"| spam | 41.9999 |",
374-
"|:-----|---------:|",
374+
"| :--- | -------: |",
375375
"| eggs | 451 |",
376376
]
377377
)
@@ -489,12 +489,13 @@ def test_github():
489489
expected = "\n".join(
490490
[
491491
"| strings | numbers |",
492-
"|:----------|----------:|",
492+
"| :-------- | --------: |",
493493
"| spam | 41.9999 |",
494494
"| eggs | 451 |",
495495
]
496496
)
497497
result = tabulate(_test_table, _test_table_headers, tablefmt="github")
498+
498499
assert_equal(expected, result)
499500

500501

@@ -506,7 +507,7 @@ def test_github_multiline():
506507
[
507508
"| more | more spam |",
508509
"| spam eggs | & eggs |",
509-
"|------------:|:------------|",
510+
"| ----------: | :---------- |",
510511
"| 2 | foo |",
511512
"| | bar |",
512513
]
@@ -520,7 +521,7 @@ def test_github_with_colalign():
520521
expected = "\n".join(
521522
[
522523
"| Name | Age |",
523-
"|:-------|------:|",
524+
"| :----- | ----: |",
524525
"| Alice | 24 |",
525526
"| Bob | 19 |",
526527
]
@@ -539,7 +540,7 @@ def test_github_no_alignment():
539540
expected = "\n".join(
540541
[
541542
"| strings | numbers |",
542-
"|-----------|-----------|",
543+
"| --------- | --------- |",
543544
"| spam | 41.9999 |",
544545
"| eggs | 451 |",
545546
]
@@ -1995,7 +1996,7 @@ def test_pipe():
19951996
expected = "\n".join(
19961997
[
19971998
"| strings | numbers |",
1998-
"|:----------|----------:|",
1999+
"| :-------- | --------: |",
19992000
"| spam | 41.9999 |",
20002001
"| eggs | 451 |",
20012002
]
@@ -2006,7 +2007,7 @@ def test_pipe():
20062007

20072008
def test_pipe_headerless():
20082009
"Output: pipe without headers"
2009-
expected = "\n".join(["|:-----|---------:|", "| spam | 41.9999 |", "| eggs | 451 |"])
2010+
expected = "\n".join(["| :--- | -------: |", "| spam | 41.9999 |", "| eggs | 451 |"])
20102011
result = tabulate(_test_table, tablefmt="pipe")
20112012
assert_equal(expected, result)
20122013

test/test_regression.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_ansi_color_in_table_cells():
1313
expected = "\n".join(
1414
[
1515
"| test | test | test |",
16-
"|:-------|:-------|:-------|",
16+
"| :----- | :----- | :----- |",
1717
"| test | \x1b[31mtest\x1b[0m | \x1b[32mtest\x1b[0m |",
1818
]
1919
)
@@ -195,7 +195,7 @@ def test_88_256_ANSI_color_codes():
195195
expected = "\n".join(
196196
[
197197
"| background | foreground |",
198-
"|:-------------|:-------------|",
198+
"| :----------- | :----------- |",
199199
"| \x1b[48;5;196mred\x1b[49m | \x1b[38;5;196mred\x1b[39m |",
200200
]
201201
)
@@ -424,7 +424,7 @@ def test_empty_pipe_table_with_columns():
424424
"Regression: allow empty pipe tables with columns, like empty dataframes (github issue #15)"
425425
table = []
426426
headers = ["Col1", "Col2"]
427-
expected = "\n".join(["| Col1 | Col2 |", "|--------|--------|"])
427+
expected = "\n".join(["| Col1 | Col2 |", "| ------ | ------ |"])
428428
result = tabulate(table, headers, tablefmt="pipe")
429429
assert_equal(expected, result)
430430

@@ -542,7 +542,7 @@ def test_numpy_int64_as_integer():
542542
expected = "\n".join(
543543
[
544544
"| int | float |",
545-
"|------:|--------:|",
545+
"| ----: | ------: |",
546546
"| 1 | 3.14 |",
547547
]
548548
)
@@ -596,5 +596,5 @@ def test_asciidoc_without_trailing_whitespace():
596596
def test_github_escape_pipe_character():
597597
"Regression: github format must escape pipe character with a backslash (issue #241)"
598598
result = tabulate([["foo|bar"]], headers=("spam|eggs",), tablefmt="github")
599-
expected = "| spam\\|eggs |\n|:------------|\n| foo\\|bar |"
599+
expected = "| spam\\|eggs |\n| :---------- |\n| foo\\|bar |"
600600
assert_equal(expected, result)

0 commit comments

Comments
 (0)