Skip to content
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

BUG: Fix ndarray + DataFrame ops #23114

Merged
merged 10 commits into from
Oct 14, 2018
7 changes: 7 additions & 0 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,13 @@ def __array__(self, dtype=None):
return com.values_from_object(self)

def __array_wrap__(self, result, context=None):
if (context is not None and context[1] is not None and
len(context[1]) == 2 and context[1][1] is self and
isinstance(context[1][0], np.ndarray)):
# TODO: Can we return NotImplemented earlier? By the time we
# get here we've calculated `result`, which may not be cheap
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shoyer any idea if there is a more elegant way to do this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are you trying to fix here? Generally I recommend avoiding __array_wrap__ if possible... __array_ufunc__ is a much more complete interface. To be honest, I'm not even sure if returning NotImplemented from __array_wrap__ has well-defined behavior.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are you trying to fix here?

#22537. In master ndarray[int] + DataFrame[timedelta64[ns]] treats the ndarray as timedelta64 instead of raising TypeError.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with exactly how pandas implements binary ops, but this doesn't look like the right place to fix this.

The problem is likely in the DataFrame.__radd__ or DataFrame.__array_ufunc__ method (which NumPy calls instead of __radd__ if defined, see here for details and recommendations)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Looks like its extra-simple: Series and Index both define __array_priority__ but DataFrame does not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, I'm kind of surprised we never defined DataFrame.__array_priority__ :)

return NotImplemented

d = self._construct_axes_dict(self._AXIS_ORDERS, copy=False)
return self._constructor(result, **d).__finalize__(self)

Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/arithmetic/test_numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def test_numeric_arr_rdiv_tdscalar(self, three_days, numeric_idx, box):
if box is not pd.Index and broken:
# np.timedelta64(3, 'D') / 2 == np.timedelta64(1, 'D')
raise pytest.xfail("timedelta64 not converted to nanos; "
"Tick division not imlpemented")
"Tick division not implemented")

expected = TimedeltaIndex(['3 Days', '36 Hours'])

Expand Down
3 changes: 0 additions & 3 deletions pandas/tests/arithmetic/test_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,6 @@ def test_objarr_radd_str_invalid(self, dtype, data, box):
operator.sub, ops.rsub])
def test_objarr_add_invalid(self, op, box):
# invalid ops
if box is pd.DataFrame and op is ops.radd:
pytest.xfail(reason="DataFrame op incorrectly casts the np.array"
"case to M8[ns]")

obj_ser = tm.makeObjectSeries()
obj_ser.name = 'objects'
Expand Down