Repository: astanin/python-tabulate (python)

Issue:
Can not tabulate row with a field that looks like a Python Bool using maxcolwidths
The following line will fail with an error about "bool' object has no attribute 'expandtabs'

    tabulate.tabulate([['init','True']], maxcolwidths=[None, 42])

This happens because the _wrap_text_to_col_widths method casts the cell to a casted cell by calling _type(cell, numpars)(cell)  which will convert the string 'True' into a bool.  Unfortunately the wrapper.wrap method called immediately after expects a str according to it's docstring and so explodes when passed a bool

My quick naïve reading suggests you could remove the entire if/else clause for casted_cell and just set casted cell equal to str(cell); if your next call only accepts a str why cast to anything else?  Still I'll leave it to those that know the code better then ignorant me to figure out the best fix.

Also completely random nitpick, but I noticed the _type method docstring lists other types it will convert, but does not include bool in it's description despite checking for and handling bools so may want to update that for consistency.

Pull request description:
Fix handling "True"/"False" bool str and None
calling `_type` is incorrect here; the subsequent lines need a `str`. Also you can't reconstruct `None` with `type(None)(None)` anyway. This regressed in e8e3091d46966f462735f227d5ef4effdfaa0582

Fixes #305

Patch:
diff --git a/tabulate/__init__.py b/tabulate/__init__.py
index b15d7f0..b937d6c 100644
--- a/tabulate/__init__.py
+++ b/tabulate/__init__.py
@@ -1641,13 +1641,7 @@ def _wrap_text_to_colwidths(list_of_lists, colwidths, numparses=True):
 
             if width is not None:
                 wrapper = _CustomTextWrap(width=width)
-                # Cast based on our internal type handling. Any future custom
-                # formatting of types (such as datetimes) may need to be more
-                # explicit than just `str` of the object. Also doesn't work for
-                # custom floatfmt/intfmt, nor with any missing/blank cells.
-                casted_cell = (
-                    str(cell) if _isnumber(cell) else _type(cell, numparse)(cell)
-                )
+                casted_cell = str(cell)
                 wrapped = [
                     "\n".join(wrapper.wrap(line))
                     for line in casted_cell.splitlines()


Test patch:
diff --git a/test/test_textwrapper.py b/test/test_textwrapper.py
index 8c0a6cc..46dd818 100644
--- a/test/test_textwrapper.py
+++ b/test/test_textwrapper.py
@@ -220,3 +220,27 @@ def test_wrap_datetime():
     ]
     expected = "\n".join(expected)
     assert_equal(expected, result)
+
+
+def test_wrap_optional_bool_strs():
+    """TextWrapper: Show that str bools and None can be wrapped without crashing"""
+    data = [
+        ["First Entry", "True"],
+        ["Second Entry", None],
+    ]
+    headers = ["Title", "When"]
+    result = tabulate(data, headers=headers, tablefmt="grid", maxcolwidths=[7, 5])
+
+    expected = [
+        "+---------+--------+",
+        "| Title   | When   |",
+        "+=========+========+",
+        "| First   | True   |",
+        "| Entry   |        |",
+        "+---------+--------+",
+        "| Second  | None   |",
+        "| Entry   |        |",
+        "+---------+--------+",
+    ]
+    expected = "\n".join(expected)
+    assert_equal(expected, result)