From adf9343a0c1b7b39ada3990a27c82d46d89ad5cc Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 22 May 2017 06:44:45 -0500 Subject: [PATCH] COMPAT: Catch warnings on tab-complete in IPy 6 Properties may run code with Jedi completion in IPython 6 Closes https://github.com/pandas-dev/pandas/issues/16409 --- doc/source/whatsnew/v0.20.2.txt | 4 ++++ pandas/conftest.py | 10 ++++++++++ pandas/core/categorical.py | 7 +++++++ pandas/core/resample.py | 6 ++++++ pandas/tests/test_categorical.py | 11 +++++++++++ pandas/tests/test_resample.py | 17 +++++++++++++++-- 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.20.2.txt b/doc/source/whatsnew/v0.20.2.txt index 1f71710d19e44..eb9e31279616e 100644 --- a/doc/source/whatsnew/v0.20.2.txt +++ b/doc/source/whatsnew/v0.20.2.txt @@ -40,6 +40,10 @@ Bug Fixes - Bug in ``DataFrame.update()`` with ``overwrite=False`` and ``NaN values`` (:issue:`15593`) + +- Fixed a compatibility issue with IPython 6.0's tab completion showing deprecation warnings on Categoricals (:issue:`16409`) + + Conversion ^^^^^^^^^^ diff --git a/pandas/conftest.py b/pandas/conftest.py index 1149fae3fc0b0..8a3ffe22242ac 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -45,3 +45,13 @@ def spmatrix(request): tm._skip_if_no_scipy() from scipy import sparse return getattr(sparse, request.param + '_matrix') + + +@pytest.fixture +def ip(): + """An instance of IPython.InteractiveShell. + Will raise a skip if IPython is not installed. + """ + pytest.importorskip('IPython', minversion="6.0.0") + from IPython.core.interactiveshell import InteractiveShell + return InteractiveShell() diff --git a/pandas/core/categorical.py b/pandas/core/categorical.py index 5b663f1d85ee7..f58eed74f760e 100644 --- a/pandas/core/categorical.py +++ b/pandas/core/categorical.py @@ -342,6 +342,13 @@ def __init__(self, values, categories=None, ordered=False, fastpath=False): self._categories = categories self._codes = coerce_indexer_dtype(codes, categories) + def __dir__(self): + # Avoid IPython warnings for deprecated properties + # https://github.com/pandas-dev/pandas/issues/16409 + rv = set(dir(type(self))) + rv.discard("labels") + return sorted(rv) + @property def _constructor(self): return Categorical diff --git a/pandas/core/resample.py b/pandas/core/resample.py index 631b91c3aad11..2bb825541e23b 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -184,6 +184,12 @@ def __getattr__(self, attr): matches_pattern = any(attr.startswith(x) for x in self._deprecated_valid_patterns) if not matches_pattern and attr not in self._deprecated_valids: + # avoid the warning, if it's just going to be an exception + # anyway. + if not hasattr(self.obj, attr): + raise AttributeError("'{}' has no attribute '{}'".format( + type(self.obj).__name__, attr + )) self = self._deprecated(attr) return object.__getattribute__(self, attr) diff --git a/pandas/tests/test_categorical.py b/pandas/tests/test_categorical.py index f48eea23220b8..1ffe956b3a607 100644 --- a/pandas/tests/test_categorical.py +++ b/pandas/tests/test_categorical.py @@ -736,6 +736,17 @@ def test_unicode_print(self): assert _rep(c) == expected + def test_tab_complete_warning(self, ip): + # https://github.com/pandas-dev/pandas/issues/16409 + pytest.importorskip('IPython', minversion="6.0.0") + from IPython.core.completer import provisionalcompleter + + code = "import pandas as pd; c = pd.Categorical([])" + ip.run_code(code) + with tm.assert_produces_warning(None): + with provisionalcompleter('ignore'): + list(ip.Completer.completions('c.', 1)) + def test_periodindex(self): idx1 = PeriodIndex(['2014-01', '2014-01', '2014-02', '2014-02', '2014-03', '2014-03'], freq='M') diff --git a/pandas/tests/test_resample.py b/pandas/tests/test_resample.py index 37e2fd0e9b188..170cab4947a5a 100644 --- a/pandas/tests/test_resample.py +++ b/pandas/tests/test_resample.py @@ -3,6 +3,7 @@ from warnings import catch_warnings from datetime import datetime, timedelta from functools import partial +from textwrap import dedent import pytz import pytest @@ -284,8 +285,7 @@ def test_attribute_access(self): tm.assert_series_equal(r.A.sum(), r['A'].sum()) # getting - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): - pytest.raises(AttributeError, lambda: r.F) + pytest.raises(AttributeError, lambda: r.F) # setting def f(): @@ -2816,6 +2816,19 @@ def test_back_compat_v180(self): expected = df.groupby('A').resample('4s').mean().ffill() assert_frame_equal(result, expected) + def test_tab_complete_ipython6_warning(self, ip): + from IPython.core.completer import provisionalcompleter + code = dedent("""\ + import pandas.util.testing as tm + s = tm.makeTimeSeries() + rs = s.resample("D") + """) + ip.run_code(code) + + with tm.assert_produces_warning(None): + with provisionalcompleter('ignore'): + list(ip.Completer.completions('rs.', 1)) + def test_deferred_with_groupby(self): # GH 12486