Skip to content

TST: arithmetic test parametrization/cleanup #38673

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 8 commits into from
Dec 24, 2020
4 changes: 2 additions & 2 deletions pandas/core/arrays/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2077,15 +2077,15 @@ def objects_to_datetime64ns(
require_iso8601=require_iso8601,
)
result = result.reshape(data.shape, order=order)
except ValueError as e:
except ValueError as err:
try:
values, tz_parsed = conversion.datetime_to_datetime64(data.ravel("K"))
# If tzaware, these values represent unix timestamps, so we
# return them as i8 to distinguish from wall times
values = values.reshape(data.shape, order=order)
return values.view("i8"), tz_parsed
except (ValueError, TypeError):
raise e
raise err

if tz_parsed is not None:
# We can take a shortcut since the datetime64 numpy array
Expand Down
1 change: 1 addition & 0 deletions pandas/core/dtypes/cast.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ def maybe_downcast_to_dtype(result, dtype: Union[str, np.dtype]):
# convert to datetime and change timezone
i8values = result.astype("i8", copy=False)
cls = dtype.construct_array_type()
# equiv: DatetimeArray(i8values).tz_localize("UTC").tz_convert(dtype.tz)
result = cls._simple_new(i8values, dtype=dtype)
else:
result = result.astype(dtype)
Expand Down
4 changes: 3 additions & 1 deletion pandas/tests/arithmetic/test_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ def test_compare_zerodim(self, box_with_array):
expected = tm.box_expected(expected, xbox)
tm.assert_equal(result, expected)

@pytest.mark.parametrize("scalar", ["foo", Timestamp.now(), Timedelta(days=4)])
@pytest.mark.parametrize(
"scalar", ["foo", Timestamp.now(), Timedelta(days=4), 9, 9.5]
)
def test_compare_invalid_scalar(self, box_with_array, scalar):
# comparison with scalar that cannot be interpreted as a Period
pi = pd.period_range("2000", periods=4)
Expand Down
32 changes: 20 additions & 12 deletions pandas/tests/arithmetic/test_timedelta64.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
Timedelta,
TimedeltaIndex,
Timestamp,
offsets,
timedelta_range,
)
import pandas._testing as tm
Expand Down Expand Up @@ -70,7 +71,12 @@ def test_compare_timedelta64_zerodim(self, box_with_array):

@pytest.mark.parametrize(
"td_scalar",
[timedelta(days=1), Timedelta(days=1), Timedelta(days=1).to_timedelta64()],
[
timedelta(days=1),
Timedelta(days=1),
Timedelta(days=1).to_timedelta64(),
offsets.Hour(24),
],
)
def test_compare_timedeltalike_scalar(self, box_with_array, td_scalar):
# regression test for GH#5963
Expand All @@ -84,7 +90,18 @@ def test_compare_timedeltalike_scalar(self, box_with_array, td_scalar):
expected = tm.box_expected(expected, xbox)
tm.assert_equal(actual, expected)

@pytest.mark.parametrize("invalid", [345600000000000, "a"])
@pytest.mark.parametrize(
"invalid",
[
345600000000000,
"a",
Timestamp.now(),
Timestamp.now("UTC"),
Timestamp.now().to_datetime64(),
Timestamp.now().to_pydatetime(),
Timestamp.now().date(),
],
)
def test_td64_comparisons_invalid(self, box_with_array, invalid):
# GH#13624 for str
box = box_with_array
Expand Down Expand Up @@ -261,7 +278,6 @@ def test_ufunc_coercions(self):
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(
Expand Down Expand Up @@ -413,10 +429,6 @@ def test_dti_tdi_numeric_ops(self):
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)
Expand Down Expand Up @@ -543,7 +555,6 @@ def test_tda_add_sub_index(self):
expected = tdi - tdi
tm.assert_index_equal(result, expected)

@pytest.mark.xfail(reason="GH38630", strict=False)
def test_tda_add_dt64_object_array(self, box_with_array, tz_naive_fixture):
# Result should be cast back to DatetimeArray
box = box_with_array
Expand All @@ -555,10 +566,7 @@ def test_tda_add_dt64_object_array(self, box_with_array, tz_naive_fixture):
obj = tm.box_expected(tdi, box)
other = tm.box_expected(dti, box)

warn = None
if box is not pd.DataFrame or tz_naive_fixture is None:
warn = PerformanceWarning
with tm.assert_produces_warning(warn):
with tm.assert_produces_warning(PerformanceWarning):
result = obj + other.astype(object)
tm.assert_equal(result, other)

Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/extension/base/setitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_setitem_sequence_mismatched_length_raises(self, data, as_array):
ser[slice(3)] = value
self.assert_series_equal(ser, original)

def test_setitem_empty_indxer(self, data, box_in_series):
def test_setitem_empty_indexer(self, data, box_in_series):
if box_in_series:
data = pd.Series(data)
original = data.copy()
Expand Down
116 changes: 46 additions & 70 deletions pandas/tests/series/test_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ def test_sub_datetimelike_align(self):

