# -*- coding: utf-8 -*- from datetime import datetime, timedelta import operator from decimal import Decimal import numpy as np import pytest from pandas import Series, Timestamp, Timedelta, Period, NaT from pandas._libs.tslibs.period import IncompatibleFrequency import pandas as pd import pandas.util.testing as tm @pytest.fixture def tdser(): """ Return a Series with dtype='timedelta64[ns]', including a NaT. """ return Series(['59 Days', '59 Days', 'NaT'], dtype='timedelta64[ns]') # ------------------------------------------------------------------ # Comparisons class TestSeriesComparison(object): def test_compare_invalid(self): # GH#8058 # ops testing a = pd.Series(np.random.randn(5), name=0) b = pd.Series(np.random.randn(5)) b.name = pd.Timestamp('2000-01-01') tm.assert_series_equal(a / b, 1 / (b / a)) @pytest.mark.parametrize('opname', ['eq', 'ne', 'gt', 'lt', 'ge', 'le']) def test_ser_flex_cmp_return_dtypes(self, opname): # GH#15115 ser = Series([1, 3, 2], index=range(3)) const = 2 result = getattr(ser, opname)(const).get_dtype_counts() tm.assert_series_equal(result, Series([1], ['bool'])) @pytest.mark.parametrize('opname', ['eq', 'ne', 'gt', 'lt', 'ge', 'le']) def test_ser_flex_cmp_return_dtypes_empty(self, opname): # GH#15115 empty Series case ser = Series([1, 3, 2], index=range(3)) empty = ser.iloc[:0] const = 2 result = getattr(empty, opname)(const).get_dtype_counts() tm.assert_series_equal(result, Series([1], ['bool'])) @pytest.mark.parametrize('op', [operator.eq, operator.ne, operator.le, operator.lt, operator.ge, operator.gt]) @pytest.mark.parametrize('names', [(None, None, None), ('foo', 'bar', None), ('baz', 'baz', 'baz')]) def test_ser_cmp_result_names(self, names, op): # datetime64 dtype dti = pd.date_range('1949-06-07 03:00:00', freq='H', periods=5, name=names[0]) ser = Series(dti).rename(names[1]) result = op(ser, dti) assert result.name == names[2] # datetime64tz dtype dti = dti.tz_localize('US/Central') ser = Series(dti).rename(names[1]) result = op(ser, dti) assert result.name == names[2] # timedelta64 dtype tdi = dti - dti.shift(1) ser = Series(tdi).rename(names[1]) result = op(ser, tdi) assert result.name == names[2] # categorical if op in [operator.eq, operator.ne]: # categorical dtype comparisons raise for inequalities cidx = tdi.astype('category') ser = Series(cidx).rename(names[1]) result = op(ser, cidx) assert result.name == names[2] class TestTimestampSeriesComparison(object): def test_dt64_ser_cmp_date_warning(self): # https://github.com/pandas-dev/pandas/issues/21359 # Remove this test and enble invalid test below ser = pd.Series(pd.date_range('20010101', periods=10), name='dates') date = ser.iloc[0].to_pydatetime().date() with tm.assert_produces_warning(FutureWarning) as m: result = ser == date expected = pd.Series([True] + [False] * 9, name='dates') tm.assert_series_equal(result, expected) assert "Comparing Series of datetimes " in str(m[0].message) assert "will not compare equal" in str(m[0].message) with tm.assert_produces_warning(FutureWarning) as m: result = ser != date tm.assert_series_equal(result, ~expected) assert "will not compare equal" in str(m[0].message) with tm.assert_produces_warning(FutureWarning) as m: result = ser <= date tm.assert_series_equal(result, expected) assert "a TypeError will be raised" in str(m[0].message) with tm.assert_produces_warning(FutureWarning) as m: result = ser < date tm.assert_series_equal(result, pd.Series([False] * 10, name='dates')) assert "a TypeError will be raised" in str(m[0].message) with tm.assert_produces_warning(FutureWarning) as m: result = ser >= date tm.assert_series_equal(result, pd.Series([True] * 10, name='dates')) assert "a TypeError will be raised" in str(m[0].message) with tm.assert_produces_warning(FutureWarning) as m: result = ser > date tm.assert_series_equal(result, pd.Series([False] + [True] * 9, name='dates')) assert "a TypeError will be raised" in str(m[0].message) @pytest.mark.skip(reason="GH-21359") def test_dt64ser_cmp_date_invalid(self): # GH#19800 datetime.date comparison raises to # match DatetimeIndex/Timestamp. This also matches the behavior # of stdlib datetime.datetime ser = pd.Series(pd.date_range('20010101', periods=10), name='dates') date = ser.iloc[0].to_pydatetime().date() assert not (ser == date).any() assert (ser != date).all() with pytest.raises(TypeError): ser > date with pytest.raises(TypeError): ser < date with pytest.raises(TypeError): ser >= date with pytest.raises(TypeError): ser <= date def test_dt64ser_cmp_period_scalar(self): ser = Series(pd.period_range('2000-01-01', periods=10, freq='D')) val = Period('2000-01-04', freq='D') result = ser > val expected = Series([x > val for x in ser]) tm.assert_series_equal(result, expected) val = ser[5] result = ser > val expected = Series([x > val for x in ser]) tm.assert_series_equal(result, expected) def test_timestamp_compare_series(self): # make sure we can compare Timestamps on the right AND left hand side # GH#4982 ser = pd.Series(pd.date_range('20010101', periods=10), name='dates') s_nat = ser.copy(deep=True) ser[0] = pd.Timestamp('nat') ser[3] = pd.Timestamp('nat') ops = {'lt': 'gt', 'le': 'ge', 'eq': 'eq', 'ne': 'ne'} for left, right in ops.items(): left_f = getattr(operator, left) right_f = getattr(operator, right) # no nats expected = left_f(ser, pd.Timestamp('20010109')) result = right_f(pd.Timestamp('20010109'), ser) tm.assert_series_equal(result, expected) # nats expected = left_f(ser, pd.Timestamp('nat')) result = right_f(pd.Timestamp('nat'), ser) tm.assert_series_equal(result, expected) # compare to timestamp with series containing nats expected = left_f(s_nat, pd.Timestamp('20010109')) result = right_f(pd.Timestamp('20010109'), s_nat) tm.assert_series_equal(result, expected) # compare to nat with series containing nats expected = left_f(s_nat, pd.Timestamp('nat')) result = right_f(pd.Timestamp('nat'), s_nat) tm.assert_series_equal(result, expected) def test_timestamp_equality(self): # GH#11034 ser = pd.Series([pd.Timestamp('2000-01-29 01:59:00'), 'NaT']) result = ser != ser tm.assert_series_equal(result, pd.Series([False, True])) result = ser != ser[0] tm.assert_series_equal(result, pd.Series([False, True])) result = ser != ser[1] tm.assert_series_equal(result, pd.Series([True, True])) result = ser == ser tm.assert_series_equal(result, pd.Series([True, False])) result = ser == ser[0] tm.assert_series_equal(result, pd.Series([True, False])) result = ser == ser[1] tm.assert_series_equal(result, pd.Series([False, False])) class TestTimedeltaSeriesComparisons(object): def test_compare_timedelta_series(self): # regresssion test for GH5963 s = pd.Series([timedelta(days=1), timedelta(days=2)]) actual = s > timedelta(days=1) expected = pd.Series([False, True]) tm.assert_series_equal(actual, expected) class TestPeriodSeriesComparisons(object): @pytest.mark.parametrize('freq', ['M', '2M', '3M']) def test_cmp_series_period_scalar(self, freq): # GH 13200 base = Series([Period(x, freq=freq) for x in ['2011-01', '2011-02', '2011-03', '2011-04']]) p = Period('2011-02', freq=freq) exp = Series([False, True, False, False]) tm.assert_series_equal(base == p, exp) tm.assert_series_equal(p == base, exp) exp = Series([True, False, True, True]) tm.assert_series_equal(base != p, exp) tm.assert_series_equal(p != base, exp) exp = Series([False, False, True, True]) tm.assert_series_equal(base > p, exp) tm.assert_series_equal(p < base, exp) exp = Series([True, False, False, False]) tm.assert_series_equal(base < p, exp) tm.assert_series_equal(p > base, exp) exp = Series([False, True, True, True]) tm.assert_series_equal(base >= p, exp) tm.assert_series_equal(p <= base, exp) exp = Series([True, True, False, False]) tm.assert_series_equal(base <= p, exp) tm.assert_series_equal(p >= base, exp) # different base freq msg = "Input has different freq=A-DEC from Period" with tm.assert_raises_regex(IncompatibleFrequency, msg): base <= Period('2011', freq='A') with tm.assert_raises_regex(IncompatibleFrequency, msg): Period('2011', freq='A') >= base @pytest.mark.parametrize('freq', ['M', '2M', '3M']) def test_cmp_series_period_series(self, freq): # GH#13200 base = Series([Period(x, freq=freq) for x in ['2011-01', '2011-02', '2011-03', '2011-04']]) ser = Series([Period(x, freq=freq) for x in ['2011-02', '2011-01', '2011-03', '2011-05']]) exp = Series([False, False, True, False]) tm.assert_series_equal(base == ser, exp) exp = Series([True, True, False, True]) tm.assert_series_equal(base != ser, exp) exp = Series([False, True, False, False]) tm.assert_series_equal(base > ser, exp) exp = Series([True, False, False, True]) tm.assert_series_equal(base < ser, exp) exp = Series([False, True, True, False]) tm.assert_series_equal(base >= ser, exp) exp = Series([True, False, True, True]) tm.assert_series_equal(base <= ser, exp) ser2 = Series([Period(x, freq='A') for x in ['2011', '2011', '2011', '2011']]) # different base freq msg = "Input has different freq=A-DEC from Period" with tm.assert_raises_regex(IncompatibleFrequency, msg): base <= ser2 def test_cmp_series_period_series_mixed_freq(self): # GH#13200 base = Series([Period('2011', freq='A'), Period('2011-02', freq='M'), Period('2013', freq='A'), Period('2011-04', freq='M')]) ser = Series([Period('2012', freq='A'), Period('2011-01', freq='M'), Period('2013', freq='A'), Period('2011-05', freq='M')]) exp = Series([False, False, True, False]) tm.assert_series_equal(base == ser, exp) exp = Series([True, True, False, True]) tm.assert_series_equal(base != ser, exp) exp = Series([False, True, False, False]) tm.assert_series_equal(base > ser, exp) exp = Series([True, False, False, True]) tm.assert_series_equal(base < ser, exp) exp = Series([False, True, True, False]) tm.assert_series_equal(base >= ser, exp) exp = Series([True, False, True, True]) tm.assert_series_equal(base <= ser, exp) # ------------------------------------------------------------------ # Arithmetic class TestSeriesDivision(object): # __div__, __rdiv__, __floordiv__, __rfloordiv__ # for non-timestamp/timedelta/period dtypes def test_divide_decimal(self): # resolves issue GH#9787 expected = Series([Decimal(5)]) ser = Series([Decimal(10)]) result = ser / Decimal(2) tm.assert_series_equal(result, expected) ser = Series([Decimal(10)]) result = ser // Decimal(2) tm.assert_series_equal(result, expected) def test_div_equiv_binop(self): # Test Series.div as well as Series.__div__ # float/integer issue # GH#7785 first = Series([1, 0], name='first') second = Series([-0.01, -0.02], name='second') expected = Series([-0.01, -np.inf]) result = second.div(first) tm.assert_series_equal(result, expected, check_names=False) result = second / first tm.assert_series_equal(result, expected) @pytest.mark.parametrize('dtype2', [ np.int64, np.int32, np.int16, np.int8, np.float64, np.float32, np.float16, np.uint64, np.uint32, np.uint16, np.uint8]) @pytest.mark.parametrize('dtype1', [np.int64, np.float64, np.uint64]) def test_ser_div_ser(self, dtype1, dtype2): # no longer do integer div for any ops, but deal with the 0's first = Series([3, 4, 5, 8], name='first').astype(dtype1) second = Series([0, 0, 0, 3], name='second').astype(dtype2) with np.errstate(all='ignore'): expected = Series(first.values.astype(np.float64) / second.values, dtype='float64', name=None) expected.iloc[0:3] = np.inf result = first / second tm.assert_series_equal(result, expected) assert not result.equals(second / first) def test_rdiv_zero_compat(self): # GH#8674 zero_array = np.array([0] * 5) data = np.random.randn(5) expected = Series([0.] * 5) result = zero_array / Series(data) tm.assert_series_equal(result, expected) result = Series(zero_array) / data tm.assert_series_equal(result, expected) result = Series(zero_array) / Series(data) tm.assert_series_equal(result, expected) def test_div_zero_inf_signs(self): # GH#9144, inf signing ser = Series([-1, 0, 1], name='first') expected = Series([-np.inf, np.nan, np.inf], name='first') result = ser / 0 tm.assert_series_equal(result, expected) def test_rdiv_zero(self): # GH#9144 ser = Series([-1, 0, 1], name='first') expected = Series([0.0, np.nan, 0.0], name='first') result = 0 / ser tm.assert_series_equal(result, expected) def test_floordiv_div(self): # GH#9144 ser = Series([-1, 0, 1], name='first') result = ser // 0 expected = Series([-np.inf, np.nan, np.inf], name='first') tm.assert_series_equal(result, expected) class TestSeriesArithmetic(object): # Standard, numeric, or otherwise not-Timestamp/Timedelta/Period dtypes @pytest.mark.parametrize('data', [ [1, 2, 3], [1.1, 2.2, 3.3], [Timestamp('2011-01-01'), Timestamp('2011-01-02'), pd.NaT], ['x', 'y', 1]]) @pytest.mark.parametrize('dtype', [None, object]) def test_series_radd_str_invalid(self, dtype, data): ser = Series(data, dtype=dtype) with pytest.raises(TypeError): 'foo_' + ser # TODO: parametrize, better name def test_object_ser_add_invalid(self): # invalid ops obj_ser = tm.makeObjectSeries() obj_ser.name = 'objects' with pytest.raises(Exception): obj_ser + 1 with pytest.raises(Exception): obj_ser + np.array(1, dtype=np.int64) with pytest.raises(Exception): obj_ser - 1 with pytest.raises(Exception): obj_ser - np.array(1, dtype=np.int64) @pytest.mark.parametrize('dtype', [None, object]) def test_series_with_dtype_radd_nan(self, dtype): ser = pd.Series([1, 2, 3], dtype=dtype) expected = pd.Series([np.nan, np.nan, np.nan], dtype=dtype) result = np.nan + ser tm.assert_series_equal(result, expected) result = ser + np.nan tm.assert_series_equal(result, expected) @pytest.mark.parametrize('dtype', [None, object]) def test_series_with_dtype_radd_int(self, dtype): ser = pd.Series([1, 2, 3], dtype=dtype) expected = pd.Series([2, 3, 4], dtype=dtype) result = 1 + ser tm.assert_series_equal(result, expected) result = ser + 1 tm.assert_series_equal(result, expected) def test_series_radd_str(self): ser = pd.Series(['x', np.nan, 'x']) tm.assert_series_equal('a' + ser, pd.Series(['ax', np.nan, 'ax'])) tm.assert_series_equal(ser + 'a', pd.Series(['xa', np.nan, 'xa'])) @pytest.mark.parametrize('dtype', [None, object]) def test_series_with_dtype_radd_timedelta(self, dtype): # note this test is _not_ aimed at timedelta64-dtyped Series ser = pd.Series([pd.Timedelta('1 days'), pd.Timedelta('2 days'), pd.Timedelta('3 days')], dtype=dtype) expected = pd.Series([pd.Timedelta('4 days'), pd.Timedelta('5 days'), pd.Timedelta('6 days')]) result = pd.Timedelta('3 days') + ser tm.assert_series_equal(result, expected) result = ser + pd.Timedelta('3 days') tm.assert_series_equal(result, expected) class TestPeriodSeriesArithmetic(object): def test_ops_series_timedelta(self): # GH 13043 ser = pd.Series([pd.Period('2015-01-01', freq='D'), pd.Period('2015-01-02', freq='D')], name='xxx') assert ser.dtype == object expected = pd.Series([pd.Period('2015-01-02', freq='D'), pd.Period('2015-01-03', freq='D')], name='xxx') result = ser + pd.Timedelta('1 days') tm.assert_series_equal(result, expected) result = pd.Timedelta('1 days') + ser tm.assert_series_equal(result, expected) result = ser + pd.tseries.offsets.Day() tm.assert_series_equal(result, expected) result = pd.tseries.offsets.Day() + ser tm.assert_series_equal(result, expected) def test_ops_series_period(self): # GH 13043 ser = pd.Series([pd.Period('2015-01-01', freq='D'), pd.Period('2015-01-02', freq='D')], name='xxx') assert ser.dtype == object per = pd.Period('2015-01-10', freq='D') # dtype will be object because of original dtype expected = pd.Series([9, 8], name='xxx', dtype=object) tm.assert_series_equal(per - ser, expected) tm.assert_series_equal(ser - per, -1 * expected) s2 = pd.Series([pd.Period('2015-01-05', freq='D'), pd.Period('2015-01-04', freq='D')], name='xxx') assert s2.dtype == object expected = pd.Series([4, 2], name='xxx', dtype=object) tm.assert_series_equal(s2 - ser, expected) tm.assert_series_equal(ser - s2, -1 * expected) class TestTimestampSeriesArithmetic(object): def test_timestamp_sub_series(self): ser = pd.Series(pd.date_range('2014-03-17', periods=2, freq='D', tz='US/Eastern')) ts = ser[0] delta_series = pd.Series([np.timedelta64(0, 'D'), np.timedelta64(1, 'D')]) tm.assert_series_equal(ser - ts, delta_series) tm.assert_series_equal(ts - ser, -delta_series) def test_dt64ser_sub_datetime_dtype(self): ts = Timestamp(datetime(1993, 1, 7, 13, 30, 00)) dt = datetime(1993, 6, 22, 13, 30) ser = Series([ts]) result = pd.to_timedelta(np.abs(ser - dt)) assert result.dtype == 'timedelta64[ns]' class TestTimedeltaSeriesAdditionSubtraction(object): # Tests for Series[timedelta64[ns]] __add__, __sub__, __radd__, __rsub__ # ------------------------------------------------------------------ # Operations with int-like others def test_td64series_add_int_series_invalid(self, tdser): with pytest.raises(TypeError): tdser + Series([2, 3, 4]) @pytest.mark.xfail(reason='GH#19123 integer interpreted as nanoseconds') def test_td64series_radd_int_series_invalid(self, tdser): with pytest.raises(TypeError): Series([2, 3, 4]) + tdser def test_td64series_sub_int_series_invalid(self, tdser): with pytest.raises(TypeError): tdser - Series([2, 3, 4]) @pytest.mark.xfail(reason='GH#19123 integer interpreted as nanoseconds') def test_td64series_rsub_int_series_invalid(self, tdser): with pytest.raises(TypeError): Series([2, 3, 4]) - tdser def test_td64_series_add_intlike(self): # GH#19123 tdi = pd.TimedeltaIndex(['59 days', '59 days', 'NaT']) ser = Series(tdi) other = Series([20, 30, 40], dtype='uint8') pytest.raises(TypeError, ser.__add__, 1) pytest.raises(TypeError, ser.__sub__, 1) pytest.raises(TypeError, ser.__add__, other) pytest.raises(TypeError, ser.__sub__, other) pytest.raises(TypeError, ser.__add__, other.values) pytest.raises(TypeError, ser.__sub__, other.values) pytest.raises(TypeError, ser.__add__, pd.Index(other)) pytest.raises(TypeError, ser.__sub__, pd.Index(other)) @pytest.mark.parametrize('scalar', [1, 1.5, np.array(2)]) def test_td64series_add_sub_numeric_scalar_invalid(self, scalar, tdser): with pytest.raises(TypeError): tdser + scalar with pytest.raises(TypeError): scalar + tdser with pytest.raises(TypeError): tdser - scalar with pytest.raises(TypeError): scalar - tdser @pytest.mark.parametrize('dtype', ['int64', 'int32', 'int16', 'uint64', 'uint32', 'uint16', 'uint8', 'float64', 'float32', 'float16']) @pytest.mark.parametrize('vector', [ np.array([1, 2, 3]), pd.Index([1, 2, 3]), pytest.param(Series([1, 2, 3]), marks=pytest.mark.xfail(reason='GH#19123 integer ' 'interpreted as nanos')) ]) def test_td64series_add_sub_numeric_array_invalid(self, vector, dtype, tdser): vector = vector.astype(dtype) with pytest.raises(TypeError): tdser + vector with pytest.raises(TypeError): vector + tdser with pytest.raises(TypeError): tdser - vector with pytest.raises(TypeError): vector - tdser # ------------------------------------------------------------------ # Operations with datetime-like others def test_td64series_add_sub_timestamp(self): # GH#11925 tdser = Series(pd.timedelta_range('1 day', periods=3)) ts = Timestamp('2012-01-01') expected = Series(pd.date_range('2012-01-02', periods=3)) tm.assert_series_equal(ts + tdser, expected) tm.assert_series_equal(tdser + ts, expected) expected2 = Series(pd.date_range('2011-12-31', periods=3, freq='-1D')) tm.assert_series_equal(ts - tdser, expected2) tm.assert_series_equal(ts + (-tdser), expected2) with pytest.raises(TypeError): tdser - ts # ------------------------------------------------------------------ # Operations with timedelta-like others (including DateOffsets) @pytest.mark.parametrize('names', [(None, None, None), ('Egon', 'Venkman', None), ('NCC1701D', 'NCC1701D', 'NCC1701D')]) def test_td64_series_with_tdi(self, names): # GH#17250 make sure result dtype is correct # GH#19043 make sure names are propagated correctly tdi = pd.TimedeltaIndex(['0 days', '1 day'], name=names[0]) ser = Series([Timedelta(hours=3), Timedelta(hours=4)], name=names[1]) expected = Series([Timedelta(hours=3), Timedelta(days=1, hours=4)], name=names[2]) result = tdi + ser tm.assert_series_equal(result, expected) assert result.dtype == 'timedelta64[ns]' result = ser + tdi tm.assert_series_equal(result, expected) assert result.dtype == 'timedelta64[ns]' expected = Series([Timedelta(hours=-3), Timedelta(days=1, hours=-4)], name=names[2]) result = tdi - ser tm.assert_series_equal(result, expected) assert result.dtype == 'timedelta64[ns]' result = ser - tdi tm.assert_series_equal(result, -expected) assert result.dtype == 'timedelta64[ns]' def test_td64_sub_NaT(self): # GH#18808 ser = Series([NaT, Timedelta('1s')]) res = ser - NaT expected = Series([NaT, NaT], dtype='timedelta64[ns]') tm.assert_series_equal(res, expected) class TestTimedeltaSeriesMultiplicationDivision(object): # Tests for Series[timedelta64[ns]] # __mul__, __rmul__, __div__, __rdiv__, __floordiv__, __rfloordiv__ # ------------------------------------------------------------------ # __floordiv__, __rfloordiv__ @pytest.mark.parametrize('scalar_td', [ timedelta(minutes=5, seconds=4), Timedelta('5m4s'), Timedelta('5m4s').to_timedelta64()]) def test_timedelta_floordiv(self, scalar_td): # GH#18831 td1 = Series([timedelta(minutes=5, seconds=3)] * 3) td1.iloc[2] = np.nan result = td1 // scalar_td expected = Series([0, 0, np.nan]) tm.assert_series_equal(result, expected) @pytest.mark.parametrize('scalar_td', [ timedelta(minutes=5, seconds=4), Timedelta('5m4s'), Timedelta('5m4s').to_timedelta64()]) def test_timedelta_rfloordiv(self, scalar_td): # GH#18831 td1 = Series([timedelta(minutes=5, seconds=3)] * 3) td1.iloc[2] = np.nan result = scalar_td // td1 expected = Series([1, 1, np.nan]) tm.assert_series_equal(result, expected) @pytest.mark.parametrize('scalar_td', [ timedelta(minutes=5, seconds=4), Timedelta('5m4s'), Timedelta('5m4s').to_timedelta64()]) def test_timedelta_rfloordiv_explicit(self, scalar_td): # GH#18831 td1 = Series([timedelta(minutes=5, seconds=3)] * 3) td1.iloc[2] = np.nan # We can test __rfloordiv__ using this syntax, # see `test_timedelta_rfloordiv` result = td1.__rfloordiv__(scalar_td) expected = Series([1, 1, np.nan]) tm.assert_series_equal(result, expected) # ------------------------------------------------------------------ # Operations with int-like others @pytest.mark.parametrize('dtype', ['int64', 'int32', 'int16', 'uint64', 'uint32', 'uint16', 'uint8', 'float64', 'float32', 'float16']) @pytest.mark.parametrize('vector', [np.array([20, 30, 40]), pd.Index([20, 30, 40]), Series([20, 30, 40])]) def test_td64series_div_numeric_array(self, vector, dtype, tdser): # GH#4521 # divide/multiply by integers vector = vector.astype(dtype) expected = Series(['2.95D', '1D 23H 12m', 'NaT'], dtype='timedelta64[ns]') result = tdser / vector tm.assert_series_equal(result, expected) with pytest.raises(TypeError): vector / tdser @pytest.mark.parametrize('dtype', ['int64', 'int32', 'int16', 'uint64', 'uint32', 'uint16', 'uint8', 'float64', 'float32', 'float16']) @pytest.mark.parametrize('vector', [np.array([20, 30, 40]), pd.Index([20, 30, 40]), Series([20, 30, 40])]) def test_td64series_mul_numeric_array(self, vector, dtype, tdser): # GH#4521 # divide/multiply by integers vector = vector.astype(dtype) expected = Series(['1180 Days', '1770 Days', 'NaT'], dtype='timedelta64[ns]') result = tdser * vector tm.assert_series_equal(result, expected) @pytest.mark.parametrize('dtype', ['int64', 'int32', 'int16', 'uint64', 'uint32', 'uint16', 'uint8', 'float64', 'float32', 'float16']) @pytest.mark.parametrize('vector', [ np.array([20, 30, 40]), pytest.param(pd.Index([20, 30, 40]), marks=pytest.mark.xfail(reason='__mul__ raises ' 'instead of returning ' 'NotImplemented')), Series([20, 30, 40]) ]) def test_td64series_rmul_numeric_array(self, vector, dtype, tdser): # GH#4521 # divide/multiply by integers vector = vector.astype(dtype) expected = Series(['1180 Days', '1770 Days', 'NaT'], dtype='timedelta64[ns]') result = vector * tdser tm.assert_series_equal(result, expected) @pytest.mark.parametrize('one', [1, np.array(1), 1.0, np.array(1.0)]) def test_td64series_mul_numeric_scalar(self, one, tdser): # GH#4521 # divide/multiply by integers expected = Series(['-59 Days', '-59 Days', 'NaT'], dtype='timedelta64[ns]') result = tdser * (-one) tm.assert_series_equal(result, expected) result = (-one) * tdser tm.assert_series_equal(result, expected) expected = Series(['118 Days', '118 Days', 'NaT'], dtype='timedelta64[ns]') result = tdser * (2 * one) tm.assert_series_equal(result, expected) result = (2 * one) * tdser tm.assert_series_equal(result, expected) @pytest.mark.parametrize('two', [ 2, 2.0, pytest.param(np.array(2), marks=pytest.mark.xfail(reason='GH#19011 is_list_like ' 'incorrectly True.')), pytest.param(np.array(2.0), marks=pytest.mark.xfail(reason='GH#19011 is_list_like ' 'incorrectly True.')), ]) def test_td64series_div_numeric_scalar(self, two, tdser): # GH#4521 # divide/multiply by integers expected = Series(['29.5D', '29.5D', 'NaT'], dtype='timedelta64[ns]') result = tdser / two tm.assert_series_equal(result, expected) # ------------------------------------------------------------------ # Operations with timedelta-like others @pytest.mark.parametrize('names', [(None, None, None), ('Egon', 'Venkman', None), ('NCC1701D', 'NCC1701D', 'NCC1701D')]) def test_tdi_mul_int_series(self, names): # GH#19042 tdi = pd.TimedeltaIndex(['0days', '1day', '2days', '3days', '4days'], name=names[0]) ser = Series([0, 1, 2, 3, 4], dtype=np.int64, name=names[1]) expected = Series(['0days', '1day', '4days', '9days', '16days'], dtype='timedelta64[ns]', name=names[2]) result = ser * tdi tm.assert_series_equal(result, expected) # The direct operation tdi * ser still needs to be fixed. result = ser.__rmul__(tdi) tm.assert_series_equal(result, expected) @pytest.mark.parametrize('names', [(None, None, None), ('Egon', 'Venkman', None), ('NCC1701D', 'NCC1701D', 'NCC1701D')]) def test_float_series_rdiv_tdi(self, names): # GH#19042 # TODO: the direct operation TimedeltaIndex / Series still # needs to be fixed. tdi = pd.TimedeltaIndex(['0days', '1day', '2days', '3days', '4days'], name=names[0]) ser = Series([1.5, 3, 4.5, 6, 7.5], dtype=np.float64, name=names[1]) expected = Series([tdi[n] / ser[n] for n in range(len(ser))], dtype='timedelta64[ns]', name=names[2]) result = ser.__rdiv__(tdi) tm.assert_series_equal(result, expected) @pytest.mark.parametrize('scalar_td', [ timedelta(minutes=5, seconds=4), Timedelta('5m4s'), Timedelta('5m4s').to_timedelta64()]) def test_td64series_mul_timedeltalike_invalid(self, scalar_td): td1 = Series([timedelta(minutes=5, seconds=3)] * 3) td1.iloc[2] = np.nan # check that we are getting a TypeError # with 'operate' (from core/ops.py) for the ops that are not # defined pattern = 'operate|unsupported|cannot|not supported' with tm.assert_raises_regex(TypeError, pattern): td1 * scalar_td with tm.assert_raises_regex(TypeError, pattern): scalar_td * td1 class TestTimedeltaSeriesInvalidArithmeticOps(object): @pytest.mark.parametrize('scalar_td', [ timedelta(minutes=5, seconds=4), Timedelta('5m4s'), Timedelta('5m4s').to_timedelta64()]) def test_td64series_pow_invalid(self, scalar_td): td1 = Series([timedelta(minutes=5, seconds=3)] * 3) td1.iloc[2] = np.nan # check that we are getting a TypeError # with 'operate' (from core/ops.py) for the ops that are not # defined pattern = 'operate|unsupported|cannot|not supported' with tm.assert_raises_regex(TypeError, pattern): scalar_td ** td1 with tm.assert_raises_regex(TypeError, pattern): td1 ** scalar_td