Skip to content

Commit a0879c2

Browse files
committed
Add urls_as_links option for DF to_html()
1 parent c55057f commit a0879c2

File tree

4 files changed

+116
-7
lines changed

4 files changed

+116
-7
lines changed

pandas/core/frame.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,7 +2086,7 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
20862086
sparsify=None, index_names=True, justify=None, bold_rows=True,
20872087
classes=None, escape=True, max_rows=None, max_cols=None,
20882088
show_dimensions=False, notebook=False, decimal='.',
2089-
border=None, table_id=None):
2089+
border=None, table_id=None, urls_as_links=False):
20902090
"""
20912091
Render a DataFrame as an HTML table.
20922092
@@ -2115,6 +2115,9 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
21152115
21162116
.. versionadded:: 0.23.0
21172117
2118+
urls_as_links : boolean, default False
2119+
Convert URLs to HTML links
2120+
21182121
%(returns)s
21192122
21202123
See Also
@@ -2137,7 +2140,8 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
21372140
max_rows=max_rows,
21382141
max_cols=max_cols,
21392142
show_dimensions=show_dimensions,
2140-
decimal=decimal, table_id=table_id)
2143+
decimal=decimal, table_id=table_id,
2144+
urls_as_links=urls_as_links)
21412145
# TODO: a generic formatter wld b in DataFrameFormatter
21422146
formatter.to_html(classes=classes, notebook=notebook, border=border)
21432147

pandas/io/formats/format.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
381381
justify=None, float_format=None, sparsify=None,
382382
index_names=True, line_width=None, max_rows=None,
383383
max_cols=None, show_dimensions=False, decimal='.',
384-
table_id=None, **kwds):
384+
table_id=None, urls_as_links=False, **kwds):
385385
self.frame = frame
386386
if buf is not None:
387387
self.buf = _expand_user(_stringify_path(buf))
@@ -408,6 +408,7 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
408408
len(self.frame))
409409
self.show_dimensions = show_dimensions
410410
self.table_id = table_id
411+
self.urls_as_links = urls_as_links
411412

412413
if justify is None:
413414
self.justify = get_option("display.colheader_justify")
@@ -733,7 +734,8 @@ def to_html(self, classes=None, notebook=False, border=None):
733734
max_cols=self.max_cols,
734735
notebook=notebook,
735736
border=border,
736-
table_id=self.table_id)
737+
table_id=self.table_id,
738+
urls_as_links=self.urls_as_links)
737739
if hasattr(self.buf, 'write'):
738740
html_renderer.write_result(self.buf)
739741
elif isinstance(self.buf, compat.string_types):

pandas/io/formats/html.py

Lines changed: 16 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+
urls_as_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.urls_as_links = urls_as_links
4952

5053
def write(self, s, indent=0):
5154
rs = pprint_thing(s)
@@ -74,9 +77,19 @@ def _write_cell(self, s, kind='td', indent=0, tags=None):
7477
('>', r'>')])
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.urls_as_links and _is_url(rs):
84+
rs_unescaped = pprint_thing(s, escape_chars={}).strip()
85+
start_tag += '<a href="{url}">'.format(url=rs_unescaped)
86+
end_a = '</a>'
87+
else:
88+
end_a = ''
89+
90+
self.write(u'{start}{rs}{end_a}</{kind}>'
91+
.format(start=start_tag, rs=rs, end_a=end_a, kind=kind),
92+
indent)
8093

8194
def write_tr(self, line, indent=0, indent_delta=4, header=False,
8295
align=None, tags=None, nindex_levels=0):

pandas/tests/io/formats/test_to_html.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,3 +1908,93 @@ def test_to_html_with_id(self):
19081908
name='myindexname'))
19091909
result = df.to_html(index_names=False, table_id="TEST_ID")
19101910
assert ' id="TEST_ID"' in result
1911+
1912+
def test_to_html_urls_as_links(self):
1913+
# GH 2679
1914+
1915+
data = [
1916+
{
1917+
'foo': 0,
1918+
'bar': 'http://pandas.pydata.org/',
1919+
None: 'pydata.org',
1920+
},
1921+
{
1922+
'foo': 0,
1923+
'bar': 'http://pandas.pydata.org/?q1=a&q2=b',
1924+
None: 'pydata.org',
1925+
},
1926+
{
1927+
'foo': 0,
1928+
'bar': 'www.pydata.org',
1929+
None: 'pydata.org',
1930+
},
1931+
]
1932+
df = DataFrame(data, columns=['foo', 'bar', None],
1933+
index=range(len(data)))
1934+
result_no_links = df.to_html()
1935+
result_with_links = df.to_html(urls_as_links=True)
1936+
expected_no_links = """\
1937+
<table border="1" class="dataframe">
1938+
<thead>
1939+
<tr style="text-align: right;">
1940+
<th></th>
1941+
<th>foo</th>
1942+
<th>bar</th>
1943+
<th>None</th>
1944+
</tr>
1945+
</thead>
1946+
<tbody>
1947+
<tr>
1948+
<th>0</th>
1949+
<td>0</td>
1950+
<td>http://pandas.pydata.org/</td>
1951+
<td>pydata.org</td>
1952+
</tr>
1953+
<tr>
1954+
<th>1</th>
1955+
<td>0</td>
1956+
<td>http://pandas.pydata.org/?q1=a&amp;q2=b</td>
1957+
<td>pydata.org</td>
1958+
</tr>
1959+
<tr>
1960+
<th>2</th>
1961+
<td>0</td>
1962+
<td>www.pydata.org</td>
1963+
<td>pydata.org</td>
1964+
</tr>
1965+
</tbody>
1966+
</table>"""
1967+
expected_with_links = """\
1968+
<table border="1" class="dataframe">
1969+
<thead>
1970+
<tr style="text-align: right;">
1971+
<th></th>
1972+
<th>foo</th>
1973+
<th>bar</th>
1974+
<th>None</th>
1975+
</tr>
1976+
</thead>
1977+
<tbody>
1978+
<tr>
1979+
<th>0</th>
1980+
<td>0</td>
1981+
<td><a href="http://pandas.pydata.org/">http://pandas.pydata.org/</a></td>
1982+
<td>pydata.org</td>
1983+
</tr>
1984+
<tr>
1985+
<th>1</th>
1986+
<td>0</td>
1987+
<td><a href="http://pandas.pydata.org/?q1=a&q2=b">http://pandas.pydata.org/?q1=a&amp;q2=b</a></td>
1988+
<td>pydata.org</td>
1989+
</tr>
1990+
<tr>
1991+
<th>2</th>
1992+
<td>0</td>
1993+
<td>www.pydata.org</td>
1994+
<td>pydata.org</td>
1995+
</tr>
1996+
</tbody>
1997+
</table>"""
1998+
1999+
assert result_with_links == expected_with_links
2000+
assert result_no_links == expected_no_links

0 commit comments

Comments
 (0)