def test_alignment_doesnt_change_tz(self):
# GH#33671
dti = pd.date_range("2016-01-01", periods=10, tz="CET")
dti = date_range("2016-01-01", periods=10, tz="CET")
dti_utc = dti.tz_convert("UTC")
ser = Series(10, index=dti)
ser_utc = Series(10, index=dti_utc)
Expand Down Expand Up @@ -399,7 +399,7 @@ def test_ser_flex_cmp_return_dtypes_empty(self, opname):
)
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])
dti = 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]
Expand Down Expand Up @@ -624,9 +624,13 @@ def test_ne(self):
),
],
)
def test_comp_ops_df_compat(self, left, right):
def test_comp_ops_df_compat(self, left, right, frame_or_series):
# GH 1134
msg = "Can only compare identically-labeled Series objects"
msg = f"Can only compare identically-labeled {frame_or_series.__name__} objects"
if frame_or_series is not Series:
left = left.to_frame()
right = right.to_frame()

with pytest.raises(ValueError, match=msg):
left == right
with pytest.raises(ValueError, match=msg):
Expand All @@ -642,22 +646,6 @@ def test_comp_ops_df_compat(self, left, right):
with pytest.raises(ValueError, match=msg):
right < left

msg = "Can only compare identically-labeled DataFrame objects"
with pytest.raises(ValueError, match=msg):
left.to_frame() == right.to_frame()
with pytest.raises(ValueError, match=msg):
right.to_frame() == left.to_frame()

with pytest.raises(ValueError, match=msg):
left.to_frame() != right.to_frame()
with pytest.raises(ValueError, match=msg):
right.to_frame() != left.to_frame()

with pytest.raises(ValueError, match=msg):
left.to_frame() < right.to_frame()
with pytest.raises(ValueError, match=msg):
right.to_frame() < left.to_frame()

def test_compare_series_interval_keyword(self):
# GH#25338
s = Series(["IntervalA", "IntervalB", "IntervalC"])
Expand Down Expand Up @@ -724,7 +712,7 @@ def test_series_add_aware_naive_raises(self):
def test_datetime_understood(self):
# Ensures it doesn't fail to create the right series
# reported in issue#16726
series = Series(pd.date_range("2012-01-01", periods=3))
series = Series(date_range("2012-01-01", periods=3))
offset = pd.offsets.DateOffset(days=6)
result = series - offset
expected = Series(pd.to_datetime(["2011-12-26", "2011-12-27", "2011-12-28"]))
Expand All @@ -746,58 +734,46 @@ def test_align_date_objects_with_datetimeindex(self):
tm.assert_series_equal(result2, expected)


@pytest.mark.parametrize(
"names",
[
("foo", None, None),
("Egon", "Venkman", None),
("NCC1701D", "NCC1701D", "NCC1701D"),
],
)
@pytest.mark.parametrize("box", [list, tuple, np.array, pd.Index, pd.Series, pd.array])
@pytest.mark.parametrize("flex", [True, False])
def test_series_ops_name_retention(flex, box, names, all_binary_operators, request):
# GH#33930 consistent name retention
op = all_binary_operators

if op is ops.rfloordiv and box in [list, tuple] and not flex:
mark = pytest.mark.xfail(
reason="op fails because of inconsistent ndarray-wrapping GH#28759"
)
request.node.add_marker(mark)

left = Series(range(10), name=names[0])
right = Series(range(10), name=names[1])

name = op.__name__.strip("_")
is_logical = name in ["and", "rand", "xor", "rxor", "or", "ror"]
is_rlogical = is_logical and name.startswith("r")

right = box(right)
if flex:
if is_logical:
# Series doesn't have these as flex methods
class TestNamePreservation:
@pytest.mark.parametrize("box", [list, tuple, np.array, Index, Series, pd.array])
@pytest.mark.parametrize("flex", [True, False])
def test_series_ops_name_retention(self, flex, box, names, all_binary_operators):
# GH#33930 consistent name renteiton
op = all_binary_operators

if op is ops.rfloordiv and box in [list, tuple]:
pytest.xfail("op fails because of inconsistent ndarray-wrapping GH#28759")

left = Series(range(10), name=names[0])
right = Series(range(10), name=names[1])

name = op.__name__.strip("_")
is_logical = name in ["and", "rand", "xor", "rxor", "or", "ror"]
is_rlogical = is_logical and name.startswith("r")

right = box(right)
if flex:
if is_logical:
# Series doesn't have these as flex methods
return
result = getattr(left, name)(right)
else:
# GH#37374 logical ops behaving as set ops deprecated
warn = FutureWarning if is_rlogical and box is Index else None
with tm.assert_produces_warning(warn, check_stacklevel=False):
result = op(left, right)

if box is Index and is_rlogical:
# Index treats these as set operators, so does not defer
assert isinstance(result, Index)
return
result = getattr(left, name)(right)
else:
# GH#37374 logical ops behaving as set ops deprecated
warn = FutureWarning if is_rlogical and box is Index else None
with tm.assert_produces_warning(warn, check_stacklevel=False):
result = op(left, right)

if box is pd.Index and is_rlogical:
# Index treats these as set operators, so does not defer
assert isinstance(result, pd.Index)
return

assert isinstance(result, Series)
if box in [pd.Index, pd.Series]:
assert result.name == names[2]
else:
assert result.name == names[0]

assert isinstance(result, Series)
if box in [Index, Series]:
assert result.name == names[2]
else:
assert result.name == names[0]

class TestNamePreservation:
def test_binop_maybe_preserve_name(self, datetime_series):
# names match, preserve
result = datetime_series * datetime_series
Expand Down