diff --git a/README.md b/README.md index 223a85a..5c69cd9 100644 --- a/README.md +++ b/README.md @@ -503,10 +503,10 @@ format: >>> print(tabulate(table, headers, tablefmt="asciidoc")) [cols="8<,7>",options="header"] |==== -| item | qty -| spam | 42 -| eggs | 451 -| bacon | 0 +| item | qty +| spam | 42 +| eggs | 451 +| bacon | 0 |==== ``` @@ -1065,11 +1065,11 @@ the lines being wrapped would probably be significantly longer than this. Text is preferably wrapped on whitespaces and right after the hyphens in hyphenated words. -break_long_words (default: True) If true, then words longer than width will be broken in order to ensure that no lines are longer than width. +break_long_words (default: True) If true, then words longer than width will be broken in order to ensure that no lines are longer than width. If it is false, long words will not be broken, and some lines may be longer than width. (Long words will be put on a line by themselves, in order to minimize the amount by which width is exceeded.) -break_on_hyphens (default: True) If true, wrapping will occur preferably on whitespaces and right after hyphens in compound words, as it is customary in English. +break_on_hyphens (default: True) If true, wrapping will occur preferably on whitespaces and right after hyphens in compound words, as it is customary in English. If false, only whitespaces will be considered as potentially good places for line breaks. ```pycon diff --git a/tabulate/__init__.py b/tabulate/__init__.py index e100c09..69ed495 100644 --- a/tabulate/__init__.py +++ b/tabulate/__init__.py @@ -3,6 +3,7 @@ import warnings from collections import namedtuple from collections.abc import Iterable, Sized +from decimal import Decimal from html import escape as htmlescape from itertools import chain, zip_longest as izip_longest from functools import reduce, partial @@ -1357,6 +1358,8 @@ def _format(val, valtype, floatfmt, intfmt, missingval="", has_invisible=True): else: if isinstance(val, str) and "," in val: val = val.replace(",", "") # handle thousands-separators + if isinstance(val, Decimal): + return format(val, floatfmt) return format(float(val), floatfmt) else: return f"{val}" @@ -1588,9 +1591,11 @@ def _normalize_tabular_data(tabular_data, headers, showindex="default"): if headers == "keys": headers = field_names rows = [ - [getattr(row, f) for f in field_names] - if not _is_separating_line(row) - else row + ( + [getattr(row, f) for f in field_names] + if not _is_separating_line(row) + else row + ) for row in rows ] @@ -1638,7 +1643,13 @@ def _normalize_tabular_data(tabular_data, headers, showindex="default"): return rows, headers, headers_pad -def _wrap_text_to_colwidths(list_of_lists, colwidths, numparses=True, break_long_words=_BREAK_LONG_WORDS, break_on_hyphens=_BREAK_ON_HYPHENS): +def _wrap_text_to_colwidths( + list_of_lists, + colwidths, + numparses=True, + break_long_words=_BREAK_LONG_WORDS, + break_on_hyphens=_BREAK_ON_HYPHENS, +): if len(list_of_lists): num_cols = len(list_of_lists[0]) else: @@ -1655,7 +1666,11 @@ def _wrap_text_to_colwidths(list_of_lists, colwidths, numparses=True, break_long continue if width is not None: - wrapper = _CustomTextWrap(width=width, break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) + wrapper = _CustomTextWrap( + width=width, + break_long_words=break_long_words, + break_on_hyphens=break_on_hyphens, + ) casted_cell = str(cell) wrapped = [ "\n".join(wrapper.wrap(line)) @@ -2258,7 +2273,11 @@ def tabulate( numparses = _expand_numparse(disable_numparse, num_cols) list_of_lists = _wrap_text_to_colwidths( - list_of_lists, maxcolwidths, numparses=numparses, break_long_words=break_long_words, break_on_hyphens=break_on_hyphens + list_of_lists, + maxcolwidths, + numparses=numparses, + break_long_words=break_long_words, + break_on_hyphens=break_on_hyphens, ) if maxheadercolwidths is not None: @@ -2272,7 +2291,11 @@ def tabulate( numparses = _expand_numparse(disable_numparse, num_cols) headers = _wrap_text_to_colwidths( - [headers], maxheadercolwidths, numparses=numparses, break_long_words=break_long_words, break_on_hyphens=break_on_hyphens + [headers], + maxheadercolwidths, + numparses=numparses, + break_long_words=break_long_words, + break_on_hyphens=break_on_hyphens, )[0] # empty values in the first column of RST tables should be escaped (issue #82) diff --git a/test/test_output.py b/test/test_output.py index 12dfc3a..4befbb9 100644 --- a/test/test_output.py +++ b/test/test_output.py @@ -1,5 +1,6 @@ """Test output of the various forms of tabular data.""" +from decimal import Decimal from pytest import mark from common import assert_equal, raises, skip, check_warnings @@ -2896,6 +2897,16 @@ def test_floatfmt_multi(): assert_equal(expected, result) +def test_floatfmt_decimal(): + result = tabulate( + [[Decimal("99999998999.999980"), 1234.5, 1.2345678, "inf"]], + floatfmt=".6f", + tablefmt="plain", + ) + expected = "99999998999.999980 1234.500000 1.234568 inf" + assert_equal(expected, result) + + def test_colalign_multi(): "Output: string columns with custom colalign" result = tabulate( @@ -3320,6 +3331,7 @@ def test_preserve_whitespace(): result = tabulate(test_table, table_headers, preserve_whitespace=False) assert_equal(expected, result) + def test_break_long_words(): "Output: Default table output, with breakwords true." table_headers = ["h1", "h2", "h3"] @@ -3335,6 +3347,7 @@ def test_break_long_words(): result = tabulate(test_table, table_headers, maxcolwidths=3, break_long_words=True) assert_equal(expected, result) + def test_break_on_hyphens(): "Output: Default table output, with break on hyphens true." table_headers = ["h1", "h2", "h3"]