diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index 02e9c212b56ef..c7c487a04b2fd 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -20,6 +20,8 @@ from pandas._libs.tslibs.conversion import localize_pydatetime from pandas._libs.tslibs.offsets import shift_months +from pandas.core.indexes.datetimes import _to_m8 + from pandas import ( Timestamp, Timedelta, Period, Series, date_range, NaT, DatetimeIndex, TimedeltaIndex) @@ -61,6 +63,50 @@ def test_dt64_nat_comparison(self): class TestDatetime64SeriesComparison(object): # TODO: moved from tests.series.test_operators; needs cleanup + + @pytest.mark.parametrize('pair', [ + ([pd.Timestamp('2011-01-01'), NaT, pd.Timestamp('2011-01-03')], + [NaT, NaT, pd.Timestamp('2011-01-03')]), + + ([pd.Timedelta('1 days'), NaT, pd.Timedelta('3 days')], + [NaT, NaT, pd.Timedelta('3 days')]), + + ([pd.Period('2011-01', freq='M'), NaT, + pd.Period('2011-03', freq='M')], + [NaT, NaT, pd.Period('2011-03', freq='M')]), + + ]) + @pytest.mark.parametrize('reverse', [True, False]) + @pytest.mark.parametrize('box', [Series, pd.Index]) + @pytest.mark.parametrize('dtype', [None, object]) + def test_nat_comparisons(self, dtype, box, reverse, pair): + l, r = pair + if reverse: + # add lhs / rhs switched data + l, r = r, l + + left = Series(l, dtype=dtype) + right = box(r, dtype=dtype) + # Series, Index + + expected = Series([False, False, True]) + tm.assert_series_equal(left == right, expected) + + expected = Series([True, True, False]) + tm.assert_series_equal(left != right, expected) + + expected = Series([False, False, False]) + tm.assert_series_equal(left < right, expected) + + expected = Series([False, False, False]) + tm.assert_series_equal(left > right, expected) + + expected = Series([False, False, True]) + tm.assert_series_equal(left >= right, expected) + + expected = Series([False, False, True]) + tm.assert_series_equal(left <= right, expected) + def test_comparison_invalid(self, box_with_array): # GH#4968 # invalid date/int comparisons @@ -272,8 +318,46 @@ def test_dt64arr_timestamp_equality(self, box_with_array): expected = tm.box_expected([False, False], xbox) tm.assert_equal(result, expected) + @pytest.mark.parametrize('op', [operator.eq, operator.ne, + operator.gt, operator.ge, + operator.lt, operator.le]) + def test_comparison_tzawareness_compat(self, op): + # GH#18162 + dr = pd.date_range('2016-01-01', periods=6) + dz = dr.tz_localize('US/Pacific') + + # Check that there isn't a problem aware-aware and naive-naive do not + # raise + naive_series = Series(dr) + aware_series = Series(dz) + with pytest.raises(TypeError): + op(dz, naive_series) + with pytest.raises(TypeError): + op(dr, aware_series) + + # TODO: implement _assert_tzawareness_compat for the reverse + # comparison with the Series on the left-hand side + class TestDatetimeIndexComparisons(object): + + # TODO: moved from tests.indexes.test_base; parametrize and de-duplicate + @pytest.mark.parametrize("op", [ + operator.eq, operator.ne, operator.gt, operator.lt, + operator.ge, operator.le + ]) + def test_comparators(self, op): + index = tm.makeDateIndex(100) + element = index[len(index) // 2] + element = _to_m8(element) + + arr = np.array(index) + arr_result = op(arr, element) + index_result = op(index, element) + + assert isinstance(index_result, np.ndarray) + tm.assert_numpy_array_equal(arr_result, index_result) + @pytest.mark.parametrize('other', [datetime(2016, 1, 1), Timestamp('2016-01-01'), np.datetime64('2016-01-01')]) @@ -1450,6 +1534,42 @@ def test_datetimeindex_sub_datetimeindex_overflow(self): class TestTimestampSeriesArithmetic(object): + def test_empty_series_add_sub(self): + # GH#13844 + a = Series(dtype='M8[ns]') + b = Series(dtype='m8[ns]') + tm.assert_series_equal(a, a + b) + tm.assert_series_equal(a, a - b) + tm.assert_series_equal(a, b + a) + with pytest.raises(TypeError): + b - a + + def test_operators_datetimelike(self): + + # ## timedelta64 ### + td1 = Series([timedelta(minutes=5, seconds=3)] * 3) + td1.iloc[2] = np.nan + + # ## datetime64 ### + dt1 = Series([pd.Timestamp('20111230'), pd.Timestamp('20120101'), + pd.Timestamp('20120103')]) + dt1.iloc[2] = np.nan + dt2 = Series([pd.Timestamp('20111231'), pd.Timestamp('20120102'), + pd.Timestamp('20120104')]) + dt1 - dt2 + dt2 - dt1 + + # ## datetime64 with timetimedelta ### + dt1 + td1 + td1 + dt1 + dt1 - td1 + # TODO: Decide if this ought to work. + # td1 - dt1 + + # ## timetimedelta with datetime64 ### + td1 + dt1 + dt1 + td1 + def test_dt64ser_sub_datetime_dtype(self): ts = Timestamp(datetime(1993, 1, 7, 13, 30, 00)) dt = datetime(1993, 6, 22, 13, 30) diff --git a/pandas/tests/arithmetic/test_numeric.py b/pandas/tests/arithmetic/test_numeric.py index 2d26959c65632..c603485f6f076 100644 --- a/pandas/tests/arithmetic/test_numeric.py +++ b/pandas/tests/arithmetic/test_numeric.py @@ -3,6 +3,7 @@ # behave identically. # Specifically for numeric dtypes from decimal import Decimal +from itertools import combinations import operator import pytest @@ -846,11 +847,15 @@ def check(series, other): class TestUFuncCompat(object): @pytest.mark.parametrize('holder', [pd.Int64Index, pd.UInt64Index, - pd.Float64Index, pd.Series]) + pd.Float64Index, pd.RangeIndex, + pd.Series]) def test_ufunc_compat(self, holder): box = pd.Series if holder is pd.Series else pd.Index - idx = holder(np.arange(5, dtype='int64')) + if holder is pd.RangeIndex: + idx = pd.RangeIndex(0, 5) + else: + idx = holder(np.arange(5, dtype='int64')) result = np.sin(idx) expected = box(np.sin(np.arange(5, dtype='int64'))) tm.assert_equal(result, expected) @@ -940,3 +945,117 @@ def test_operators_reverse_object(self, op): result = op(1., arr) expected = op(1., arr.astype(float)) tm.assert_series_equal(result.astype(float), expected) + + +class TestNumericArithmeticUnsorted(object): + # Tests in this class have been moved from type-specific test modules + # but not yet sorted, parametrized, and de-duplicated + + def check_binop(self, ops, scalars, idxs): + for op in ops: + for a, b in combinations(idxs, 2): + result = op(a, b) + expected = op(pd.Int64Index(a), pd.Int64Index(b)) + tm.assert_index_equal(result, expected) + for idx in idxs: + for scalar in scalars: + result = op(idx, scalar) + expected = op(pd.Int64Index(idx), scalar) + tm.assert_index_equal(result, expected) + + def test_binops(self): + ops = [operator.add, operator.sub, operator.mul, operator.floordiv, + operator.truediv] + scalars = [-1, 1, 2] + idxs = [pd.RangeIndex(0, 10, 1), pd.RangeIndex(0, 20, 2), + pd.RangeIndex(-10, 10, 2), pd.RangeIndex(5, -5, -1)] + self.check_binop(ops, scalars, idxs) + + def test_binops_pow(self): + # later versions of numpy don't allow powers of negative integers + # so test separately + # https://github.com/numpy/numpy/pull/8127 + ops = [pow] + scalars = [1, 2] + idxs = [pd.RangeIndex(0, 10, 1), pd.RangeIndex(0, 20, 2)] + self.check_binop(ops, scalars, idxs) + + # TODO: mod, divmod? + @pytest.mark.parametrize('op', [operator.add, operator.sub, + operator.mul, operator.floordiv, + operator.truediv, operator.pow]) + def test_arithmetic_with_frame_or_series(self, op): + # check that we return NotImplemented when operating with Series + # or DataFrame + index = pd.RangeIndex(5) + other = pd.Series(np.random.randn(5)) + + expected = op(pd.Series(index), other) + result = op(index, other) + tm.assert_series_equal(result, expected) + + other = pd.DataFrame(np.random.randn(2, 5)) + expected = op(pd.DataFrame([index, index]), other) + result = op(index, other) + tm.assert_frame_equal(result, expected) + + def test_numeric_compat2(self): + # validate that we are handling the RangeIndex overrides to numeric ops + # and returning RangeIndex where possible + + idx = pd.RangeIndex(0, 10, 2) + + result = idx * 2 + expected = pd.RangeIndex(0, 20, 4) + tm.assert_index_equal(result, expected, exact=True) + + result = idx + 2 + expected = pd.RangeIndex(2, 12, 2) + tm.assert_index_equal(result, expected, exact=True) + + result = idx - 2 + expected = pd.RangeIndex(-2, 8, 2) + tm.assert_index_equal(result, expected, exact=True) + + # truediv under PY3 + result = idx / 2 + + if PY3: + expected = pd.RangeIndex(0, 5, 1).astype('float64') + else: + expected = pd.RangeIndex(0, 5, 1) + tm.assert_index_equal(result, expected, exact=True) + + result = idx / 4 + expected = pd.RangeIndex(0, 10, 2) / 4 + tm.assert_index_equal(result, expected, exact=True) + + result = idx // 1 + expected = idx + tm.assert_index_equal(result, expected, exact=True) + + # __mul__ + result = idx * idx + expected = Index(idx.values * idx.values) + tm.assert_index_equal(result, expected, exact=True) + + # __pow__ + idx = pd.RangeIndex(0, 1000, 2) + result = idx ** 2 + expected = idx._int64index ** 2 + tm.assert_index_equal(Index(result.values), expected, exact=True) + + # __floordiv__ + cases_exact = [ + (pd.RangeIndex(0, 1000, 2), 2, pd.RangeIndex(0, 500, 1)), + (pd.RangeIndex(-99, -201, -3), -3, pd.RangeIndex(33, 67, 1)), + (pd.RangeIndex(0, 1000, 1), 2, + pd.RangeIndex(0, 1000, 1)._int64index // 2), + (pd.RangeIndex(0, 100, 1), 2.0, + pd.RangeIndex(0, 100, 1)._int64index // 2.0), + (pd.RangeIndex(0), 50, pd.RangeIndex(0)), + (pd.RangeIndex(2, 4, 2), 3, pd.RangeIndex(0, 1, 1)), + (pd.RangeIndex(-5, -10, -6), 4, pd.RangeIndex(-2, -1, 1)), + (pd.RangeIndex(-100, -200, 3), 2, pd.RangeIndex(0))] + for idx, div, expected in cases_exact: + tm.assert_index_equal(idx // div, expected, exact=True) diff --git a/pandas/tests/arithmetic/test_object.py b/pandas/tests/arithmetic/test_object.py index da5055cc7b737..e9a3f4accc486 100644 --- a/pandas/tests/arithmetic/test_object.py +++ b/pandas/tests/arithmetic/test_object.py @@ -73,6 +73,21 @@ def test_more_na_comparisons(self, dtype): class TestArithmetic(object): + # TODO: parametrize + def test_pow_ops_object(self): + # GH#22922 + # pow is weird with masking & 1, so testing here + a = Series([1, np.nan, 1, np.nan], dtype=object) + b = Series([1, np.nan, np.nan, 1], dtype=object) + result = a ** b + expected = Series(a.values ** b.values, dtype=object) + tm.assert_series_equal(result, expected) + + result = b ** a + expected = Series(b.values ** a.values, dtype=object) + + tm.assert_series_equal(result, expected) + @pytest.mark.parametrize("op", [operator.add, ops.radd]) @pytest.mark.parametrize("other", ["category", "Int64"]) def test_add_extension_scalar(self, other, box, op): diff --git a/pandas/tests/arithmetic/test_period.py b/pandas/tests/arithmetic/test_period.py index 6b722f72fd2a8..6288e4ec26e1e 100644 --- a/pandas/tests/arithmetic/test_period.py +++ b/pandas/tests/arithmetic/test_period.py @@ -22,6 +22,15 @@ # Comparisons class TestPeriodIndexComparisons(object): + + @pytest.mark.parametrize("other", ["2017", 2017]) + def test_eq(self, other): + idx = PeriodIndex(['2017', '2017', '2018'], freq="D") + expected = np.array([True, True, False]) + result = idx == other + + tm.assert_numpy_array_equal(result, expected) + def test_pi_cmp_period(self): idx = period_range('2007-01', periods=20, freq='M') @@ -277,6 +286,99 @@ def test_cmp_series_period_series_mixed_freq(self): tm.assert_series_equal(base <= ser, exp) +class TestPeriodIndexSeriesComparisonConsistency(object): + """ Test PeriodIndex and Period Series Ops consistency """ + # TODO: needs parametrization+de-duplication + + def _check(self, values, func, expected): + # Test PeriodIndex and Period Series Ops consistency + + idx = pd.PeriodIndex(values) + result = func(idx) + + # check that we don't pass an unwanted type to tm.assert_equal + assert isinstance(expected, (pd.Index, np.ndarray)) + tm.assert_equal(result, expected) + + s = pd.Series(values) + result = func(s) + + exp = pd.Series(expected, name=values.name) + tm.assert_series_equal(result, exp) + + def test_pi_comp_period(self): + idx = PeriodIndex(['2011-01', '2011-02', '2011-03', + '2011-04'], freq='M', name='idx') + + f = lambda x: x == pd.Period('2011-03', freq='M') + exp = np.array([False, False, True, False], dtype=np.bool) + self._check(idx, f, exp) + f = lambda x: pd.Period('2011-03', freq='M') == x + self._check(idx, f, exp) + + f = lambda x: x != pd.Period('2011-03', freq='M') + exp = np.array([True, True, False, True], dtype=np.bool) + self._check(idx, f, exp) + f = lambda x: pd.Period('2011-03', freq='M') != x + self._check(idx, f, exp) + + f = lambda x: pd.Period('2011-03', freq='M') >= x + exp = np.array([True, True, True, False], dtype=np.bool) + self._check(idx, f, exp) + + f = lambda x: x > pd.Period('2011-03', freq='M') + exp = np.array([False, False, False, True], dtype=np.bool) + self._check(idx, f, exp) + + f = lambda x: pd.Period('2011-03', freq='M') >= x + exp = np.array([True, True, True, False], dtype=np.bool) + self._check(idx, f, exp) + + def test_pi_comp_period_nat(self): + idx = PeriodIndex(['2011-01', 'NaT', '2011-03', + '2011-04'], freq='M', name='idx') + + f = lambda x: x == pd.Period('2011-03', freq='M') + exp = np.array([False, False, True, False], dtype=np.bool) + self._check(idx, f, exp) + f = lambda x: pd.Period('2011-03', freq='M') == x + self._check(idx, f, exp) + + f = lambda x: x == pd.NaT + exp = np.array([False, False, False, False], dtype=np.bool) + self._check(idx, f, exp) + f = lambda x: pd.NaT == x + self._check(idx, f, exp) + + f = lambda x: x != pd.Period('2011-03', freq='M') + exp = np.array([True, True, False, True], dtype=np.bool) + self._check(idx, f, exp) + f = lambda x: pd.Period('2011-03', freq='M') != x + self._check(idx, f, exp) + + f = lambda x: x != pd.NaT + exp = np.array([True, True, True, True], dtype=np.bool) + self._check(idx, f, exp) + f = lambda x: pd.NaT != x + self._check(idx, f, exp) + + f = lambda x: pd.Period('2011-03', freq='M') >= x + exp = np.array([True, False, True, False], dtype=np.bool) + self._check(idx, f, exp) + + f = lambda x: x < pd.Period('2011-03', freq='M') + exp = np.array([True, False, False, False], dtype=np.bool) + self._check(idx, f, exp) + + f = lambda x: x > pd.NaT + exp = np.array([False, False, False, False], dtype=np.bool) + self._check(idx, f, exp) + + f = lambda x: pd.NaT >= x + exp = np.array([False, False, False, False], dtype=np.bool) + self._check(idx, f, exp) + + # ------------------------------------------------------------------ # Arithmetic diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index 5404d3f5f1915..f672baed944fc 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -158,6 +158,259 @@ def test_comparisons_coverage(self): # ------------------------------------------------------------------ # Timedelta64[ns] dtype Arithmetic Operations +class TestTimedelta64ArithmeticUnsorted(object): + # Tests moved from type-specific test files but not + # yet sorted/parametrized/de-duplicated + + def test_ufunc_coercions(self): + # normal ops are also tested in tseries/test_timedeltas.py + idx = TimedeltaIndex(['2H', '4H', '6H', '8H', '10H'], + freq='2H', name='x') + + for result in [idx * 2, np.multiply(idx, 2)]: + assert isinstance(result, TimedeltaIndex) + exp = TimedeltaIndex(['4H', '8H', '12H', '16H', '20H'], + freq='4H', name='x') + tm.assert_index_equal(result, exp) + assert result.freq == '4H' + + for result in [idx / 2, np.divide(idx, 2)]: + assert isinstance(result, TimedeltaIndex) + exp = TimedeltaIndex(['1H', '2H', '3H', '4H', '5H'], + freq='H', name='x') + tm.assert_index_equal(result, exp) + assert result.freq == 'H' + + idx = TimedeltaIndex(['2H', '4H', '6H', '8H', '10H'], + freq='2H', name='x') + for result in [-idx, np.negative(idx)]: + assert isinstance(result, TimedeltaIndex) + exp = TimedeltaIndex(['-2H', '-4H', '-6H', '-8H', '-10H'], + freq='-2H', name='x') + tm.assert_index_equal(result, exp) + assert result.freq == '-2H' + + idx = TimedeltaIndex(['-2H', '-1H', '0H', '1H', '2H'], + freq='H', name='x') + for result in [abs(idx), np.absolute(idx)]: + assert isinstance(result, TimedeltaIndex) + exp = TimedeltaIndex(['2H', '1H', '0H', '1H', '2H'], + freq=None, name='x') + tm.assert_index_equal(result, exp) + assert result.freq is None + + def test_subtraction_ops(self): + # with datetimes/timedelta and tdi/dti + tdi = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo') + dti = pd.date_range('20130101', periods=3, name='bar') + td = Timedelta('1 days') + dt = Timestamp('20130101') + + pytest.raises(TypeError, lambda: tdi - dt) + pytest.raises(TypeError, lambda: tdi - dti) + pytest.raises(TypeError, lambda: td - dt) + pytest.raises(TypeError, lambda: td - dti) + + result = dt - dti + expected = TimedeltaIndex(['0 days', '-1 days', '-2 days'], name='bar') + tm.assert_index_equal(result, expected) + + result = dti - dt + expected = TimedeltaIndex(['0 days', '1 days', '2 days'], name='bar') + tm.assert_index_equal(result, expected) + + result = tdi - td + expected = TimedeltaIndex(['0 days', pd.NaT, '1 days'], name='foo') + tm.assert_index_equal(result, expected, check_names=False) + + result = td - tdi + expected = TimedeltaIndex(['0 days', pd.NaT, '-1 days'], name='foo') + tm.assert_index_equal(result, expected, check_names=False) + + result = dti - td + expected = DatetimeIndex( + ['20121231', '20130101', '20130102'], name='bar') + tm.assert_index_equal(result, expected, check_names=False) + + result = dt - tdi + expected = DatetimeIndex(['20121231', pd.NaT, '20121230'], name='foo') + tm.assert_index_equal(result, expected) + + def test_subtraction_ops_with_tz(self): + + # check that dt/dti subtraction ops with tz are validated + dti = pd.date_range('20130101', periods=3) + ts = Timestamp('20130101') + dt = ts.to_pydatetime() + dti_tz = pd.date_range('20130101', periods=3).tz_localize('US/Eastern') + ts_tz = Timestamp('20130101').tz_localize('US/Eastern') + ts_tz2 = Timestamp('20130101').tz_localize('CET') + dt_tz = ts_tz.to_pydatetime() + td = Timedelta('1 days') + + def _check(result, expected): + assert result == expected + assert isinstance(result, Timedelta) + + # scalars + result = ts - ts + expected = Timedelta('0 days') + _check(result, expected) + + result = dt_tz - ts_tz + expected = Timedelta('0 days') + _check(result, expected) + + result = ts_tz - dt_tz + expected = Timedelta('0 days') + _check(result, expected) + + # tz mismatches + pytest.raises(TypeError, lambda: dt_tz - ts) + pytest.raises(TypeError, lambda: dt_tz - dt) + pytest.raises(TypeError, lambda: dt_tz - ts_tz2) + pytest.raises(TypeError, lambda: dt - dt_tz) + pytest.raises(TypeError, lambda: ts - dt_tz) + pytest.raises(TypeError, lambda: ts_tz2 - ts) + pytest.raises(TypeError, lambda: ts_tz2 - dt) + pytest.raises(TypeError, lambda: ts_tz - ts_tz2) + + # with dti + pytest.raises(TypeError, lambda: dti - ts_tz) + pytest.raises(TypeError, lambda: dti_tz - ts) + pytest.raises(TypeError, lambda: dti_tz - ts_tz2) + + result = dti_tz - dt_tz + expected = TimedeltaIndex(['0 days', '1 days', '2 days']) + tm.assert_index_equal(result, expected) + + result = dt_tz - dti_tz + expected = TimedeltaIndex(['0 days', '-1 days', '-2 days']) + tm.assert_index_equal(result, expected) + + result = dti_tz - ts_tz + expected = TimedeltaIndex(['0 days', '1 days', '2 days']) + tm.assert_index_equal(result, expected) + + result = ts_tz - dti_tz + expected = TimedeltaIndex(['0 days', '-1 days', '-2 days']) + tm.assert_index_equal(result, expected) + + result = td - td + expected = Timedelta('0 days') + _check(result, expected) + + result = dti_tz - td + expected = DatetimeIndex( + ['20121231', '20130101', '20130102'], tz='US/Eastern') + tm.assert_index_equal(result, expected) + + def test_dti_tdi_numeric_ops(self): + # These are normally union/diff set-like ops + tdi = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo') + dti = pd.date_range('20130101', periods=3, name='bar') + + # TODO(wesm): unused? + # td = Timedelta('1 days') + # dt = Timestamp('20130101') + + result = tdi - tdi + expected = TimedeltaIndex(['0 days', pd.NaT, '0 days'], name='foo') + tm.assert_index_equal(result, expected) + + result = tdi + tdi + expected = TimedeltaIndex(['2 days', pd.NaT, '4 days'], name='foo') + tm.assert_index_equal(result, expected) + + result = dti - tdi # name will be reset + expected = DatetimeIndex(['20121231', pd.NaT, '20130101']) + tm.assert_index_equal(result, expected) + + def test_addition_ops(self): + # with datetimes/timedelta and tdi/dti + tdi = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo') + dti = pd.date_range('20130101', periods=3, name='bar') + td = Timedelta('1 days') + dt = Timestamp('20130101') + + result = tdi + dt + expected = DatetimeIndex(['20130102', pd.NaT, '20130103'], name='foo') + tm.assert_index_equal(result, expected) + + result = dt + tdi + expected = DatetimeIndex(['20130102', pd.NaT, '20130103'], name='foo') + tm.assert_index_equal(result, expected) + + result = td + tdi + expected = TimedeltaIndex(['2 days', pd.NaT, '3 days'], name='foo') + tm.assert_index_equal(result, expected) + + result = tdi + td + expected = TimedeltaIndex(['2 days', pd.NaT, '3 days'], name='foo') + tm.assert_index_equal(result, expected) + + # unequal length + pytest.raises(ValueError, lambda: tdi + dti[0:1]) + pytest.raises(ValueError, lambda: tdi[0:1] + dti) + + # random indexes + with pytest.raises(NullFrequencyError): + tdi + pd.Int64Index([1, 2, 3]) + + # this is a union! + # pytest.raises(TypeError, lambda : Int64Index([1,2,3]) + tdi) + + result = tdi + dti # name will be reset + expected = DatetimeIndex(['20130102', pd.NaT, '20130105']) + tm.assert_index_equal(result, expected) + + result = dti + tdi # name will be reset + expected = DatetimeIndex(['20130102', pd.NaT, '20130105']) + tm.assert_index_equal(result, expected) + + result = dt + td + expected = Timestamp('20130102') + assert result == expected + + result = td + dt + expected = Timestamp('20130102') + assert result == expected + + # TODO: Needs more informative name, probably split up into + # more targeted tests + @pytest.mark.parametrize('freq', ['D', 'B']) + def test_timedelta(self, freq): + index = pd.date_range('1/1/2000', periods=50, freq=freq) + + shifted = index + timedelta(1) + back = shifted + timedelta(-1) + tm.assert_index_equal(index, back) + + if freq == 'D': + expected = pd.tseries.offsets.Day(1) + assert index.freq == expected + assert shifted.freq == expected + assert back.freq == expected + else: # freq == 'B' + assert index.freq == pd.tseries.offsets.BusinessDay(1) + assert shifted.freq is None + assert back.freq == pd.tseries.offsets.BusinessDay(1) + + result = index - timedelta(1) + expected = index + timedelta(-1) + tm.assert_index_equal(result, expected) + + # GH#4134, buggy with timedeltas + rng = pd.date_range('2013', '2014') + s = Series(rng) + result1 = rng - pd.offsets.Hour(1) + result2 = DatetimeIndex(s - np.timedelta64(100000000)) + result3 = rng - np.timedelta64(100000000) + result4 = DatetimeIndex(s - pd.offsets.Hour(1)) + tm.assert_index_equal(result1, result4) + tm.assert_index_equal(result2, result3) + + class TestAddSubNaTMasking(object): # TODO: parametrize over boxes @@ -221,6 +474,118 @@ def test_tdi_add_overflow(self): class TestTimedeltaArraylikeAddSubOps(object): # Tests for timedelta64[ns] __add__, __sub__, __radd__, __rsub__ + # TODO: moved from frame tests; needs parametrization/de-duplication + def test_td64_df_add_int_frame(self): + # GH#22696 Check that we don't dispatch to numpy implementation, + # which treats int64 as m8[ns] + tdi = pd.timedelta_range('1', periods=3) + df = tdi.to_frame() + other = pd.DataFrame([1, 2, 3], index=tdi) # indexed like `df` + with pytest.raises(TypeError): + df + other + with pytest.raises(TypeError): + other + df + with pytest.raises(TypeError): + df - other + with pytest.raises(TypeError): + other - df + + # TODO: moved from tests.indexes.timedeltas.test_arithmetic; needs + # parametrization+de-duplication + def test_timedelta_ops_with_missing_values(self): + # setup + s1 = pd.to_timedelta(Series(['00:00:01'])) + s2 = pd.to_timedelta(Series(['00:00:02'])) + with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): + # Passing datetime64-dtype data to TimedeltaIndex is deprecated + sn = pd.to_timedelta(Series([pd.NaT])) + + df1 = pd.DataFrame(['00:00:01']).apply(pd.to_timedelta) + df2 = pd.DataFrame(['00:00:02']).apply(pd.to_timedelta) + with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): + # Passing datetime64-dtype data to TimedeltaIndex is deprecated + dfn = pd.DataFrame([pd.NaT]).apply(pd.to_timedelta) + + scalar1 = pd.to_timedelta('00:00:01') + scalar2 = pd.to_timedelta('00:00:02') + timedelta_NaT = pd.to_timedelta('NaT') + + actual = scalar1 + scalar1 + assert actual == scalar2 + actual = scalar2 - scalar1 + assert actual == scalar1 + + actual = s1 + s1 + tm.assert_series_equal(actual, s2) + actual = s2 - s1 + tm.assert_series_equal(actual, s1) + + actual = s1 + scalar1 + tm.assert_series_equal(actual, s2) + actual = scalar1 + s1 + tm.assert_series_equal(actual, s2) + actual = s2 - scalar1 + tm.assert_series_equal(actual, s1) + actual = -scalar1 + s2 + tm.assert_series_equal(actual, s1) + + actual = s1 + timedelta_NaT + tm.assert_series_equal(actual, sn) + actual = timedelta_NaT + s1 + tm.assert_series_equal(actual, sn) + actual = s1 - timedelta_NaT + tm.assert_series_equal(actual, sn) + actual = -timedelta_NaT + s1 + tm.assert_series_equal(actual, sn) + + with pytest.raises(TypeError): + s1 + np.nan + with pytest.raises(TypeError): + np.nan + s1 + with pytest.raises(TypeError): + s1 - np.nan + with pytest.raises(TypeError): + -np.nan + s1 + + actual = s1 + pd.NaT + tm.assert_series_equal(actual, sn) + actual = s2 - pd.NaT + tm.assert_series_equal(actual, sn) + + actual = s1 + df1 + tm.assert_frame_equal(actual, df2) + actual = s2 - df1 + tm.assert_frame_equal(actual, df1) + actual = df1 + s1 + tm.assert_frame_equal(actual, df2) + actual = df2 - s1 + tm.assert_frame_equal(actual, df1) + + actual = df1 + df1 + tm.assert_frame_equal(actual, df2) + actual = df2 - df1 + tm.assert_frame_equal(actual, df1) + + actual = df1 + scalar1 + tm.assert_frame_equal(actual, df2) + actual = df2 - scalar1 + tm.assert_frame_equal(actual, df1) + + actual = df1 + timedelta_NaT + tm.assert_frame_equal(actual, dfn) + actual = df1 - timedelta_NaT + tm.assert_frame_equal(actual, dfn) + + with pytest.raises(TypeError): + df1 + np.nan + with pytest.raises(TypeError): + df1 - np.nan + + actual = df1 + pd.NaT # NaT is datetime, not timedelta + tm.assert_frame_equal(actual, dfn) + actual = df1 - pd.NaT + tm.assert_frame_equal(actual, dfn) + # TODO: moved from tests.series.test_operators, needs splitting, cleanup, # de-duplication, box-parametrization... def test_operators_timedelta64(self): diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index 3cdb223a813b7..e67f6d4ee369e 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -557,21 +557,6 @@ def test_df_bool_mul_int(self): kinds = result.dtypes.apply(lambda x: x.kind) assert (kinds == 'i').all() - def test_td64_df_add_int_frame(self): - # GH#22696 Check that we don't dispatch to numpy implementation, - # which treats int64 as m8[ns] - tdi = pd.timedelta_range('1', periods=3) - df = tdi.to_frame() - other = pd.DataFrame([1, 2, 3], index=tdi) # indexed like `df` - with pytest.raises(TypeError): - df + other - with pytest.raises(TypeError): - other + df - with pytest.raises(TypeError): - df - other - with pytest.raises(TypeError): - other - df - def test_arith_mixed(self): left = pd.DataFrame({'A': ['a', 'b', 'c'], diff --git a/pandas/tests/indexes/period/test_ops.py b/pandas/tests/indexes/period/test_ops.py index 01347db4db3b2..6648be5d2818a 100644 --- a/pandas/tests/indexes/period/test_ops.py +++ b/pandas/tests/indexes/period/test_ops.py @@ -402,103 +402,3 @@ def test_freq_setter_deprecated(self): # warning for setter with tm.assert_produces_warning(FutureWarning): idx.freq = pd.offsets.Day() - - -class TestPeriodIndexSeriesMethods(object): - """ Test PeriodIndex and Period Series Ops consistency """ - - def _check(self, values, func, expected): - idx = pd.PeriodIndex(values) - result = func(idx) - if isinstance(expected, pd.Index): - tm.assert_index_equal(result, expected) - else: - # comp op results in bool - tm.assert_numpy_array_equal(result, expected) - - s = pd.Series(values) - result = func(s) - - exp = pd.Series(expected, name=values.name) - tm.assert_series_equal(result, exp) - - def test_pi_comp_period(self): - idx = PeriodIndex(['2011-01', '2011-02', '2011-03', - '2011-04'], freq='M', name='idx') - - f = lambda x: x == pd.Period('2011-03', freq='M') - exp = np.array([False, False, True, False], dtype=np.bool) - self._check(idx, f, exp) - f = lambda x: pd.Period('2011-03', freq='M') == x - self._check(idx, f, exp) - - f = lambda x: x != pd.Period('2011-03', freq='M') - exp = np.array([True, True, False, True], dtype=np.bool) - self._check(idx, f, exp) - f = lambda x: pd.Period('2011-03', freq='M') != x - self._check(idx, f, exp) - - f = lambda x: pd.Period('2011-03', freq='M') >= x - exp = np.array([True, True, True, False], dtype=np.bool) - self._check(idx, f, exp) - - f = lambda x: x > pd.Period('2011-03', freq='M') - exp = np.array([False, False, False, True], dtype=np.bool) - self._check(idx, f, exp) - - f = lambda x: pd.Period('2011-03', freq='M') >= x - exp = np.array([True, True, True, False], dtype=np.bool) - self._check(idx, f, exp) - - def test_pi_comp_period_nat(self): - idx = PeriodIndex(['2011-01', 'NaT', '2011-03', - '2011-04'], freq='M', name='idx') - - f = lambda x: x == pd.Period('2011-03', freq='M') - exp = np.array([False, False, True, False], dtype=np.bool) - self._check(idx, f, exp) - f = lambda x: pd.Period('2011-03', freq='M') == x - self._check(idx, f, exp) - - f = lambda x: x == NaT - exp = np.array([False, False, False, False], dtype=np.bool) - self._check(idx, f, exp) - f = lambda x: NaT == x - self._check(idx, f, exp) - - f = lambda x: x != pd.Period('2011-03', freq='M') - exp = np.array([True, True, False, True], dtype=np.bool) - self._check(idx, f, exp) - f = lambda x: pd.Period('2011-03', freq='M') != x - self._check(idx, f, exp) - - f = lambda x: x != NaT - exp = np.array([True, True, True, True], dtype=np.bool) - self._check(idx, f, exp) - f = lambda x: NaT != x - self._check(idx, f, exp) - - f = lambda x: pd.Period('2011-03', freq='M') >= x - exp = np.array([True, False, True, False], dtype=np.bool) - self._check(idx, f, exp) - - f = lambda x: x < pd.Period('2011-03', freq='M') - exp = np.array([True, False, False, False], dtype=np.bool) - self._check(idx, f, exp) - - f = lambda x: x > NaT - exp = np.array([False, False, False, False], dtype=np.bool) - self._check(idx, f, exp) - - f = lambda x: NaT >= x - exp = np.array([False, False, False, False], dtype=np.bool) - self._check(idx, f, exp) - - -@pytest.mark.parametrize("other", ["2017", 2017]) -def test_eq(other): - idx = pd.PeriodIndex(['2017', '2017', '2018'], freq="D") - expected = np.array([True, True, False]) - result = idx == other - - tm.assert_numpy_array_equal(result, expected) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 2580a47e8fdd3..28e4ad9c9f88c 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import math -import operator from collections import defaultdict from datetime import datetime, timedelta from decimal import Decimal @@ -28,7 +27,6 @@ from pandas.core.dtypes.generic import ABCIndex from pandas.core.index import _get_combined_index, ensure_index_from_sequences from pandas.core.indexes.api import Index, MultiIndex -from pandas.core.indexes.datetimes import _to_m8 from pandas.tests.indexes.common import Base from pandas.util.testing import assert_almost_equal from pandas.core.sorting import safe_sort @@ -624,22 +622,6 @@ def test_nanosecond_index_access(self): '0000', 'ns') assert first_value == x[Timestamp(expected_ts)] - @pytest.mark.parametrize("op", [ - operator.eq, operator.ne, operator.gt, operator.lt, - operator.ge, operator.le - ]) - def test_comparators(self, op): - index = self.dateIndex - element = index[len(index) // 2] - element = _to_m8(element) - - arr = np.array(index) - arr_result = op(arr, element) - index_result = op(index, element) - - assert isinstance(index_result, np.ndarray) - tm.assert_numpy_array_equal(arr_result, index_result) - def test_booleanindex(self): boolIndex = np.repeat(True, len(self.strIndex)).astype(bool) boolIndex[5:30:2] = False @@ -2475,26 +2457,6 @@ def test_intersect_str_dates(self): expected = Index([], dtype=object) tm.assert_index_equal(result, expected) - @pytest.mark.parametrize('op', [operator.eq, operator.ne, - operator.gt, operator.ge, - operator.lt, operator.le]) - def test_comparison_tzawareness_compat(self, op): - # GH#18162 - dr = pd.date_range('2016-01-01', periods=6) - dz = dr.tz_localize('US/Pacific') - - # Check that there isn't a problem aware-aware and naive-naive do not - # raise - naive_series = Series(dr) - aware_series = Series(dz) - with pytest.raises(TypeError): - op(dz, naive_series) - with pytest.raises(TypeError): - op(dr, aware_series) - - # TODO: implement _assert_tzawareness_compat for the reverse - # comparison with the Series on the left-hand side - class TestIndexUtils(object): diff --git a/pandas/tests/indexes/test_range.py b/pandas/tests/indexes/test_range.py index 90aa7602c2b62..5dbec9490a115 100644 --- a/pandas/tests/indexes/test_range.py +++ b/pandas/tests/indexes/test_range.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- from datetime import datetime -from itertools import combinations -import operator import numpy as np import pytest @@ -28,40 +26,11 @@ def setup_method(self, method): def create_index(self): return RangeIndex(5) - def check_binop(self, ops, scalars, idxs): - for op in ops: - for a, b in combinations(idxs, 2): - result = op(a, b) - expected = op(Int64Index(a), Int64Index(b)) - tm.assert_index_equal(result, expected) - for idx in idxs: - for scalar in scalars: - result = op(idx, scalar) - expected = op(Int64Index(idx), scalar) - tm.assert_index_equal(result, expected) - def test_can_hold_identifiers(self): idx = self.create_index() key = idx[0] assert idx._can_hold_identifiers_and_holds_name(key) is False - def test_binops(self): - ops = [operator.add, operator.sub, operator.mul, operator.floordiv, - operator.truediv] - scalars = [-1, 1, 2] - idxs = [RangeIndex(0, 10, 1), RangeIndex(0, 20, 2), - RangeIndex(-10, 10, 2), RangeIndex(5, -5, -1)] - self.check_binop(ops, scalars, idxs) - - def test_binops_pow(self): - # later versions of numpy don't allow powers of negative integers - # so test separately - # https://github.com/numpy/numpy/pull/8127 - ops = [pow] - scalars = [1, 2] - idxs = [RangeIndex(0, 10, 1), RangeIndex(0, 20, 2)] - self.check_binop(ops, scalars, idxs) - def test_too_many_names(self): with pytest.raises(ValueError, match="^Length"): self.index.names = ["roger", "harold"] @@ -88,10 +57,6 @@ def test_constructor(self): assert index._step == 2 tm.assert_index_equal(Index(expected), index) - msg = "RangeIndex\\(\\.\\.\\.\\) must be called with integers" - with pytest.raises(TypeError, match=msg): - RangeIndex() - for index in [RangeIndex(0), RangeIndex(start=0), RangeIndex(stop=0), RangeIndex(0, 0)]: expected = np.empty(0, dtype=np.int64) @@ -101,9 +66,6 @@ def test_constructor(self): assert index._step == 1 tm.assert_index_equal(Index(expected), index) - with pytest.raises(TypeError, match=msg): - RangeIndex(name='Foo') - for index in [RangeIndex(0, name='Foo'), RangeIndex(start=0, name='Foo'), RangeIndex(stop=0, name='Foo'), @@ -112,13 +74,23 @@ def test_constructor(self): assert index.name == 'Foo' # we don't allow on a bare Index - pytest.raises(TypeError, lambda: Index(0, 1000)) + with pytest.raises(TypeError): + Index(0, 1000) + + def test_constructor_invalid_args(self): + msg = "RangeIndex\\(\\.\\.\\.\\) must be called with integers" + with pytest.raises(TypeError, match=msg): + RangeIndex() + + with pytest.raises(TypeError, match=msg): + RangeIndex(name='Foo') # invalid args for i in [Index(['a', 'b']), Series(['a', 'b']), np.array(['a', 'b']), [], 'foo', datetime(2000, 1, 1, 0, 0), np.arange(0, 10), np.array([1]), [1]]: - pytest.raises(TypeError, lambda: RangeIndex(i)) + with pytest.raises(TypeError): + RangeIndex(i) def test_constructor_same(self): @@ -133,12 +105,13 @@ def test_constructor_same(self): result = RangeIndex(index) tm.assert_index_equal(result, index, exact=True) - pytest.raises(TypeError, - lambda: RangeIndex(index, dtype='float64')) + with pytest.raises(TypeError): + RangeIndex(index, dtype='float64') def test_constructor_range(self): - pytest.raises(TypeError, lambda: RangeIndex(range(1, 5, 2))) + with pytest.raises(TypeError): + RangeIndex(range(1, 5, 2)) result = RangeIndex.from_range(range(1, 5, 2)) expected = RangeIndex(1, 5, 2) @@ -161,8 +134,8 @@ def test_constructor_range(self): expected = RangeIndex(1, 5, 2) tm.assert_index_equal(result, expected, exact=True) - pytest.raises(TypeError, - lambda: Index(range(1, 5, 2), dtype='float64')) + with pytest.raises(TypeError): + Index(range(1, 5, 2), dtype='float64') def test_constructor_name(self): # GH12288 @@ -183,85 +156,6 @@ def test_constructor_name(self): assert copy.name == 'copy' assert new.name == 'new' - # TODO: mod, divmod? - @pytest.mark.parametrize('op', [operator.add, operator.sub, - operator.mul, operator.floordiv, - operator.truediv, operator.pow]) - def test_arithmetic_with_frame_or_series(self, op): - # check that we return NotImplemented when operating with Series - # or DataFrame - index = pd.RangeIndex(5) - other = pd.Series(np.random.randn(5)) - - expected = op(pd.Series(index), other) - result = op(index, other) - tm.assert_series_equal(result, expected) - - other = pd.DataFrame(np.random.randn(2, 5)) - expected = op(pd.DataFrame([index, index]), other) - result = op(index, other) - tm.assert_frame_equal(result, expected) - - def test_numeric_compat2(self): - # validate that we are handling the RangeIndex overrides to numeric ops - # and returning RangeIndex where possible - - idx = RangeIndex(0, 10, 2) - - result = idx * 2 - expected = RangeIndex(0, 20, 4) - tm.assert_index_equal(result, expected, exact=True) - - result = idx + 2 - expected = RangeIndex(2, 12, 2) - tm.assert_index_equal(result, expected, exact=True) - - result = idx - 2 - expected = RangeIndex(-2, 8, 2) - tm.assert_index_equal(result, expected, exact=True) - - # truediv under PY3 - result = idx / 2 - - if PY3: - expected = RangeIndex(0, 5, 1).astype('float64') - else: - expected = RangeIndex(0, 5, 1) - tm.assert_index_equal(result, expected, exact=True) - - result = idx / 4 - expected = RangeIndex(0, 10, 2) / 4 - tm.assert_index_equal(result, expected, exact=True) - - result = idx // 1 - expected = idx - tm.assert_index_equal(result, expected, exact=True) - - # __mul__ - result = idx * idx - expected = Index(idx.values * idx.values) - tm.assert_index_equal(result, expected, exact=True) - - # __pow__ - idx = RangeIndex(0, 1000, 2) - result = idx ** 2 - expected = idx._int64index ** 2 - tm.assert_index_equal(Index(result.values), expected, exact=True) - - # __floordiv__ - cases_exact = [(RangeIndex(0, 1000, 2), 2, RangeIndex(0, 500, 1)), - (RangeIndex(-99, -201, -3), -3, RangeIndex(33, 67, 1)), - (RangeIndex(0, 1000, 1), 2, - RangeIndex(0, 1000, 1)._int64index // 2), - (RangeIndex(0, 100, 1), 2.0, - RangeIndex(0, 100, 1)._int64index // 2.0), - (RangeIndex(0), 50, RangeIndex(0)), - (RangeIndex(2, 4, 2), 3, RangeIndex(0, 1, 1)), - (RangeIndex(-5, -10, -6), 4, RangeIndex(-2, -1, 1)), - (RangeIndex(-100, -200, 3), 2, RangeIndex(0))] - for idx, div, expected in cases_exact: - tm.assert_index_equal(idx // div, expected, exact=True) - def test_constructor_corner(self): arr = np.array([1, 2, 3, 4], dtype=object) index = RangeIndex(1, 5) @@ -269,11 +163,14 @@ def test_constructor_corner(self): tm.assert_index_equal(index, Index(arr)) # non-int raise Exception - pytest.raises(TypeError, RangeIndex, '1', '10', '1') - pytest.raises(TypeError, RangeIndex, 1.1, 10.2, 1.3) + with pytest.raises(TypeError): + RangeIndex('1', '10', '1') + with pytest.raises(TypeError): + RangeIndex(1.1, 10.2, 1.3) # invalid passed type - pytest.raises(TypeError, lambda: RangeIndex(1, 5, dtype='float64')) + with pytest.raises(TypeError): + RangeIndex(1, 5, dtype='float64') def test_copy(self): i = RangeIndex(5, name='Foo') @@ -735,10 +632,12 @@ def test_nbytes(self): def test_cant_or_shouldnt_cast(self): # can't - pytest.raises(TypeError, RangeIndex, 'foo', 'bar', 'baz') + with pytest.raises(TypeError): + RangeIndex('foo', 'bar', 'baz') # shouldn't - pytest.raises(TypeError, RangeIndex, '0', '1', '2') + with pytest.raises(TypeError): + RangeIndex('0', '1', '2') def test_view_Index(self): self.index.view(Index) @@ -825,12 +724,6 @@ def test_has_duplicates(self): assert idx.is_unique assert not idx.has_duplicates - def test_ufunc_compat(self): - idx = RangeIndex(5) - result = np.sin(idx) - expected = Float64Index(np.sin(np.arange(5, dtype='int64'))) - tm.assert_index_equal(result, expected) - def test_extended_gcd(self): result = self.index._extended_gcd(6, 10) assert result[0] == result[1] * 6 + result[2] * 10 diff --git a/pandas/tests/indexes/timedeltas/test_arithmetic.py b/pandas/tests/indexes/timedeltas/test_arithmetic.py index 82337ac37fbee..d2d116055f17c 100644 --- a/pandas/tests/indexes/timedeltas/test_arithmetic.py +++ b/pandas/tests/indexes/timedeltas/test_arithmetic.py @@ -8,10 +8,7 @@ import pandas as pd import pandas.util.testing as tm -from pandas import ( - DatetimeIndex, Int64Index, Series, Timedelta, TimedeltaIndex, Timestamp, - date_range, timedelta_range -) +from pandas import Timedelta, TimedeltaIndex, timedelta_range from pandas.errors import NullFrequencyError @@ -85,45 +82,6 @@ def test_shift_no_freq(self): with pytest.raises(NullFrequencyError): tdi.shift(2) - # ------------------------------------------------------------- - - def test_ufunc_coercions(self): - # normal ops are also tested in tseries/test_timedeltas.py - idx = TimedeltaIndex(['2H', '4H', '6H', '8H', '10H'], - freq='2H', name='x') - - for result in [idx * 2, np.multiply(idx, 2)]: - assert isinstance(result, TimedeltaIndex) - exp = TimedeltaIndex(['4H', '8H', '12H', '16H', '20H'], - freq='4H', name='x') - tm.assert_index_equal(result, exp) - assert result.freq == '4H' - - for result in [idx / 2, np.divide(idx, 2)]: - assert isinstance(result, TimedeltaIndex) - exp = TimedeltaIndex(['1H', '2H', '3H', '4H', '5H'], - freq='H', name='x') - tm.assert_index_equal(result, exp) - assert result.freq == 'H' - - idx = TimedeltaIndex(['2H', '4H', '6H', '8H', '10H'], - freq='2H', name='x') - for result in [-idx, np.negative(idx)]: - assert isinstance(result, TimedeltaIndex) - exp = TimedeltaIndex(['-2H', '-4H', '-6H', '-8H', '-10H'], - freq='-2H', name='x') - tm.assert_index_equal(result, exp) - assert result.freq == '-2H' - - idx = TimedeltaIndex(['-2H', '-1H', '0H', '1H', '2H'], - freq='H', name='x') - for result in [abs(idx), np.absolute(idx)]: - assert isinstance(result, TimedeltaIndex) - exp = TimedeltaIndex(['2H', '1H', '0H', '1H', '2H'], - freq=None, name='x') - tm.assert_index_equal(result, exp) - assert result.freq is None - # ------------------------------------------------------------- # Binary operations TimedeltaIndex and integer @@ -211,7 +169,8 @@ def test_tdi_addsub_integer_array_no_freq(self, box): # ------------------------------------------------------------- # Binary operations TimedeltaIndex and timedelta-like - # Note: add and sub are tested in tests.test_arithmetic + # Note: add and sub are tested in tests.test_arithmetic, in-place + # tests are kept here because their behavior is Index-specific def test_tdi_iadd_timedeltalike(self, delta): # only test adding/sub offsets as + is now numeric @@ -230,182 +189,7 @@ def test_tdi_isub_timedeltalike(self, delta): # ------------------------------------------------------------- - def test_subtraction_ops(self): - # with datetimes/timedelta and tdi/dti - tdi = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo') - dti = date_range('20130101', periods=3, name='bar') - td = Timedelta('1 days') - dt = Timestamp('20130101') - - pytest.raises(TypeError, lambda: tdi - dt) - pytest.raises(TypeError, lambda: tdi - dti) - pytest.raises(TypeError, lambda: td - dt) - pytest.raises(TypeError, lambda: td - dti) - - result = dt - dti - expected = TimedeltaIndex(['0 days', '-1 days', '-2 days'], name='bar') - tm.assert_index_equal(result, expected) - - result = dti - dt - expected = TimedeltaIndex(['0 days', '1 days', '2 days'], name='bar') - tm.assert_index_equal(result, expected) - - result = tdi - td - expected = TimedeltaIndex(['0 days', pd.NaT, '1 days'], name='foo') - tm.assert_index_equal(result, expected, check_names=False) - - result = td - tdi - expected = TimedeltaIndex(['0 days', pd.NaT, '-1 days'], name='foo') - tm.assert_index_equal(result, expected, check_names=False) - - result = dti - td - expected = DatetimeIndex( - ['20121231', '20130101', '20130102'], name='bar') - tm.assert_index_equal(result, expected, check_names=False) - - result = dt - tdi - expected = DatetimeIndex(['20121231', pd.NaT, '20121230'], name='foo') - tm.assert_index_equal(result, expected) - - def test_subtraction_ops_with_tz(self): - - # check that dt/dti subtraction ops with tz are validated - dti = date_range('20130101', periods=3) - ts = Timestamp('20130101') - dt = ts.to_pydatetime() - dti_tz = date_range('20130101', periods=3).tz_localize('US/Eastern') - ts_tz = Timestamp('20130101').tz_localize('US/Eastern') - ts_tz2 = Timestamp('20130101').tz_localize('CET') - dt_tz = ts_tz.to_pydatetime() - td = Timedelta('1 days') - - def _check(result, expected): - assert result == expected - assert isinstance(result, Timedelta) - - # scalars - result = ts - ts - expected = Timedelta('0 days') - _check(result, expected) - - result = dt_tz - ts_tz - expected = Timedelta('0 days') - _check(result, expected) - - result = ts_tz - dt_tz - expected = Timedelta('0 days') - _check(result, expected) - - # tz mismatches - pytest.raises(TypeError, lambda: dt_tz - ts) - pytest.raises(TypeError, lambda: dt_tz - dt) - pytest.raises(TypeError, lambda: dt_tz - ts_tz2) - pytest.raises(TypeError, lambda: dt - dt_tz) - pytest.raises(TypeError, lambda: ts - dt_tz) - pytest.raises(TypeError, lambda: ts_tz2 - ts) - pytest.raises(TypeError, lambda: ts_tz2 - dt) - pytest.raises(TypeError, lambda: ts_tz - ts_tz2) - - # with dti - pytest.raises(TypeError, lambda: dti - ts_tz) - pytest.raises(TypeError, lambda: dti_tz - ts) - pytest.raises(TypeError, lambda: dti_tz - ts_tz2) - - result = dti_tz - dt_tz - expected = TimedeltaIndex(['0 days', '1 days', '2 days']) - tm.assert_index_equal(result, expected) - - result = dt_tz - dti_tz - expected = TimedeltaIndex(['0 days', '-1 days', '-2 days']) - tm.assert_index_equal(result, expected) - - result = dti_tz - ts_tz - expected = TimedeltaIndex(['0 days', '1 days', '2 days']) - tm.assert_index_equal(result, expected) - - result = ts_tz - dti_tz - expected = TimedeltaIndex(['0 days', '-1 days', '-2 days']) - tm.assert_index_equal(result, expected) - - result = td - td - expected = Timedelta('0 days') - _check(result, expected) - - result = dti_tz - td - expected = DatetimeIndex( - ['20121231', '20130101', '20130102'], tz='US/Eastern') - tm.assert_index_equal(result, expected) - - def test_dti_tdi_numeric_ops(self): - # These are normally union/diff set-like ops - tdi = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo') - dti = date_range('20130101', periods=3, name='bar') - - # TODO(wesm): unused? - # td = Timedelta('1 days') - # dt = Timestamp('20130101') - - result = tdi - tdi - expected = TimedeltaIndex(['0 days', pd.NaT, '0 days'], name='foo') - tm.assert_index_equal(result, expected) - - result = tdi + tdi - expected = TimedeltaIndex(['2 days', pd.NaT, '4 days'], name='foo') - tm.assert_index_equal(result, expected) - - result = dti - tdi # name will be reset - expected = DatetimeIndex(['20121231', pd.NaT, '20130101']) - tm.assert_index_equal(result, expected) - - def test_addition_ops(self): - # with datetimes/timedelta and tdi/dti - tdi = TimedeltaIndex(['1 days', pd.NaT, '2 days'], name='foo') - dti = date_range('20130101', periods=3, name='bar') - td = Timedelta('1 days') - dt = Timestamp('20130101') - - result = tdi + dt - expected = DatetimeIndex(['20130102', pd.NaT, '20130103'], name='foo') - tm.assert_index_equal(result, expected) - - result = dt + tdi - expected = DatetimeIndex(['20130102', pd.NaT, '20130103'], name='foo') - tm.assert_index_equal(result, expected) - - result = td + tdi - expected = TimedeltaIndex(['2 days', pd.NaT, '3 days'], name='foo') - tm.assert_index_equal(result, expected) - - result = tdi + td - expected = TimedeltaIndex(['2 days', pd.NaT, '3 days'], name='foo') - tm.assert_index_equal(result, expected) - - # unequal length - pytest.raises(ValueError, lambda: tdi + dti[0:1]) - pytest.raises(ValueError, lambda: tdi[0:1] + dti) - - # random indexes - pytest.raises(NullFrequencyError, lambda: tdi + Int64Index([1, 2, 3])) - - # this is a union! - # pytest.raises(TypeError, lambda : Int64Index([1,2,3]) + tdi) - - result = tdi + dti # name will be reset - expected = DatetimeIndex(['20130102', pd.NaT, '20130105']) - tm.assert_index_equal(result, expected) - - result = dti + tdi # name will be reset - expected = DatetimeIndex(['20130102', pd.NaT, '20130105']) - tm.assert_index_equal(result, expected) - - result = dt + td - expected = Timestamp('20130102') - assert result == expected - - result = td + dt - expected = Timestamp('20130102') - assert result == expected - + # TODO: after #24365 this probably belongs in scalar tests def test_ops_ndarray(self): td = Timedelta('1 day') @@ -449,100 +233,6 @@ def test_ops_ndarray(self): if LooseVersion(np.__version__) >= LooseVersion('1.8'): tm.assert_numpy_array_equal(other - td, expected) - def test_timedelta_ops_with_missing_values(self): - # setup - s1 = pd.to_timedelta(Series(['00:00:01'])) - s2 = pd.to_timedelta(Series(['00:00:02'])) - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): - # Passing datetime64-dtype data to TimedeltaIndex is deprecated - sn = pd.to_timedelta(Series([pd.NaT])) - - df1 = pd.DataFrame(['00:00:01']).apply(pd.to_timedelta) - df2 = pd.DataFrame(['00:00:02']).apply(pd.to_timedelta) - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False): - # Passing datetime64-dtype data to TimedeltaIndex is deprecated - dfn = pd.DataFrame([pd.NaT]).apply(pd.to_timedelta) - - scalar1 = pd.to_timedelta('00:00:01') - scalar2 = pd.to_timedelta('00:00:02') - timedelta_NaT = pd.to_timedelta('NaT') - - actual = scalar1 + scalar1 - assert actual == scalar2 - actual = scalar2 - scalar1 - assert actual == scalar1 - - actual = s1 + s1 - tm.assert_series_equal(actual, s2) - actual = s2 - s1 - tm.assert_series_equal(actual, s1) - - actual = s1 + scalar1 - tm.assert_series_equal(actual, s2) - actual = scalar1 + s1 - tm.assert_series_equal(actual, s2) - actual = s2 - scalar1 - tm.assert_series_equal(actual, s1) - actual = -scalar1 + s2 - tm.assert_series_equal(actual, s1) - - actual = s1 + timedelta_NaT - tm.assert_series_equal(actual, sn) - actual = timedelta_NaT + s1 - tm.assert_series_equal(actual, sn) - actual = s1 - timedelta_NaT - tm.assert_series_equal(actual, sn) - actual = -timedelta_NaT + s1 - tm.assert_series_equal(actual, sn) - - with pytest.raises(TypeError): - s1 + np.nan - with pytest.raises(TypeError): - np.nan + s1 - with pytest.raises(TypeError): - s1 - np.nan - with pytest.raises(TypeError): - -np.nan + s1 - - actual = s1 + pd.NaT - tm.assert_series_equal(actual, sn) - actual = s2 - pd.NaT - tm.assert_series_equal(actual, sn) - - actual = s1 + df1 - tm.assert_frame_equal(actual, df2) - actual = s2 - df1 - tm.assert_frame_equal(actual, df1) - actual = df1 + s1 - tm.assert_frame_equal(actual, df2) - actual = df2 - s1 - tm.assert_frame_equal(actual, df1) - - actual = df1 + df1 - tm.assert_frame_equal(actual, df2) - actual = df2 - df1 - tm.assert_frame_equal(actual, df1) - - actual = df1 + scalar1 - tm.assert_frame_equal(actual, df2) - actual = df2 - scalar1 - tm.assert_frame_equal(actual, df1) - - actual = df1 + timedelta_NaT - tm.assert_frame_equal(actual, dfn) - actual = df1 - timedelta_NaT - tm.assert_frame_equal(actual, dfn) - - with pytest.raises(TypeError): - df1 + np.nan - with pytest.raises(TypeError): - df1 - np.nan - - actual = df1 + pd.NaT # NaT is datetime, not timedelta - tm.assert_frame_equal(actual, dfn) - actual = df1 - pd.NaT - tm.assert_frame_equal(actual, dfn) - def test_tdi_ops_attributes(self): rng = timedelta_range('2 days', periods=5, freq='2D', name='x') @@ -578,36 +268,3 @@ def test_tdi_ops_attributes(self): '2 days'], name='x') tm.assert_index_equal(result, exp) assert result.freq is None - - # TODO: Needs more informative name, probably split up into - # more targeted tests - def test_timedelta(self, freq): - index = date_range('1/1/2000', periods=50, freq=freq) - - shifted = index + timedelta(1) - back = shifted + timedelta(-1) - tm.assert_index_equal(index, back) - - if freq == 'D': - expected = pd.tseries.offsets.Day(1) - assert index.freq == expected - assert shifted.freq == expected - assert back.freq == expected - else: # freq == 'B' - assert index.freq == pd.tseries.offsets.BusinessDay(1) - assert shifted.freq is None - assert back.freq == pd.tseries.offsets.BusinessDay(1) - - result = index - timedelta(1) - expected = index + timedelta(-1) - tm.assert_index_equal(result, expected) - - # GH4134, buggy with timedeltas - rng = date_range('2013', '2014') - s = Series(rng) - result1 = rng - pd.offsets.Hour(1) - result2 = DatetimeIndex(s - np.timedelta64(100000000)) - result3 = rng - np.timedelta64(100000000) - result4 = DatetimeIndex(s - pd.offsets.Hour(1)) - tm.assert_index_equal(result1, result4) - tm.assert_index_equal(result2, result3) diff --git a/pandas/tests/series/test_arithmetic.py b/pandas/tests/series/test_arithmetic.py index d1d6aa8b51c0d..687ed59772d18 100644 --- a/pandas/tests/series/test_arithmetic.py +++ b/pandas/tests/series/test_arithmetic.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from datetime import timedelta import operator import numpy as np @@ -59,16 +58,6 @@ def test_flex_method_equivalence(self, opname, ts): class TestSeriesArithmetic(object): # Some of these may end up in tests/arithmetic, but are not yet sorted - def test_empty_series_add_sub(self): - # GH#13844 - a = Series(dtype='M8[ns]') - b = Series(dtype='m8[ns]') - tm.assert_series_equal(a, a + b) - tm.assert_series_equal(a, a - b) - tm.assert_series_equal(a, b + a) - with pytest.raises(TypeError): - b - a - def test_add_series_with_period_index(self): rng = pd.period_range('1/1/2000', '1/1/2010', freq='A') ts = Series(np.random.randn(len(rng)), index=rng) @@ -85,32 +74,6 @@ def test_add_series_with_period_index(self): with pytest.raises(IncompatibleFrequency, match=msg): ts + ts.asfreq('D', how="end") - def test_operators_datetimelike(self): - - # ## timedelta64 ### - td1 = Series([timedelta(minutes=5, seconds=3)] * 3) - td1.iloc[2] = np.nan - - # ## datetime64 ### - dt1 = Series([pd.Timestamp('20111230'), pd.Timestamp('20120101'), - pd.Timestamp('20120103')]) - dt1.iloc[2] = np.nan - dt2 = Series([pd.Timestamp('20111231'), pd.Timestamp('20120102'), - pd.Timestamp('20120104')]) - dt1 - dt2 - dt2 - dt1 - - # ## datetime64 with timetimedelta ### - dt1 + td1 - td1 + dt1 - dt1 - td1 - # TODO: Decide if this ought to work. - # td1 - dt1 - - # ## timetimedelta with datetime64 ### - td1 + dt1 - dt1 + td1 - # ------------------------------------------------------------------ # Comparisons @@ -207,18 +170,3 @@ def test_ser_cmp_result_names(self, names, op): ser = Series(cidx).rename(names[1]) result = op(ser, cidx) assert result.name == names[2] - - -def test_pow_ops_object(): - # 22922 - # pow is weird with masking & 1, so testing here - a = Series([1, np.nan, 1, np.nan], dtype=object) - b = Series([1, np.nan, np.nan, 1], dtype=object) - result = a ** b - expected = Series(a.values ** b.values, dtype=object) - tm.assert_series_equal(result, expected) - - result = b ** a - expected = Series(b.values ** a.values, dtype=object) - - tm.assert_series_equal(result, expected) diff --git a/pandas/tests/series/test_operators.py b/pandas/tests/series/test_operators.py index bcecedc2bba97..7c11880ae5f94 100644 --- a/pandas/tests/series/test_operators.py +++ b/pandas/tests/series/test_operators.py @@ -12,7 +12,7 @@ import pandas as pd from pandas import ( - Categorical, DataFrame, Index, NaT, Series, bdate_range, date_range, isna) + Categorical, DataFrame, Index, Series, bdate_range, date_range, isna) from pandas.core import ops import pandas.core.nanops as nanops import pandas.util.testing as tm @@ -543,49 +543,6 @@ def test_unequal_categorical_comparison_raises_type_error(self): tm.assert_series_equal(cat == "d", Series([False, False, False])) tm.assert_series_equal(cat != "d", Series([True, True, True])) - @pytest.mark.parametrize('pair', [ - ([pd.Timestamp('2011-01-01'), NaT, pd.Timestamp('2011-01-03')], - [NaT, NaT, pd.Timestamp('2011-01-03')]), - - ([pd.Timedelta('1 days'), NaT, pd.Timedelta('3 days')], - [NaT, NaT, pd.Timedelta('3 days')]), - - ([pd.Period('2011-01', freq='M'), NaT, - pd.Period('2011-03', freq='M')], - [NaT, NaT, pd.Period('2011-03', freq='M')]), - - ]) - @pytest.mark.parametrize('reverse', [True, False]) - @pytest.mark.parametrize('box', [Series, Index]) - @pytest.mark.parametrize('dtype', [None, object]) - def test_nat_comparisons(self, dtype, box, reverse, pair): - l, r = pair - if reverse: - # add lhs / rhs switched data - l, r = r, l - - left = Series(l, dtype=dtype) - right = box(r, dtype=dtype) - # Series, Index - - expected = Series([False, False, True]) - assert_series_equal(left == right, expected) - - expected = Series([True, True, False]) - assert_series_equal(left != right, expected) - - expected = Series([False, False, False]) - assert_series_equal(left < right, expected) - - expected = Series([False, False, False]) - assert_series_equal(left > right, expected) - - expected = Series([False, False, True]) - assert_series_equal(left >= right, expected) - - expected = Series([False, False, True]) - assert_series_equal(left <= right, expected) - def test_ne(self): ts = Series([3, 4, 5, 6, 7], [3, 4, 5, 6, 7], dtype=float) expected = [True, True, False, True, True]