Skip to content

Commit

Permalink
fix bug in Datetime64Formatter, which affected custom date formatted …
Browse files Browse the repository at this point in the history
…output for df.to_string, df.to_html methods

added tests for time of day formatting and df.to_html
added test for formatters kw for df.to_latex

add whatsnew entry

move whatsnew entry higher up
  • Loading branch information
haleemur committed Jul 8, 2016
1 parent 2655dae commit 8d84283
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 1 deletion.
3 changes: 2 additions & 1 deletion doc/source/whatsnew/v0.18.2.txt
Expand Up @@ -529,4 +529,5 @@ Bug Fixes
- Bug in ``Categorical.remove_unused_categories()`` changes ``.codes`` dtype to platform int (:issue:`13261`)
- Bug in ``groupby`` with ``as_index=False`` returns all NaN's when grouping on multiple columns including a categorical one (:issue:`13204`)

- Bug where ``pd.read_gbq()`` could throw ``ImportError: No module named discovery`` as a result of a naming conflict with another python package called apiclient (:issue:`13454`)
- Bug in ``.to_html``, ``.to_latex`` and ``.to_string`` silently ignore custom datetime formatter passed through the ``formatters`` key word (:issue:`10690`)
- Bug where ``pd.read_gbq()`` could throw ``ImportError: No module named discovery`` as a result of a naming conflict with another python package called apiclient (:issue:`13454`)
4 changes: 4 additions & 0 deletions pandas/formats/format.py
Expand Up @@ -2239,9 +2239,13 @@ def _format_strings(self):
""" we by definition have DO NOT have a TZ """

values = self.values

if not isinstance(values, DatetimeIndex):
values = DatetimeIndex(values)

if self.formatter is not None and callable(self.formatter):
return [self.formatter(x) for x in values]

fmt_values = format_array_from_datetime(
values.asi8.ravel(),
format=_get_format_datetime64_from_values(values,
Expand Down
128 changes: 128 additions & 0 deletions pandas/tests/formats/test_format.py
Expand Up @@ -456,6 +456,28 @@ def test_to_string_with_formatters(self):
'2 0x3 [ 3.0] -False-'))
self.assertEqual(result, result2)

def test_to_string_with_datetime64_monthformatter(self):
months = [datetime(2016, 1, 1), datetime(2016, 2, 2)]
x = DataFrame({'months': months})

def format_func(x):
return x.strftime('%Y-%m')
result = x.to_string(formatters={'months': format_func})
expected = 'months\n0 2016-01\n1 2016-02'
self.assertEqual(result.strip(), expected)

def test_to_string_with_datetime64_hourformatter(self):

x = DataFrame({'hod': pd.to_datetime(['10:10:10.100', '12:12:12.120'],
format='%H:%M:%S.%f')})

def format_func(x):
return x.strftime('%H:%M')

result = x.to_string(formatters={'hod': format_func})
expected = 'hod\n0 10:10\n1 12:12'
self.assertEqual(result.strip(), expected)

def test_to_string_with_formatters_unicode(self):
df = DataFrame({u('c/\u03c3'): [1, 2, 3]})
result = df.to_string(formatters={u('c/\u03c3'): lambda x: '%s' % x})
Expand Down Expand Up @@ -1233,6 +1255,63 @@ def test_to_html_index_formatter(self):

self.assertEqual(result, expected)

def test_to_html_datetime64_monthformatter(self):
months = [datetime(2016, 1, 1), datetime(2016, 2, 2)]
x = DataFrame({'months': months})

def format_func(x):
return x.strftime('%Y-%m')
result = x.to_html(formatters={'months': format_func})
expected = """\
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>months</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>2016-01</td>
</tr>
<tr>
<th>1</th>
<td>2016-02</td>
</tr>
</tbody>
</table>"""
self.assertEqual(result, expected)

def test_to_html_datetime64_hourformatter(self):

x = DataFrame({'hod': pd.to_datetime(['10:10:10.100', '12:12:12.120'],
format='%H:%M:%S.%f')})

def format_func(x):
return x.strftime('%H:%M')
result = x.to_html(formatters={'hod': format_func})
expected = """\
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>hod</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>10:10</td>
</tr>
<tr>
<th>1</th>
<td>12:12</td>
</tr>
</tbody>
</table>"""
self.assertEqual(result, expected)

def test_to_html_regression_GH6098(self):
df = DataFrame({u('clé1'): [u('a'), u('a'), u('b'), u('b'), u('a')],
u('clé2'): [u('1er'), u('2ème'), u('1er'), u('2ème'),
Expand Down Expand Up @@ -2775,6 +2854,33 @@ def test_to_latex_format(self):

self.assertEqual(withindex_result, withindex_expected)

def test_to_latex_with_formatters(self):
df = DataFrame({'int': [1, 2, 3],
'float': [1.0, 2.0, 3.0],
'object': [(1, 2), True, False],
'datetime64': [datetime(2016, 1, 1),
datetime(2016, 2, 5),
datetime(2016, 3, 3)]})

formatters = {'int': lambda x: '0x%x' % x,
'float': lambda x: '[% 4.1f]' % x,
'object': lambda x: '-%s-' % str(x),
'datetime64': lambda x: x.strftime('%Y-%m'),
'__index__': lambda x: 'index: %s' % x}
result = df.to_latex(formatters=dict(formatters))

expected = r"""\begin{tabular}{llrrl}
\toprule
{} & datetime64 & float & int & object \\
\midrule
index: 0 & 2016-01 & [ 1.0] & 0x1 & -(1, 2)- \\
index: 1 & 2016-02 & [ 2.0] & 0x2 & -True- \\
index: 2 & 2016-03 & [ 3.0] & 0x3 & -False- \\
\bottomrule
\end{tabular}
"""
self.assertEqual(result, expected)

def test_to_latex_multiindex(self):
df = DataFrame({('x', 'y'): ['a']})
result = df.to_latex()
Expand Down Expand Up @@ -4161,6 +4267,28 @@ def test_dates_display(self):
self.assertEqual(result[1].strip(), "NaT")
self.assertEqual(result[4].strip(), "2013-01-01 09:00:00.000000004")

def test_datetime64formatter_yearmonth(self):
x = Series([datetime(2016, 1, 1), datetime(2016, 2, 2)])

def format_func(x):
return x.strftime('%Y-%m')

formatter = fmt.Datetime64Formatter(x, formatter=format_func)
result = formatter.get_result()
self.assertEqual(result, ['2016-01', '2016-02'])

def test_datetime64formatter_hoursecond(self):

x = Series(pd.to_datetime(['10:10:10.100', '12:12:12.120'],
format='%H:%M:%S.%f'))

def format_func(x):
return x.strftime('%H:%M')

formatter = fmt.Datetime64Formatter(x, formatter=format_func)
result = formatter.get_result()
self.assertEqual(result, ['10:10', '12:12'])


class TestNaTFormatting(tm.TestCase):

Expand Down

0 comments on commit 8d84283

Please sign in to comment.