From d76e988442346cc84d2487340d03a1513ea429bf Mon Sep 17 00:00:00 2001 From: jreback Date: Tue, 24 Sep 2013 15:24:04 -0400 Subject: [PATCH] API: raise a TypeError on invalid comparison ops on Series (e.g. integer/datetime) (GH4968) --- doc/source/release.rst | 1 + pandas/core/series.py | 8 +++++++- pandas/tests/test_frame.py | 25 +++++++++++++++++++++++++ pandas/tests/test_series.py | 15 +++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/doc/source/release.rst b/doc/source/release.rst index 285cea7938f91..b95509f70f56f 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -225,6 +225,7 @@ API Changes - moved timedeltas support to pandas.tseries.timedeltas.py; add timedeltas string parsing, add top-level ``to_timedelta`` function - ``NDFrame`` now is compatible with Python's toplevel ``abs()`` function (:issue:`4821`). + - raise a ``TypeError`` on invalid comparison ops on Series/DataFrame (e.g. integer/datetime) (:issue:`4968`) Internal Refactoring ~~~~~~~~~~~~~~~~~~~~ diff --git a/pandas/core/series.py b/pandas/core/series.py index 9f7ab0cb0346b..942bb700a3718 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -324,7 +324,13 @@ def na_op(x, y): else: result = lib.scalar_compare(x, y, op) else: - result = op(x, y) + + try: + result = getattr(x,name)(y) + if result is NotImplemented: + raise TypeError("invalid type comparison") + except (AttributeError): + result = op(x, y) return result diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 7b753f5d6a367..04ee6abcbac18 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -4296,6 +4296,31 @@ def test_operators_none_as_na(self): result = op(df.fillna(7), df) assert_frame_equal(result, expected) + def test_comparison_invalid(self): + + def check(df,df2): + + for (x, y) in [(df,df2),(df2,df)]: + self.assertRaises(TypeError, lambda : x == y) + self.assertRaises(TypeError, lambda : x != y) + self.assertRaises(TypeError, lambda : x >= y) + self.assertRaises(TypeError, lambda : x > y) + self.assertRaises(TypeError, lambda : x < y) + self.assertRaises(TypeError, lambda : x <= y) + + # GH4968 + # invalid date/int comparisons + df = DataFrame(np.random.randint(10, size=(10, 1)), columns=['a']) + df['dates'] = date_range('20010101', periods=len(df)) + + df2 = df.copy() + df2['dates'] = df['a'] + check(df,df2) + + df = DataFrame(np.random.randint(10, size=(10, 2)), columns=['a', 'b']) + df2 = DataFrame({'a': date_range('20010101', periods=len(df)), 'b': date_range('20100101', periods=len(df))}) + check(df,df2) + def test_modulo(self): # GH3590, modulo as ints diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index b2c5782d56b1f..6d3b052154147 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -2663,6 +2663,21 @@ def test_comparison_object_numeric_nas(self): expected = f(s.astype(float), shifted.astype(float)) assert_series_equal(result, expected) + def test_comparison_invalid(self): + + # GH4968 + # invalid date/int comparisons + s = Series(range(5)) + s2 = Series(date_range('20010101', periods=5)) + + for (x, y) in [(s,s2),(s2,s)]: + self.assertRaises(TypeError, lambda : x == y) + self.assertRaises(TypeError, lambda : x != y) + self.assertRaises(TypeError, lambda : x >= y) + self.assertRaises(TypeError, lambda : x > y) + self.assertRaises(TypeError, lambda : x < y) + self.assertRaises(TypeError, lambda : x <= y) + def test_more_na_comparisons(self): left = Series(['a', np.nan, 'c']) right = Series(['a', np.nan, 'd'])