Skip to content

Commit

Permalink
add in unsafe html format (PR#42)
Browse files Browse the repository at this point in the history
adding in unsafe html format, in case unescaped html is required in table
  • Loading branch information
danja100 authored Apr 7, 2020
1 parent 5ec0a6b commit a610a4d
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 9 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ Supported table formats are:
- "moinmoin"
- "youtrack"
- "html"
- "unsafehtml"
- "latex"
- "latex\_raw"
- "latex\_booktabs"
Expand Down Expand Up @@ -334,7 +335,8 @@ MediaWiki-based sites:

`html` produces standard HTML markup as an html.escape'd str
with a ._repr_html_ method so that Jupyter Lab and Notebook display the HTML
and a .str property so that the raw HTML remains accessible:
and a .str property so that the raw HTML remains accessible
the unsafehtml table format can be used if an unescaped HTML format is required:

>>> print(tabulate(table, headers, tablefmt="html"))
<table>
Expand Down
34 changes: 26 additions & 8 deletions tabulate.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,17 +182,23 @@ def _html_begin_table_without_header(colwidths_ignore, colaligns_ignore):
return "<table>\n<tbody>"


def _html_row_with_attrs(celltag, cell_values, colwidths, colaligns):
def _html_row_with_attrs(celltag, unsafe, cell_values, colwidths, colaligns):
alignment = {
"left": "",
"right": ' style="text-align: right;"',
"center": ' style="text-align: center;"',
"decimal": ' style="text-align: right;"',
}
values_with_attrs = [
"<{0}{1}>{2}</{0}>".format(celltag, alignment.get(a, ""), htmlescape(c))
for c, a in zip(cell_values, colaligns)
]
if unsafe:
values_with_attrs = [
"<{0}{1}>{2}</{0}>".format(celltag, alignment.get(a, ""), c)
for c, a in zip(cell_values, colaligns)
]
else:
values_with_attrs = [
"<{0}{1}>{2}</{0}>".format(celltag, alignment.get(a, ""), htmlescape(c))
for c, a in zip(cell_values, colaligns)
]
rowhtml = "<tr>{}</tr>".format("".join(values_with_attrs).rstrip())
if celltag == "th": # it's a header row, create a new table header
rowhtml = "<table>\n<thead>\n{}\n</thead>\n<tbody>".format(rowhtml)
Expand Down Expand Up @@ -429,8 +435,18 @@ def escape_empty(val):
linebelowheader="",
linebetweenrows=None,
linebelow=Line("</tbody>\n</table>", "", "", ""),
headerrow=partial(_html_row_with_attrs, "th"),
datarow=partial(_html_row_with_attrs, "td"),
headerrow=partial(_html_row_with_attrs, "th", False),
datarow=partial(_html_row_with_attrs, "td", False),
padding=0,
with_header_hide=["lineabove"],
),
"unsafehtml": TableFormat(
lineabove=_html_begin_table_without_header,
linebelowheader="",
linebetweenrows=None,
linebelow=Line("</tbody>\n</table>", "", "", ""),
headerrow=partial(_html_row_with_attrs, "th", True),
datarow=partial(_html_row_with_attrs, "td", True),
padding=0,
with_header_hide=["lineabove"],
),
Expand Down Expand Up @@ -1360,7 +1376,8 @@ def tabulate(
"html" produces HTML markup as an html.escape'd str
with a ._repr_html_ method so that Jupyter Lab and Notebook display the HTML
and a .str property so that the raw HTML remains accessible:
and a .str property so that the raw HTML remains accessible
the unsafehtml table format can be used if an unescaped HTML format is required:
>>> print(tabulate([["strings", "numbers"], ["spam", 41.9999], ["eggs", "451.0"]],
... headers="firstrow", tablefmt="html"))
Expand Down Expand Up @@ -1421,6 +1438,7 @@ def tabulate(
e.g. `disable_numparse=[0, 2]` would disable number parsing only on the
first and third columns.
"""

if tabular_data is None:
tabular_data = []
list_of_lists, headers = _normalize_tabular_data(
Expand Down
46 changes: 46 additions & 0 deletions test/test_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,11 @@ def test_moinmoin_headerless():

_test_table_html_headers = ["<strings>", "<&numbers&>"]
_test_table_html = [["spam >", 41.9999], ["eggs &", 451.0]]
_test_table_unsafehtml_headers = ["strings", "numbers"]
_test_table_unsafehtml = [
["spam", '<font color="red">41.9999</font>'],
["eggs", '<font color="red">451.0</font>'],
]


def test_html():
Expand All @@ -1027,6 +1032,29 @@ def test_html():
assert result._repr_html_() == result.str


def test_unsafehtml():
"Output: unsafe html with headers"
expected = "\n".join(
[
"<table>",
"<thead>",
"<tr><th>strings </th><th>numbers </th></tr>", # noqa
"</thead>",
"<tbody>",
'<tr><td>spam </td><td><font color="red">41.9999</font></td></tr>',
'<tr><td>eggs </td><td><font color="red">451.0</font> </td></tr>',
"</tbody>",
"</table>",
]
)
result = tabulate(
_test_table_unsafehtml, _test_table_unsafehtml_headers, tablefmt="unsafehtml"
)
assert_equal(expected, result)
assert hasattr(result, "_repr_html_")
assert result._repr_html_() == result.str


def test_html_headerless():
"Output: html without headers"
expected = "\n".join(
Expand All @@ -1045,6 +1073,24 @@ def test_html_headerless():
assert result._repr_html_() == result.str


def test_unsafehtml_headerless():
"Output: unsafe html without headers"
expected = "\n".join(
[
"<table>",
"<tbody>",
'<tr><td>spam</td><td><font color="red">41.9999</font></td></tr>',
'<tr><td>eggs</td><td><font color="red">451.0</font> </td></tr>',
"</tbody>",
"</table>",
]
)
result = tabulate(_test_table_unsafehtml, tablefmt="unsafehtml")
assert_equal(expected, result)
assert hasattr(result, "_repr_html_")
assert result._repr_html_() == result.str


def test_latex():
"Output: latex with headers and replaced characters"
raw_test_table_headers = list(_test_table_headers)
Expand Down

0 comments on commit a610a4d

Please sign in to comment.