-
-
Notifications
You must be signed in to change notification settings - Fork 18k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
register custom DisplayFormatter for table schema #16198
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,7 +43,6 @@ | |
import pandas.core.algorithms as algos | ||
import pandas.core.common as com | ||
import pandas.core.missing as missing | ||
from pandas.errors import UnserializableWarning | ||
from pandas.io.formats.printing import pprint_thing | ||
from pandas.io.formats.format import format_percentiles | ||
from pandas.tseries.frequencies import to_offset | ||
|
@@ -6279,36 +6278,6 @@ def logical_func(self, axis=None, bool_only=None, skipna=None, level=None, | |
return set_function_name(logical_func, name, cls) | ||
|
||
|
||
def _ipython_display_(self): | ||
# Having _ipython_display_ defined messes with the return value | ||
# from cells, so the Out[x] dictionary breaks. | ||
# Currently table schema is the only thing using it, so we'll | ||
# monkey patch `_ipython_display_` onto NDFrame when config option | ||
# is set | ||
# see https://github.com/pandas-dev/pandas/issues/16168 | ||
try: | ||
from IPython.display import display | ||
except ImportError: | ||
return None | ||
|
||
# Series doesn't define _repr_html_ or _repr_latex_ | ||
latex = self._repr_latex_() if hasattr(self, '_repr_latex_') else None | ||
html = self._repr_html_() if hasattr(self, '_repr_html_') else None | ||
try: | ||
table_schema = self._repr_table_schema_() | ||
except Exception as e: | ||
warnings.warn("Cannot create table schema representation. " | ||
"{}".format(e), UnserializableWarning) | ||
table_schema = None | ||
# We need the inital newline since we aren't going through the | ||
# usual __repr__. See | ||
# https://github.com/pandas-dev/pandas/pull/14904#issuecomment-277829277 | ||
text = "\n" + repr(self) | ||
|
||
reprs = {"text/plain": text, "text/html": html, "text/latex": latex, | ||
"application/vnd.dataresource+json": table_schema} | ||
reprs = {k: v for k, v in reprs.items() if v} | ||
display(reprs, raw=True) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some whitespace issues here https://travis-ci.org/pandas-dev/pandas/jobs/228015735#L1354 |
||
|
||
# install the indexes | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,6 @@ | |
import pandas as pd | ||
|
||
from pandas import compat | ||
from pandas.errors import UnserializableWarning | ||
import pandas.io.formats.printing as printing | ||
import pandas.io.formats.format as fmt | ||
import pandas.util.testing as tm | ||
|
@@ -137,55 +136,46 @@ def setUpClass(cls): | |
except ImportError: | ||
pytest.skip("Mock is not installed") | ||
cls.mock = mock | ||
from IPython.core.interactiveshell import InteractiveShell | ||
cls.display_formatter = InteractiveShell.instance().display_formatter | ||
|
||
def test_publishes(self): | ||
|
||
df = pd.DataFrame({"A": [1, 2]}) | ||
objects = [df['A'], df, df] # dataframe / series | ||
expected_keys = [ | ||
{'text/plain', 'application/vnd.dataresource+json'}, | ||
{'text/plain', 'text/html', 'application/vnd.dataresource+json'}, | ||
] | ||
|
||
make_patch = self.mock.patch('IPython.display.display') | ||
opt = pd.option_context('display.html.table_schema', True) | ||
for obj, expected in zip(objects, expected_keys): | ||
with opt, make_patch as mock_display: | ||
handle = obj._ipython_display_() | ||
assert mock_display.call_count == 1 | ||
assert handle is None | ||
args, kwargs = mock_display.call_args | ||
arg, = args # just one argument | ||
|
||
assert kwargs == {"raw": True} | ||
assert set(arg.keys()) == expected | ||
with opt: | ||
formatted = self.display_formatter.format(obj) | ||
assert set(formatted[0].keys()) == expected | ||
|
||
with_latex = pd.option_context('display.latex.repr', True) | ||
|
||
with opt, with_latex, make_patch as mock_display: | ||
handle = obj._ipython_display_() | ||
args, kwargs = mock_display.call_args | ||
arg, = args | ||
with opt, with_latex: | ||
formatted = self.display_formatter.format(obj) | ||
|
||
expected = {'text/plain', 'text/html', 'text/latex', | ||
'application/vnd.dataresource+json'} | ||
assert set(arg.keys()) == expected | ||
assert set(formatted[0].keys()) == expected | ||
|
||
def test_publishes_not_implemented(self): | ||
# column MultiIndex | ||
# GH 15996 | ||
midx = pd.MultiIndex.from_product([['A', 'B'], ['a', 'b', 'c']]) | ||
df = pd.DataFrame(np.random.randn(5, len(midx)), columns=midx) | ||
|
||
make_patch = self.mock.patch('IPython.display.display') | ||
opt = pd.option_context('display.html.table_schema', True) | ||
with opt, make_patch as mock_display: | ||
with pytest.warns(UnserializableWarning) as record: | ||
df._ipython_display_() | ||
args, _ = mock_display.call_args | ||
arg, = args # just one argument | ||
|
||
with opt: | ||
formatted = self.display_formatter.format(df) | ||
|
||
expected = {'text/plain', 'text/html'} | ||
assert set(arg.keys()) == expected | ||
assert set(formatted[0].keys()) == expected | ||
assert "orient='table' is not supported for MultiIndex" in ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will have to remove this line. |
||
record[-1].message.args[0]) | ||
|
||
|
@@ -209,26 +199,23 @@ def test_config_monkeypatches(self): | |
assert not hasattr(df, '_ipython_display_') | ||
assert not hasattr(df['A'], '_ipython_display_') | ||
|
||
with pd.option_context('display.html.table_schema', True): | ||
assert hasattr(df, '_ipython_display_') | ||
# smoke test that it works | ||
df._ipython_display_() | ||
assert hasattr(df['A'], '_ipython_display_') | ||
df['A']._ipython_display_() | ||
formatters = self.display_formatter.formatters | ||
mimetype = 'application/vnd.dataresource+json' | ||
|
||
assert not hasattr(df, '_ipython_display_') | ||
assert not hasattr(df['A'], '_ipython_display_') | ||
# re-unsetting is OK | ||
assert not hasattr(df, '_ipython_display_') | ||
assert not hasattr(df['A'], '_ipython_display_') | ||
with pd.option_context('display.html.table_schema', True): | ||
assert 'application/vnd.dataresource+json' in formatters | ||
assert formatters[mimetype].enabled | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think our linter complained about whitespace here. |
||
# still there, just disabled | ||
assert 'application/vnd.dataresource+json' in formatters | ||
assert not formatters[mimetype].enabled | ||
|
||
# able to re-set | ||
with pd.option_context('display.html.table_schema', True): | ||
assert hasattr(df, '_ipython_display_') | ||
assert 'application/vnd.dataresource+json' in formatters | ||
assert formatters[mimetype].enabled | ||
# smoke test that it works | ||
df._ipython_display_() | ||
assert hasattr(df['A'], '_ipython_display_') | ||
df['A']._ipython_display_() | ||
self.display_formatter.format(cf) | ||
|
||
|
||
# TODO: fix this broken test | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm beginning to wonder if we should be calling this repr_data_resource, based on the mimetype we ended up at (which includes the schema inside)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea being "table schema" refers to just the schema? Makes sense to me.