Skip to content

Tests for TDI issues already fixed #19044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 5, 2018
6 changes: 5 additions & 1 deletion doc/source/whatsnew/v0.23.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,11 @@ Conversion
- Bug in :class:`Series` floor-division where operating on a scalar ``timedelta`` raises an exception (:issue:`18846`)
- Bug in :class:`FY5253Quarter`, :class:`LastWeekOfMonth` where rollback and rollforward behavior was inconsistent with addition and subtraction behavior (:issue:`18854`)
- Bug in :class:`Index` constructor with ``dtype=CategoricalDtype(...)`` where ``categories`` and ``ordered`` are not maintained (issue:`19032`)

- Bug in :class:`Index` constructor with ``dtype=CategoricalDtype(...)`` where ``categories`` and ``ordered`` are not maintained (issue:`19032`)
- Bug in :class:`Series`` with ``dtype='timedelta64[ns]`` where addition or subtraction of ``TimedeltaIndex`` had results cast to ``dtype='int64'`` (:issue:`17250`)
- Bug in :class:`TimedeltaIndex` where division by a ``Series`` would return a ``TimedeltaIndex`` instead of a ``Series`` (issue:`19042`)
- Bug in :class:`Series` with ``dtype='timedelta64[ns]`` where addition or subtraction of ``TimedeltaIndex`` could return a ``Series`` with an incorrect name (issue:`19043`)
-

Indexing
^^^^^^^^
Expand Down
3 changes: 3 additions & 0 deletions pandas/core/indexes/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,9 @@ def _add_delta(self, delta):
return result

def _evaluate_with_timedelta_like(self, other, op, opstr):
if isinstance(other, ABCSeries):
# GH#19042
return NotImplemented

# allow division by a timedelta
if opstr in ['__div__', '__truediv__', '__floordiv__']:
Expand Down
25 changes: 11 additions & 14 deletions pandas/core/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,15 @@ def _align_method_SERIES(left, right, align_asobject=False):


def _construct_result(left, result, index, name, dtype):
return left._constructor(result, index=index, name=name, dtype=dtype)
"""
If the raw op result has a non-None name (e.g. it is an Index object) and
the name argument is None, then passing name to the constructor will
not be enough; we still need to override the name attribute.
"""
out = left._constructor(result, index=index, dtype=dtype)

out.name = name
return out


def _construct_divmod_result(left, result, index, name, dtype):
Expand Down Expand Up @@ -687,21 +695,10 @@ def wrapper(left, right, name=name, na_op=na_op):
not isinstance(lvalues, ABCDatetimeIndex)):
lvalues = lvalues.values

if isinstance(right, (ABCSeries, pd.Index)):
# `left` is always a Series object
res_name = _maybe_match_name(left, right)
else:
res_name = left.name

result = wrap_results(safe_na_op(lvalues, rvalues))
res_name = _get_series_op_result_name(left, right)
return construct_result(
left,
result,
index=left.index,
name=res_name,
dtype=dtype,
)
return construct_result(left, result,
index=left.index, name=res_name, dtype=dtype)

return wrapper

Expand Down
68 changes: 68 additions & 0 deletions pandas/tests/series/test_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,74 @@ def test_timedelta_floordiv(self, scalar_td):
expected = Series([0, 0, np.nan])
tm.assert_series_equal(result, expected)

@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 propogated 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]'

@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)


class TestDatetimeSeriesArithmetic(object):
@pytest.mark.parametrize(
Expand Down