diff --git a/pandas/core/config_init.py b/pandas/core/config_init.py index f8cbdffa27bb4..790a9ed24b007 100644 --- a/pandas/core/config_init.py +++ b/pandas/core/config_init.py @@ -307,6 +307,21 @@ def mpl_style_cb(key): return val +def table_schema_cb(key): + # 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 + from pandas.core.generic import NDFrame, _ipython_display_ + + if cf.get_option(key): + NDFrame._ipython_display_ = _ipython_display_ + elif getattr(NDFrame, '_ipython_display_', None): + del NDFrame._ipython_display_ + + with cf.config_prefix('display'): cf.register_option('precision', 6, pc_precision_doc, validator=is_int) cf.register_option('float_format', None, float_format_doc, @@ -374,7 +389,7 @@ def mpl_style_cb(key): cf.register_option('latex.multirow', False, pc_latex_multirow, validator=is_bool) cf.register_option('html.table_schema', False, pc_table_schema_doc, - validator=is_bool) + validator=is_bool, cb=table_schema_cb) cf.deprecate_option('display.line_width', diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 70862015dff5b..9318a9f5ef27c 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -130,31 +130,6 @@ def __init__(self, data, axes=None, copy=False, dtype=None, object.__setattr__(self, '_data', data) object.__setattr__(self, '_item_cache', {}) - def _ipython_display_(self): - 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) - def _repr_table_schema_(self): """ Not a real Jupyter special repr method, but we use the same @@ -6283,6 +6258,38 @@ 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) + + # install the indexes for _name, _indexer in indexing.get_indexers_list(): NDFrame._create_indexer(_name, _indexer) diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 63cd08545610f..a5961910593f6 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -203,6 +203,33 @@ def test_config_default_off(self): assert result is None + def test_config_monkeypatches(self): + # GH 10491 + df = pd.DataFrame({"A": [1, 2]}) + 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_() + + 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_') + + # able to re-set + 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_() + # TODO: fix this broken test