From 75638764adf4135d8ee889ea28e627ca4c30a94c Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 7 Mar 2018 18:43:32 -0800 Subject: [PATCH 1/9] implement add/sub for period_dtype other --- doc/source/whatsnew/v0.23.0.txt | 1 + pandas/core/indexes/datetimelike.py | 45 +++++++++++++- .../indexes/datetimes/test_arithmetic.py | 11 ++++ .../tests/indexes/period/test_arithmetic.py | 62 +++++++++++++------ .../indexes/timedeltas/test_arithmetic.py | 12 ++++ 5 files changed, 111 insertions(+), 20 deletions(-) diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index 233816600ec0f..451974a8006d2 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -710,6 +710,7 @@ Other API Changes - ``Categorical.fillna`` now validates its ``value`` and ``method`` keyword arguments. It now raises when both or none are specified, matching the behavior of :meth:`Series.fillna` (:issue:`19682`) - ``pd.to_datetime('today')`` now returns a datetime, consistent with ``pd.Timestamp('today')``; previously ``pd.to_datetime('today')`` returned a ``.normalized()`` datetime (:issue:`19935`) - :func:`Series.str.replace` now takes an optional `regex` keyword which, when set to ``False``, uses literal string replacement rather than regex replacement (:issue:`16808`) +- :class:`PeriodIndex` subtraction of another ``PeriodIndex`` will now return a numeric ``Index`` instead of raising a ``TypeErrorr`` (:issue:`?????`) .. _whatsnew_0230.deprecations: diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index e673bfe411cb4..f3ad87d798921 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -13,7 +13,8 @@ import numpy as np from pandas._libs import lib, iNaT, NaT -from pandas._libs.tslibs.period import Period +from pandas._libs.tslibs.period import (Period, IncompatibleFrequency, + _DIFFERENT_FREQ_INDEX) from pandas._libs.tslibs.timedeltas import delta_to_nanoseconds from pandas._libs.tslibs.timestamps import round_ns @@ -667,6 +668,43 @@ def _sub_nat(self): def _sub_period(self, other): return NotImplemented + def _sub_period_array(self, other): + """ + Subtract one PeriodIndex from another. This is only valid if they + have the same frequency. + + Parameters + ---------- + other : PeriodIndex + + Returns + ------- + result : np.ndarray + dtype is np.int64 if there are no NaTs in self or other, + otherwise np.float64 + """ + if not is_period_dtype(self): + raise TypeError("cannot subtract {dtype}-dtype to {cls}" + .format(dtype=other.dtype, + cls=type(self).__name__)) + + if not len(self) == len(other): + raise ValueError("cannot add indices of unequal length") + if self.freq != other.freq: + msg = _DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) + raise IncompatibleFrequency(msg) + + new_values = checked_add_with_arr(self.asi8, -other.asi8, + arr_mask=self._isnan, + b_mask=other._isnan) + new_values = new_values + if self.hasnans or other.hasnans: + # we have to convert to float to represent NaNs + mask = (self._isnan) | (other._isnan) + new_values = new_values.astype(np.float64) + new_values[mask] = np.nan + return new_values + def _add_offset(self, offset): raise com.AbstractMethodError(self) @@ -740,7 +778,7 @@ def __add__(self, other): elif is_integer_dtype(other) and self.freq is None: # GH#19123 raise NullFrequencyError("Cannot shift with no freq") - elif is_float_dtype(other): + elif is_float_dtype(other) or is_period_dtype(other): # Explicitly catch invalid dtypes raise TypeError("cannot add {dtype}-dtype to {cls}" .format(dtype=other.dtype, @@ -799,6 +837,9 @@ def __sub__(self, other): elif is_datetime64_dtype(other) or is_datetime64tz_dtype(other): # DatetimeIndex, ndarray[datetime64] result = self._sub_datelike(other) + elif is_period_dtype(other): + # PeriodIndex + result = self._sub_period_array(other) elif isinstance(other, Index): raise TypeError("cannot subtract {cls} and {typ}" .format(cls=type(self).__name__, diff --git a/pandas/tests/indexes/datetimes/test_arithmetic.py b/pandas/tests/indexes/datetimes/test_arithmetic.py index 8f259a7e78897..f1ac595e76a1a 100644 --- a/pandas/tests/indexes/datetimes/test_arithmetic.py +++ b/pandas/tests/indexes/datetimes/test_arithmetic.py @@ -696,6 +696,17 @@ def test_sub_period(self, freq): with pytest.raises(TypeError): p - idx + @pytest.mark.parametrize('op', [operator.add, ops.radd, + operator.sub, ops.rsub]) + @pytest.mark.parametrize('pi_freq', ['D', 'W', 'Q', 'H']) + @pytest.mark.parametrize('dti_freq', [None, 'D']) + def test_dti_sub_pi(self, dti_freq, pi_freq, op): + # subtracting PeriodIndex should raise TypeError + dti = pd.DatetimeIndex(['2011-01-01', '2011-01-02'], freq=dti_freq) + pi = dti.to_period(pi_freq) + with pytest.raises(TypeError): + op(dti, pi) + def test_ufunc_coercions(self): idx = date_range('2011-01-01', periods=3, freq='2D', name='x') diff --git a/pandas/tests/indexes/period/test_arithmetic.py b/pandas/tests/indexes/period/test_arithmetic.py index c75fdd35a974c..57170dc328d80 100644 --- a/pandas/tests/indexes/period/test_arithmetic.py +++ b/pandas/tests/indexes/period/test_arithmetic.py @@ -258,6 +258,42 @@ def test_comp_nat(self, dtype): class TestPeriodIndexArithmetic(object): + # --------------------------------------------------------------- + # __add__/__sub__ with PeriodIndex + + def test_pi_add_iadd_pi_raises(self): + rng = pd.period_range('1/1/2000', freq='D', periods=5) + other = pd.period_range('1/6/2000', freq='D', periods=5) + + # previously performed setop union, now raises TypeError (GH14164) + with pytest.raises(TypeError): + rng + other + + with pytest.raises(TypeError): + rng += other + + def test_pi_sub_pi(self): + rng = pd.period_range('1/1/2000', freq='D', periods=5) + other = pd.period_range('1/6/2000', freq='D', periods=5) + + result = rng - other + expected = pd.Int64Index([-5, -5, -5, -5, -5]) + tm.assert_index_equal(result, expected) + + def test_pi_sub_pi_with_nat(self): + rng = pd.period_range('1/1/2000', freq='D', periods=5) + other = rng[1:].insert(0, pd.NaT) + assert other[1:].equals(rng[1:]) + + result = rng - other + expected = pd.Float64Index([np.nan, 0, 0, 0, 0]) + tm.assert_index_equal(result, expected) + + def test_pi_sub_pi_mismatched_freq(self): + rng = pd.period_range('1/1/2000', freq='D', periods=5) + other = pd.period_range('1/6/2000', freq='H', periods=5) + with pytest.raises(period.IncompatibleFrequency): + rng - other # ------------------------------------------------------------- # Invalid Operations @@ -379,17 +415,6 @@ def test_pi_sub_offset_array(self, box): with tm.assert_produces_warning(PerformanceWarning): anchored - pi - def test_pi_add_iadd_pi_raises(self): - rng = pd.period_range('1/1/2000', freq='D', periods=5) - other = pd.period_range('1/6/2000', freq='D', periods=5) - - # previously performed setop union, now raises TypeError (GH14164) - with pytest.raises(TypeError): - rng + other - - with pytest.raises(TypeError): - rng += other - def test_pi_add_iadd_int(self, one): # Variants of `one` for #19012 rng = pd.period_range('2000-01-01 09:00', freq='H', periods=10) @@ -419,17 +444,18 @@ def test_pi_sub_intlike(self, five): exp = rng + (-five) tm.assert_index_equal(result, exp) - def test_pi_sub_isub_pi_raises(self): - # previously performed setop, now raises TypeError (GH14164) - # TODO needs to wait on #13077 for decision on result type + def test_pi_sub_isub_pi(self): + # previously raised TypeError (GH#14164), before that + # performed set operation. See discussion in GH#13077 rng = pd.period_range('1/1/2000', freq='D', periods=5) other = pd.period_range('1/6/2000', freq='D', periods=5) - with pytest.raises(TypeError): - rng - other + expected = pd.Int64Index([-5, -5, -5, -5, -5]) + result = rng - other + tm.assert_index_equal(result, expected) - with pytest.raises(TypeError): - rng -= other + rng -= other + tm.assert_index_equal(rng, expected) def test_pi_sub_isub_offset(self): # offset diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index 9035434046ccb..8da9f31d1d3f8 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -305,6 +305,18 @@ def test_tdi_sub_period(self, freq): with pytest.raises(TypeError): p - idx + @pytest.mark.parametrize('op', [operator.add, ops.radd, + operator.sub, ops.rsub]) + @pytest.mark.parametrize('pi_freq', ['D', 'W', 'Q', 'H']) + @pytest.mark.parametrize('tdi_freq', [None, 'H']) + def test_dti_sub_pi(self, tdi_freq, pi_freq, op): + # subtracting PeriodIndex should raise TypeError + tdi = pd.TimedeltaIndex(['1 hours', '2 hours'], freq=tdi_freq) + dti = pd.Timestamp('2018-03-07 17:16:40') + tdi + pi = dti.to_period(pi_freq) + with pytest.raises(TypeError): + op(dti, pi) + # ------------------------------------------------------------- # TimedeltaIndex.shift is used by __add__/__sub__ From 14f8d86f1b319f4a35a8c89fec5fccfda3190d43 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Wed, 7 Mar 2018 18:46:20 -0800 Subject: [PATCH 2/9] add GH reference --- doc/source/whatsnew/v0.23.0.txt | 2 +- pandas/tests/indexes/datetimes/test_arithmetic.py | 2 +- pandas/tests/indexes/period/test_arithmetic.py | 1 + pandas/tests/indexes/timedeltas/test_arithmetic.py | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index 451974a8006d2..7dbc5239fa3df 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -710,7 +710,7 @@ Other API Changes - ``Categorical.fillna`` now validates its ``value`` and ``method`` keyword arguments. It now raises when both or none are specified, matching the behavior of :meth:`Series.fillna` (:issue:`19682`) - ``pd.to_datetime('today')`` now returns a datetime, consistent with ``pd.Timestamp('today')``; previously ``pd.to_datetime('today')`` returned a ``.normalized()`` datetime (:issue:`19935`) - :func:`Series.str.replace` now takes an optional `regex` keyword which, when set to ``False``, uses literal string replacement rather than regex replacement (:issue:`16808`) -- :class:`PeriodIndex` subtraction of another ``PeriodIndex`` will now return a numeric ``Index`` instead of raising a ``TypeErrorr`` (:issue:`?????`) +- :class:`PeriodIndex` subtraction of another ``PeriodIndex`` will now return a numeric ``Index`` instead of raising a ``TypeErrorr`` (:issue:`20049`) .. _whatsnew_0230.deprecations: diff --git a/pandas/tests/indexes/datetimes/test_arithmetic.py b/pandas/tests/indexes/datetimes/test_arithmetic.py index f1ac595e76a1a..db7d0c7b58eac 100644 --- a/pandas/tests/indexes/datetimes/test_arithmetic.py +++ b/pandas/tests/indexes/datetimes/test_arithmetic.py @@ -701,7 +701,7 @@ def test_sub_period(self, freq): @pytest.mark.parametrize('pi_freq', ['D', 'W', 'Q', 'H']) @pytest.mark.parametrize('dti_freq', [None, 'D']) def test_dti_sub_pi(self, dti_freq, pi_freq, op): - # subtracting PeriodIndex should raise TypeError + # GH#20049subtracting PeriodIndex should raise TypeError dti = pd.DatetimeIndex(['2011-01-01', '2011-01-02'], freq=dti_freq) pi = dti.to_period(pi_freq) with pytest.raises(TypeError): diff --git a/pandas/tests/indexes/period/test_arithmetic.py b/pandas/tests/indexes/period/test_arithmetic.py index 57170dc328d80..75b3c2d3f9547 100644 --- a/pandas/tests/indexes/period/test_arithmetic.py +++ b/pandas/tests/indexes/period/test_arithmetic.py @@ -445,6 +445,7 @@ def test_pi_sub_intlike(self, five): tm.assert_index_equal(result, exp) def test_pi_sub_isub_pi(self): + # GH#20049 # previously raised TypeError (GH#14164), before that # performed set operation. See discussion in GH#13077 rng = pd.period_range('1/1/2000', freq='D', periods=5) diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index 8da9f31d1d3f8..ac0a55a4e512b 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -310,7 +310,7 @@ def test_tdi_sub_period(self, freq): @pytest.mark.parametrize('pi_freq', ['D', 'W', 'Q', 'H']) @pytest.mark.parametrize('tdi_freq', [None, 'H']) def test_dti_sub_pi(self, tdi_freq, pi_freq, op): - # subtracting PeriodIndex should raise TypeError + # GH#20049 subtracting PeriodIndex should raise TypeError tdi = pd.TimedeltaIndex(['1 hours', '2 hours'], freq=tdi_freq) dti = pd.Timestamp('2018-03-07 17:16:40') + tdi pi = dti.to_period(pi_freq) From f2dac592010a501b275d28924e942d44dfa1ed5e Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 4 Jun 2018 10:09:18 -0700 Subject: [PATCH 3/9] change return type from Int64Index to Index[DateOffset] --- pandas/core/indexes/datetimelike.py | 12 +++++------- pandas/tests/indexes/period/test_arithmetic.py | 9 ++++++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 7b40a56a78375..023b875f6ee3c 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -796,9 +796,8 @@ def _sub_period_array(self, other): Returns ------- - result : np.ndarray - dtype is np.int64 if there are no NaTs in self or other, - otherwise np.float64 + result : np.ndarray[object] + Array of DateOffset objects; nulls represented by NaT """ if not is_period_dtype(self): raise TypeError("cannot subtract {dtype}-dtype to {cls}" @@ -814,12 +813,11 @@ def _sub_period_array(self, other): new_values = checked_add_with_arr(self.asi8, -other.asi8, arr_mask=self._isnan, b_mask=other._isnan) - new_values = new_values + + new_values = np.array([self.freq * x for x in new_values]) if self.hasnans or other.hasnans: - # we have to convert to float to represent NaNs mask = (self._isnan) | (other._isnan) - new_values = new_values.astype(np.float64) - new_values[mask] = np.nan + new_values[mask] = NaT return new_values def _add_offset(self, offset): diff --git a/pandas/tests/indexes/period/test_arithmetic.py b/pandas/tests/indexes/period/test_arithmetic.py index 399eeed06f700..bab503451de56 100644 --- a/pandas/tests/indexes/period/test_arithmetic.py +++ b/pandas/tests/indexes/period/test_arithmetic.py @@ -277,7 +277,8 @@ def test_pi_sub_pi(self): other = pd.period_range('1/6/2000', freq='D', periods=5) result = rng - other - expected = pd.Int64Index([-5, -5, -5, -5, -5]) + off = rng.freq + expected = pd.Index([-5 * off] * 5) tm.assert_index_equal(result, expected) def test_pi_sub_pi_with_nat(self): @@ -286,7 +287,8 @@ def test_pi_sub_pi_with_nat(self): assert other[1:].equals(rng[1:]) result = rng - other - expected = pd.Float64Index([np.nan, 0, 0, 0, 0]) + off = rng.freq + expected = pd.Index([pd.NaT, 0 * off, 0 * off, 0 * off, 0 * off]) tm.assert_index_equal(result, expected) def test_pi_sub_pi_mismatched_freq(self): @@ -451,7 +453,8 @@ def test_pi_sub_isub_pi(self): rng = pd.period_range('1/1/2000', freq='D', periods=5) other = pd.period_range('1/6/2000', freq='D', periods=5) - expected = pd.Int64Index([-5, -5, -5, -5, -5]) + off = rng.freq + expected = pd.Index([-5 * off] * 5) result = rng - other tm.assert_index_equal(result, expected) From 0adf604f0b6565c3ad70f0fd0806991ad7505c64 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 5 Jun 2018 09:55:08 -0700 Subject: [PATCH 4/9] remove merge leftover --- doc/source/whatsnew/v0.23.0.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index b8cc4d249e80f..a099fb40c35a7 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -996,7 +996,6 @@ Other API Changes - :func:`DataFrame.to_dict` with ``orient='index'`` no longer casts int columns to float for a DataFrame with only int and float columns (:issue:`18580`) - A user-defined-function that is passed to :func:`Series.rolling().aggregate() `, :func:`DataFrame.rolling().aggregate() `, or its expanding cousins, will now *always* be passed a ``Series``, rather than a ``np.array``; ``.apply()`` only has the ``raw`` keyword, see :ref:`here `. This is consistent with the signatures of ``.aggregate()`` across pandas (:issue:`20584`) - Rolling and Expanding types raise ``NotImplementedError`` upon iteration (:issue:`11704`). ->>>>>>> cbec58eacd8e9cd94b7f42351b8de4559c250909 .. _whatsnew_0230.deprecations: From eb6ec2a16630b2158b1434d44d65534267e33531 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 5 Jun 2018 18:36:00 -0700 Subject: [PATCH 5/9] flesh out comments --- pandas/tests/indexes/datetimes/test_arithmetic.py | 2 +- pandas/tests/indexes/period/test_arithmetic.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pandas/tests/indexes/datetimes/test_arithmetic.py b/pandas/tests/indexes/datetimes/test_arithmetic.py index 2744e49acbe34..a0c5e988e9407 100644 --- a/pandas/tests/indexes/datetimes/test_arithmetic.py +++ b/pandas/tests/indexes/datetimes/test_arithmetic.py @@ -745,7 +745,7 @@ def test_sub_period(self, freq): @pytest.mark.parametrize('pi_freq', ['D', 'W', 'Q', 'H']) @pytest.mark.parametrize('dti_freq', [None, 'D']) def test_dti_sub_pi(self, dti_freq, pi_freq, op): - # GH#20049subtracting PeriodIndex should raise TypeError + # GH#20049 subtracting PeriodIndex should raise TypeError dti = pd.DatetimeIndex(['2011-01-01', '2011-01-02'], freq=dti_freq) pi = dti.to_period(pi_freq) with pytest.raises(TypeError): diff --git a/pandas/tests/indexes/period/test_arithmetic.py b/pandas/tests/indexes/period/test_arithmetic.py index bab503451de56..8a62c44311a84 100644 --- a/pandas/tests/indexes/period/test_arithmetic.py +++ b/pandas/tests/indexes/period/test_arithmetic.py @@ -260,12 +260,17 @@ def test_comp_nat(self, dtype): class TestPeriodIndexArithmetic(object): # --------------------------------------------------------------- # __add__/__sub__ with PeriodIndex + # PeriodIndex + other is defined for integers and timedelta-like others + # PeriodIndex - other is defined for integers, timedelta-like others, + # and PeriodIndex (with matching freq) def test_pi_add_iadd_pi_raises(self): rng = pd.period_range('1/1/2000', freq='D', periods=5) other = pd.period_range('1/6/2000', freq='D', periods=5) - # previously performed setop union, now raises TypeError (GH14164) + # An earlier implementation of PeriodIndex addition performed + # a set operation (union). This has since been changed to + # raise a TypeError. See GH#14164 and GH#13077 for historical reference. with pytest.raises(TypeError): rng + other @@ -448,8 +453,9 @@ def test_pi_sub_intlike(self, five): def test_pi_sub_isub_pi(self): # GH#20049 - # previously raised TypeError (GH#14164), before that - # performed set operation. See discussion in GH#13077 + # For historical reference see GH#14164, GH#13077. + # PeriodIndex subtraction originally performed set difference, + # then changed to raise TypeError before being implemented in GH#20049 rng = pd.period_range('1/1/2000', freq='D', periods=5) other = pd.period_range('1/6/2000', freq='D', periods=5) From e6096319e9cbf70702cc1247a5ab9c16b8576962 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Tue, 5 Jun 2018 18:37:29 -0700 Subject: [PATCH 6/9] fixup too-long line --- pandas/tests/indexes/period/test_arithmetic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/tests/indexes/period/test_arithmetic.py b/pandas/tests/indexes/period/test_arithmetic.py index 8a62c44311a84..17c5e97ecef54 100644 --- a/pandas/tests/indexes/period/test_arithmetic.py +++ b/pandas/tests/indexes/period/test_arithmetic.py @@ -270,7 +270,8 @@ def test_pi_add_iadd_pi_raises(self): # An earlier implementation of PeriodIndex addition performed # a set operation (union). This has since been changed to - # raise a TypeError. See GH#14164 and GH#13077 for historical reference. + # raise a TypeError. See GH#14164 and GH#13077 for historical + # reference. with pytest.raises(TypeError): rng + other From 59b314f8c3f5ba2455759462165321246beb44e6 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 11 Jun 2018 09:08:53 -0700 Subject: [PATCH 7/9] Fixup typo add-->subtract --- pandas/core/indexes/datetimelike.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 023b875f6ee3c..70c87b0a231c1 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -805,7 +805,7 @@ def _sub_period_array(self, other): cls=type(self).__name__)) if not len(self) == len(other): - raise ValueError("cannot add indices of unequal length") + raise ValueError("cannot subtract indices of unequal length") if self.freq != other.freq: msg = _DIFFERENT_FREQ_INDEX.format(self.freqstr, other.freqstr) raise IncompatibleFrequency(msg) From 0f6d67d208fcbc939b2e6cfe54a5701321bbc871 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Mon, 11 Jun 2018 09:23:16 -0700 Subject: [PATCH 8/9] remove redundant test --- .../tests/indexes/period/test_arithmetic.py | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/pandas/tests/indexes/period/test_arithmetic.py b/pandas/tests/indexes/period/test_arithmetic.py index 17c5e97ecef54..79f08ab490494 100644 --- a/pandas/tests/indexes/period/test_arithmetic.py +++ b/pandas/tests/indexes/period/test_arithmetic.py @@ -278,15 +278,22 @@ def test_pi_add_iadd_pi_raises(self): with pytest.raises(TypeError): rng += other - def test_pi_sub_pi(self): + def test_pi_sub_isub_pi(self): + # GH#20049 + # For historical reference see GH#14164, GH#13077. + # PeriodIndex subtraction originally performed set difference, + # then changed to raise TypeError before being implemented in GH#20049 rng = pd.period_range('1/1/2000', freq='D', periods=5) other = pd.period_range('1/6/2000', freq='D', periods=5) - result = rng - other off = rng.freq expected = pd.Index([-5 * off] * 5) + result = rng - other tm.assert_index_equal(result, expected) + rng -= other + tm.assert_index_equal(rng, expected) + def test_pi_sub_pi_with_nat(self): rng = pd.period_range('1/1/2000', freq='D', periods=5) other = rng[1:].insert(0, pd.NaT) @@ -452,22 +459,6 @@ def test_pi_sub_intlike(self, five): exp = rng + (-five) tm.assert_index_equal(result, exp) - def test_pi_sub_isub_pi(self): - # GH#20049 - # For historical reference see GH#14164, GH#13077. - # PeriodIndex subtraction originally performed set difference, - # then changed to raise TypeError before being implemented in GH#20049 - rng = pd.period_range('1/1/2000', freq='D', periods=5) - other = pd.period_range('1/6/2000', freq='D', periods=5) - - off = rng.freq - expected = pd.Index([-5 * off] * 5) - result = rng - other - tm.assert_index_equal(result, expected) - - rng -= other - tm.assert_index_equal(rng, expected) - def test_pi_sub_isub_offset(self): # offset # DateOffset From 088691785e9d8cddf73a34ac57d48ed367c7530d Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Thu, 21 Jun 2018 20:50:56 -0700 Subject: [PATCH 9/9] fixup typo --- doc/source/whatsnew/v0.24.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index ed5b6a882e9f3..80709c098036b 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -68,7 +68,7 @@ Datetimelike API Changes - For :class:`DatetimeIndex` and :class:`TimedeltaIndex` with non-``None`` ``freq`` attribute, addition or subtraction of integer-dtyped array or ``Index`` will return an object of the same class (:issue:`19959`) - :class:`DateOffset` objects are now immutable. Attempting to alter one of these will now raise ``AttributeError`` (:issue:`21341`) -- :class:`PeriodIndex` subtraction of another ``PeriodIndex`` will now return an object-dtype :class:`Index` of :class:`DateOffset` objects instead of raising a ``TypeErrorr`` (:issue:`20049`) +- :class:`PeriodIndex` subtraction of another ``PeriodIndex`` will now return an object-dtype :class:`Index` of :class:`DateOffset` objects instead of raising a ``TypeError`` (:issue:`20049`) .. _whatsnew_0240.api.other: