Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge changes from Pull Request #79 (preserve_whitespace as an argument to tabulate()) #342

Merged
merged 5 commits into from
Sep 26, 2024
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
11 changes: 3 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ When data is a list of dictionaries, a dictionary can be passed as `headers`
to replace the keys with other column labels:

```pycon
>>> print(tabulate([{1: "Alice", 2: 24}, {1: "Bob", 2: 19}],
>>> print(tabulate([{1: "Alice", 2: 24}, {1: "Bob", 2: 19}],
... headers={1: "Name", 2: "Age"}))
Name Age
------ -----
Expand Down Expand Up @@ -739,13 +739,8 @@ column, in which case every column may have different number formatting:
### Text formatting

By default, `tabulate` removes leading and trailing whitespace from text
columns. To disable whitespace removal, set the global module-level flag
`PRESERVE_WHITESPACE`:

```python
import tabulate
tabulate.PRESERVE_WHITESPACE = True
```
columns. To disable whitespace removal, pass `preserve_whitespace=True`.
Older versions of the library used a global module-level flag PRESERVE_WHITESPACE.

### Wide (fullwidth CJK) symbols

Expand Down
53 changes: 38 additions & 15 deletions tabulate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ def _is_file(f):
# minimum extra space in headers
MIN_PADDING = 2

# Whether or not to preserve leading/trailing whitespace in data.
PRESERVE_WHITESPACE = False

_DEFAULT_FLOATFMT = "g"
_DEFAULT_INTFMT = ""
_DEFAULT_MISSINGVAL = ""
Expand Down Expand Up @@ -163,7 +160,6 @@ def _grid_line_with_colons(colwidths, colaligns):
return "+" + "+".join(segments) + "+"



def _mediawiki_row_with_attrs(separator, cell_values, colwidths, colaligns):
alignment = {
"left": "",
Expand Down Expand Up @@ -1100,13 +1096,13 @@ def _choose_width_fn(has_invisible, enable_widechars, is_multiline):
return width_fn


def _align_column_choose_padfn(strings, alignment, has_invisible):
def _align_column_choose_padfn(strings, alignment, has_invisible, preserve_whitespace):
if alignment == "right":
if not PRESERVE_WHITESPACE:
if not preserve_whitespace:
strings = [s.strip() for s in strings]
padfn = _padleft
elif alignment == "center":
if not PRESERVE_WHITESPACE:
if not preserve_whitespace:
strings = [s.strip() for s in strings]
padfn = _padboth
elif alignment == "decimal":
Expand All @@ -1120,7 +1116,7 @@ def _align_column_choose_padfn(strings, alignment, has_invisible):
elif not alignment:
padfn = _padnone
else:
if not PRESERVE_WHITESPACE:
if not preserve_whitespace:
strings = [s.strip() for s in strings]
padfn = _padright
return strings, padfn
Expand Down Expand Up @@ -1163,9 +1159,12 @@ def _align_column(
has_invisible=True,
enable_widechars=False,
is_multiline=False,
preserve_whitespace=False,
):
"""[string] -> [padded_string]"""
strings, padfn = _align_column_choose_padfn(strings, alignment, has_invisible)
strings, padfn = _align_column_choose_padfn(
strings, alignment, has_invisible, preserve_whitespace
)
width_fn = _align_column_choose_width_fn(
has_invisible, enable_widechars, is_multiline
)
Expand Down Expand Up @@ -1271,15 +1270,21 @@ def _format(val, valtype, floatfmt, intfmt, missingval="", has_invisible=True):
return f"{val}"
elif valtype is int:
if isinstance(val, str):
val_striped = val.encode('unicode_escape').decode('utf-8')
colored = re.search(r'(\\[xX]+[0-9a-fA-F]+\[\d+[mM]+)([0-9.]+)(\\.*)$', val_striped)
val_striped = val.encode("unicode_escape").decode("utf-8")
colored = re.search(
r"(\\[xX]+[0-9a-fA-F]+\[\d+[mM]+)([0-9.]+)(\\.*)$", val_striped
)
if colored:
total_groups = len(colored.groups())
if total_groups == 3:
digits = colored.group(2)
if digits.isdigit():
val_new = colored.group(1) + format(int(digits), intfmt) + colored.group(3)
val = val_new.encode('utf-8').decode('unicode_escape')
val_new = (
colored.group(1)
+ format(int(digits), intfmt)
+ colored.group(3)
)
val = val_new.encode("utf-8").decode("unicode_escape")
intfmt = ""
return format(val, intfmt)
elif valtype is bytes:
Expand Down Expand Up @@ -1645,6 +1650,7 @@ def tabulate(
disable_numparse=False,
colglobalalign=None,
colalign=None,
preserve_whitespace=False,
maxcolwidths=None,
headersglobalalign=None,
headersalign=None,
Expand Down Expand Up @@ -2323,7 +2329,15 @@ def tabulate(
if tablefmt == "colon_grid":
aligns_copy = ["left"] * len(cols)
cols = [
_align_column(c, a, minw, has_invisible, enable_widechars, is_multiline)
_align_column(
c,
a,
minw,
has_invisible,
enable_widechars,
is_multiline,
preserve_whitespace,
)
for c, a, minw in zip(cols, aligns_copy, minwidths)
]

Expand Down Expand Up @@ -2820,7 +2834,16 @@ def _main():
opts, args = getopt.getopt(
sys.argv[1:],
"h1o:s:F:I:f:",
["help", "header", "output=", "sep=", "float=", "int=", "colalign=", "format="],
[
"help",
"header",
"output=",
"sep=",
"float=",
"int=",
"colalign=",
"format=",
],
)
except getopt.GetoptError as e:
print(e)
Expand Down
2 changes: 2 additions & 0 deletions test/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
from pytest import skip, raises # noqa
import warnings


def assert_equal(expected, result):
print("Expected:\n%s\n" % expected)
print("Got:\n%s\n" % result)
assert expected == result


def assert_in(result, expected_set):
nums = range(1, len(expected_set) + 1)
for i, expected in zip(nums, expected_set):
Expand Down
1 change: 1 addition & 0 deletions test/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def test_tabulate_signature():
("disable_numparse", False),
("colglobalalign", None),
("colalign", None),
("preserve_whitespace", False),
("maxcolwidths", None),
("headersglobalalign", None),
("headersalign", None),
Expand Down
22 changes: 14 additions & 8 deletions test/test_output.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Test output of the various forms of tabular data."""
from pytest import mark

import tabulate as tabulate_module
from common import assert_equal, raises, skip, check_warnings
from tabulate import tabulate, simple_separated_format, SEPARATING_LINE

Expand Down Expand Up @@ -1459,7 +1458,12 @@ def test_colon_grid():
"+------+------+",
]
)
result = tabulate([[3, 4]], headers=("H1", "H2"), tablefmt="colon_grid", colalign=["right", "center"])
result = tabulate(
[[3, 4]],
headers=("H1", "H2"),
tablefmt="colon_grid",
colalign=["right", "center"],
)
assert_equal(expected, result)


Expand All @@ -1482,7 +1486,9 @@ def test_colon_grid_wide_characters():
"+-----------+---------+",
]
)
result = tabulate(_test_table, headers, tablefmt="colon_grid", colalign=["left", "right"])
result = tabulate(
_test_table, headers, tablefmt="colon_grid", colalign=["left", "right"]
)
assert_equal(expected, result)


Expand Down Expand Up @@ -2773,7 +2779,9 @@ def test_intfmt_with_string_as_integer():
@mark.skip(reason="It detects all values as floats but there are strings and integers.")
def test_intfmt_with_string_with_floats():
"Output: integer format"
result = tabulate([[82000.38], ["1500.47"], ["2463"], [92165]], intfmt=",", tablefmt="plain")
result = tabulate(
[[82000.38], ["1500.47"], ["2463"], [92165]], intfmt=",", tablefmt="plain"
)
expected = "82000.4\n 1500.47\n 2463\n92,165"
assert_equal(expected, result)

Expand Down Expand Up @@ -3208,18 +3216,16 @@ def test_disable_numparse_list():

def test_preserve_whitespace():
"Output: Default table output, but with preserved leading whitespace."
tabulate_module.PRESERVE_WHITESPACE = True
table_headers = ["h1", "h2", "h3"]
test_table = [[" foo", " bar ", "foo"]]
expected = "\n".join(
["h1 h2 h3", "----- ------- ----", " foo bar foo"]
)
result = tabulate(test_table, table_headers)
result = tabulate(test_table, table_headers, preserve_whitespace=True)
assert_equal(expected, result)

tabulate_module.PRESERVE_WHITESPACE = False
table_headers = ["h1", "h2", "h3"]
test_table = [[" foo", " bar ", "foo"]]
expected = "\n".join(["h1 h2 h3", "---- ---- ----", "foo bar foo"])
result = tabulate(test_table, table_headers)
result = tabulate(test_table, table_headers, preserve_whitespace=False)
assert_equal(expected, result)
1 change: 1 addition & 0 deletions test/test_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ def test_numpy_int64_as_integer():
except ImportError:
raise skip("")


def test_empty_table_with_colalign():
"Regression: empty table with colalign kwarg"
table = tabulate([], ["a", "b", "c"], colalign=("center", "left", "left", "center"))
Expand Down
Loading