Skip to content

Commit 0702824

Browse files
committed
ENH: Add render_links option to DataFrame to_html()
1 parent b7294dd commit 0702824

File tree

4 files changed

+85
-8
lines changed

4 files changed

+85
-8
lines changed

pandas/core/frame.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,8 +2093,8 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
20932093
index=True, na_rep='NaN', formatters=None, float_format=None,
20942094
sparsify=None, index_names=True, justify=None, max_rows=None,
20952095
max_cols=None, show_dimensions=False, decimal='.',
2096-
bold_rows=True, classes=None, escape=True,
2097-
notebook=False, border=None, table_id=None):
2096+
bold_rows=True, classes=None, escape=True, notebook=False,
2097+
border=None, table_id=None, render_links=False):
20982098
"""
20992099
Render a DataFrame as an HTML table.
21002100
%(shared_params)s
@@ -2116,6 +2116,12 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
21162116
A css id is included in the opening `<table>` tag if specified.
21172117
21182118
.. versionadded:: 0.23.0
2119+
2120+
render_links : boolean, default False
2121+
Convert URLs to HTML links.
2122+
2123+
.. versionadded:: 0.24.0
2124+
21192125
%(returns)s
21202126
See Also
21212127
--------
@@ -2137,7 +2143,8 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
21372143
max_rows=max_rows,
21382144
max_cols=max_cols,
21392145
show_dimensions=show_dimensions,
2140-
decimal=decimal, table_id=table_id)
2146+
decimal=decimal, table_id=table_id,
2147+
render_links=render_links)
21412148
# TODO: a generic formatter wld b in DataFrameFormatter
21422149
formatter.to_html(classes=classes, notebook=notebook, border=border)
21432150

pandas/io/formats/format.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
383383
justify=None, float_format=None, sparsify=None,
384384
index_names=True, line_width=None, max_rows=None,
385385
max_cols=None, show_dimensions=False, decimal='.',
386-
table_id=None, **kwds):
386+
table_id=None, render_links=False, **kwds):
387387
self.frame = frame
388388
if buf is not None:
389389
self.buf = _expand_user(_stringify_path(buf))
@@ -410,6 +410,7 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
410410
len(self.frame))
411411
self.show_dimensions = show_dimensions
412412
self.table_id = table_id
413+
self.render_links = render_links
413414

414415
if justify is None:
415416
self.justify = get_option("display.colheader_justify")
@@ -735,7 +736,8 @@ def to_html(self, classes=None, notebook=False, border=None):
735736
max_cols=self.max_cols,
736737
notebook=notebook,
737738
border=border,
738-
table_id=self.table_id)
739+
table_id=self.table_id,
740+
render_links=self.render_links)
739741
if hasattr(self.buf, 'write'):
740742
html_renderer.write_result(self.buf)
741743
elif isinstance(self.buf, compat.string_types):

pandas/io/formats/html.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@
1919
from pandas.io.formats.format import (
2020
TableFormatter, buffer_put_lines, get_level_lengths)
2121
from pandas.io.formats.printing import pprint_thing
22+
from pandas.io.common import _is_url
2223

2324

2425
class HTMLFormatter(TableFormatter):
2526

2627
indent_delta = 2
2728

2829
def __init__(self, formatter, classes=None, max_rows=None, max_cols=None,
29-
notebook=False, border=None, table_id=None):
30+
notebook=False, border=None, table_id=None,
31+
render_links=False):
3032
self.fmt = formatter
3133
self.classes = classes
3234

@@ -46,6 +48,7 @@ def __init__(self, formatter, classes=None, max_rows=None, max_cols=None,
4648
border = get_option('display.html.border')
4749
self.border = border
4850
self.table_id = table_id
51+
self.render_links = render_links
4952

5053
def write(self, s, indent=0):
5154
rs = pprint_thing(s)
@@ -74,9 +77,20 @@ def _write_cell(self, s, kind='td', indent=0, tags=None):
7477
('>', r'&gt;')])
7578
else:
7679
esc = {}
80+
7781
rs = pprint_thing(s, escape_chars=esc).strip()
78-
self.write(u'{start}{rs}</{kind}>'
79-
.format(start=start_tag, rs=rs, kind=kind), indent)
82+
83+
if self.render_links and _is_url(rs):
84+
rs_unescaped = pprint_thing(s, escape_chars={}).strip()
85+
start_tag += '<a href="{url}" target="_blank">'\
86+
.format(url=rs_unescaped)
87+
end_a = '</a>'
88+
else:
89+
end_a = ''
90+
91+
self.write('{start}{rs}{end_a}</{kind}>'
92+
.format(start=start_tag, rs=rs, end_a=end_a, kind=kind),
93+
indent)
8094

8195
def write_tr(self, line, indent=0, indent_delta=0, header=False,
8296
align=None, tags=None, nindex_levels=0):

pandas/tests/io/formats/test_to_html.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,3 +477,57 @@ def test_to_html_float_format_no_fixed_width(self, datapath):
477477
df = DataFrame({'x': [100.0]})
478478
expected = expected_html(datapath, 'gh22270_expected_output')
479479
assert df.to_html(float_format='%.0f') == expected
480+
481+
@pytest.mark.parametrize("render_links", [True, False])
482+
def test_to_html_render_links(self, render_links):
483+
# GH 2679
484+
485+
data = [
486+
{
487+
'foo': 0,
488+
'bar': 'http://pandas.pydata.org/?q1=a&q2=b',
489+
None: 'pydata.org',
490+
},
491+
{
492+
'foo': 0,
493+
'bar': 'www.pydata.org',
494+
None: 'pydata.org',
495+
},
496+
]
497+
df = DataFrame(data, columns=['foo', 'bar', None],
498+
index=range(len(data)))
499+
500+
result = df.to_html(render_links=render_links)
501+
502+
open_tag = not render_links and '<td>' or\
503+
('<td><a href="http://pandas.pydata.org/?q1=a&q2=b"'
504+
' target="_blank">')
505+
close_tag = not render_links and '</td>' or '</a></td>'
506+
507+
expected = dedent("""\
508+
<table border="1" class="dataframe">
509+
<thead>
510+
<tr style="text-align: right;">
511+
<th></th>
512+
<th>foo</th>
513+
<th>bar</th>
514+
<th>None</th>
515+
</tr>
516+
</thead>
517+
<tbody>
518+
<tr>
519+
<th>0</th>
520+
<td>0</td>
521+
{open_tag}http://pandas.pydata.org/?q1=a&amp;q2=b{close_tag}
522+
<td>pydata.org</td>
523+
</tr>
524+
<tr>
525+
<th>1</th>
526+
<td>0</td>
527+
<td>www.pydata.org</td>
528+
<td>pydata.org</td>
529+
</tr>
530+
</tbody>
531+
</table>""").format(open_tag=open_tag, close_tag=close_tag)
532+
533+
assert result == expected

0 commit comments

Comments
 (0)