From 9da5ca248370a6107b43fdfd3679e1658147df97 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Sat, 29 Apr 2017 06:36:11 -0500 Subject: [PATCH 1/3] BUG: Restore return value in notebook reprs Monkey patches the _ipython_display_ method onto NDFrame, so that notebook cells have a real return value. Setting the display.html.table_schema will monkey patch the method on, and remove it when unset. closes https://github.com/ipython/ipython/issues/10491 --- pandas/core/config_init.py | 44 +++++++++++++++++++++++- pandas/core/generic.py | 30 ++++------------ pandas/tests/io/formats/test_printing.py | 16 +++++++++ 3 files changed, 65 insertions(+), 25 deletions(-) diff --git a/pandas/core/config_init.py b/pandas/core/config_init.py index f8cbdffa27bb4..06346f1d003d2 100644 --- a/pandas/core/config_init.py +++ b/pandas/core/config_init.py @@ -307,6 +307,48 @@ 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] dicitonary breaks. + # Currently table schema is the only thing using it, so we'll + # monkey patch `_ipython_displa_` onto NDFrame when config option + # is set + # see https://github.com/pandas-dev/pandas/issues/16168 + from pandas.core.generic import NDFrame + + def _ipython_display_(self): + from pandas.errors import UnserializableWarning + + 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) + + 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 +416,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..c141a356312bc 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -130,30 +130,12 @@ 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_ipython_(self): + # This is defined in config_init.py and monkey patched + # onto NDFrame, depending on the display.html.table_schema + # setting. Defining a _repr_iptyhon_ means notebook cells to not + # have a return value. + # See https://github.com/ipython/ipython/issues/10491 def _repr_table_schema_(self): """ diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 63cd08545610f..a2ffddfe8e505 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -203,6 +203,22 @@ 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_') + # TODO: fix this broken test From c70de54bab1130a903cbaafc4f28938494806741 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Sat, 29 Apr 2017 09:29:04 -0500 Subject: [PATCH 2/3] Define in generic.py --- pandas/core/config_init.py | 33 ++------------------ pandas/core/generic.py | 39 +++++++++++++++++++----- pandas/tests/io/formats/test_printing.py | 13 ++++++++ 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/pandas/core/config_init.py b/pandas/core/config_init.py index 06346f1d003d2..790a9ed24b007 100644 --- a/pandas/core/config_init.py +++ b/pandas/core/config_init.py @@ -309,39 +309,12 @@ def mpl_style_cb(key): def table_schema_cb(key): # Having _ipython_display_ defined messes with the return value - # from cells, so the Out[x] dicitonary breaks. + # from cells, so the Out[x] dictionary breaks. # Currently table schema is the only thing using it, so we'll - # monkey patch `_ipython_displa_` onto NDFrame when config option + # 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 - - def _ipython_display_(self): - from pandas.errors import UnserializableWarning - - 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) + from pandas.core.generic import NDFrame, _ipython_display_ if cf.get_option(key): NDFrame._ipython_display_ = _ipython_display_ diff --git a/pandas/core/generic.py b/pandas/core/generic.py index c141a356312bc..9318a9f5ef27c 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -130,13 +130,6 @@ def __init__(self, data, axes=None, copy=False, dtype=None, object.__setattr__(self, '_data', data) object.__setattr__(self, '_item_cache', {}) - # def _repr_ipython_(self): - # This is defined in config_init.py and monkey patched - # onto NDFrame, depending on the display.html.table_schema - # setting. Defining a _repr_iptyhon_ means notebook cells to not - # have a return value. - # See https://github.com/ipython/ipython/issues/10491 - def _repr_table_schema_(self): """ Not a real Jupyter special repr method, but we use the same @@ -6265,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 a2ffddfe8e505..1842182ba8eda 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -218,6 +218,19 @@ def test_config_monkeypatches(self): 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 From fd24e27b4742984b301f35435232e8209f7be8b6 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Sun, 30 Apr 2017 06:13:50 -0500 Subject: [PATCH 3/3] PEP8 --- pandas/tests/io/formats/test_printing.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas/tests/io/formats/test_printing.py b/pandas/tests/io/formats/test_printing.py index 1842182ba8eda..a5961910593f6 100644 --- a/pandas/tests/io/formats/test_printing.py +++ b/pandas/tests/io/formats/test_printing.py @@ -231,8 +231,6 @@ def test_config_monkeypatches(self): df['A']._ipython_display_() - - # TODO: fix this broken test # def test_console_encode():