diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index e76b558f4c669..4414462dd9a48 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -1810,55 +1810,51 @@ def test_dt64ser_sub_datetime_dtype(self): # TODO: This next block of tests came from tests.series.test_operators, # needs to be de-duplicated and parametrized over `box` classes - def test_operators_datetimelike_invalid(self, all_arithmetic_operators): - # these are all TypeEror ops + @pytest.mark.parametrize( + "left, right, op_fail", + [ + [ + [Timestamp("20111230"), Timestamp("20120101"), NaT], + [Timestamp("20111231"), Timestamp("20120102"), Timestamp("20120104")], + ["__sub__", "__rsub__"], + ], + [ + [Timestamp("20111230"), Timestamp("20120101"), NaT], + [timedelta(minutes=5, seconds=3), timedelta(minutes=5, seconds=3), NaT], + ["__add__", "__radd__", "__sub__"], + ], + [ + [ + Timestamp("20111230", tz="US/Eastern"), + Timestamp("20111230", tz="US/Eastern"), + NaT, + ], + [timedelta(minutes=5, seconds=3), NaT, timedelta(minutes=5, seconds=3)], + ["__add__", "__radd__", "__sub__"], + ], + ], + ) + def test_operators_datetimelike_invalid( + self, left, right, op_fail, all_arithmetic_operators + ): + # these are all TypeError ops op_str = all_arithmetic_operators - - def check(get_ser, test_ser): - - # check that we are getting a TypeError - # with 'operate' (from core/ops.py) for the ops that are not - # defined - op = getattr(get_ser, op_str, None) - # Previously, _validate_for_numeric_binop in core/indexes/base.py - # did this for us. + arg1 = Series(left) + arg2 = Series(right) + # check that we are getting a TypeError + # with 'operate' (from core/ops.py) for the ops that are not + # defined + op = getattr(arg1, op_str, None) + # Previously, _validate_for_numeric_binop in core/indexes/base.py + # did this for us. + if op_str not in op_fail: with pytest.raises( TypeError, match="operate|[cC]annot|unsupported operand" ): - op(test_ser) - - # ## timedelta64 ### - td1 = Series([timedelta(minutes=5, seconds=3)] * 3) - td1.iloc[2] = np.nan - - # ## datetime64 ### - dt1 = Series( - [Timestamp("20111230"), Timestamp("20120101"), Timestamp("20120103")] - ) - dt1.iloc[2] = np.nan - dt2 = Series( - [Timestamp("20111231"), Timestamp("20120102"), Timestamp("20120104")] - ) - if op_str not in ["__sub__", "__rsub__"]: - check(dt1, dt2) - - # ## datetime64 with timetimedelta ### - # TODO(jreback) __rsub__ should raise? - if op_str not in ["__add__", "__radd__", "__sub__"]: - check(dt1, td1) - - # 8260, 10763 - # datetime64 with tz - tz = "US/Eastern" - dt1 = Series(date_range("2000-01-01 09:00:00", periods=5, tz=tz), name="foo") - dt2 = dt1.copy() - dt2.iloc[2] = np.nan - td1 = Series(pd.timedelta_range("1 days 1 min", periods=5, freq="H")) - td2 = td1.copy() - td2.iloc[1] = np.nan - - if op_str not in ["__add__", "__radd__", "__sub__", "__rsub__"]: - check(dt2, td2) + op(arg2) + else: + # Smoke test + op(arg2) def test_sub_single_tz(self): # GH#12290 diff --git a/pandas/tests/arithmetic/test_numeric.py b/pandas/tests/arithmetic/test_numeric.py index 063e3c7e6dd19..5a3e417aa1799 100644 --- a/pandas/tests/arithmetic/test_numeric.py +++ b/pandas/tests/arithmetic/test_numeric.py @@ -58,6 +58,17 @@ def adjust_negative_zero(zero, expected): return expected +def compare_op(series, other, op): + left = np.abs(series) if op in (ops.rpow, operator.pow) else series + right = np.abs(other) if op in (ops.rpow, operator.pow) else other + + cython_or_numpy = op(left, right) + python = left.combine(right, op) + if isinstance(other, Series) and not other.index.equals(series.index): + python.index = python.index._with_freq(None) + tm.assert_series_equal(cython_or_numpy, python) + + # TODO: remove this kludge once mypy stops giving false positives here # List comprehension has incompatible type List[PandasObject]; expected List[RangeIndex] # See GH#29725 @@ -959,77 +970,54 @@ def test_frame_operators(self, float_frame): assert (df + df).equals(df) tm.assert_frame_equal(df + df, df) - # TODO: taken from tests.series.test_operators; needs cleanup - def test_series_operators(self): - def _check_op(series, other, op, pos_only=False): - left = np.abs(series) if pos_only else series - right = np.abs(other) if pos_only else other - - cython_or_numpy = op(left, right) - python = left.combine(right, op) - if isinstance(other, Series) and not other.index.equals(series.index): - python.index = python.index._with_freq(None) - tm.assert_series_equal(cython_or_numpy, python) - - def check(series, other): - simple_ops = ["add", "sub", "mul", "truediv", "floordiv", "mod"] - - for opname in simple_ops: - _check_op(series, other, getattr(operator, opname)) + @pytest.mark.parametrize( + "func", + [lambda x: x * 2, lambda x: x[::2], lambda x: 5], + ids=["multiply", "slice", "constant"], + ) + def test_series_operators_arithmetic(self, all_arithmetic_functions, func): + op = all_arithmetic_functions + series = tm.makeTimeSeries().rename("ts") + other = func(series) + compare_op(series, other, op) - _check_op(series, other, operator.pow, pos_only=True) + @pytest.mark.parametrize( + "func", [lambda x: x + 1, lambda x: 5], ids=["add", "constant"] + ) + def test_series_operators_compare(self, comparison_op, func): + op = comparison_op + series = tm.makeTimeSeries().rename("ts") + other = func(series) + compare_op(series, other, op) - _check_op(series, other, ops.radd) - _check_op(series, other, ops.rsub) - _check_op(series, other, ops.rtruediv) - _check_op(series, other, ops.rfloordiv) - _check_op(series, other, ops.rmul) - _check_op(series, other, ops.rpow, pos_only=True) - _check_op(series, other, ops.rmod) + @pytest.mark.parametrize( + "func", + [lambda x: x * 2, lambda x: x[::2], lambda x: 5], + ids=["multiply", "slice", "constant"], + ) + def test_divmod(self, func): + series = tm.makeTimeSeries().rename("ts") + other = func(series) + results = divmod(series, other) + if isinstance(other, abc.Iterable) and len(series) != len(other): + # if the lengths don't match, this is the test where we use + # `tser[::2]`. Pad every other value in `other_np` with nan. + other_np = [] + for n in other: + other_np.append(n) + other_np.append(np.nan) + else: + other_np = other + other_np = np.asarray(other_np) + with np.errstate(all="ignore"): + expecteds = divmod(series.values, np.asarray(other_np)) - tser = tm.makeTimeSeries().rename("ts") - check(tser, tser * 2) - check(tser, tser[::2]) - check(tser, 5) - - def check_comparators(series, other): - _check_op(series, other, operator.gt) - _check_op(series, other, operator.ge) - _check_op(series, other, operator.eq) - _check_op(series, other, operator.lt) - _check_op(series, other, operator.le) - - check_comparators(tser, 5) - check_comparators(tser, tser + 1) - - # TODO: taken from tests.series.test_operators; needs cleanup - def test_divmod(self): - def check(series, other): - results = divmod(series, other) - if isinstance(other, abc.Iterable) and len(series) != len(other): - # if the lengths don't match, this is the test where we use - # `tser[::2]`. Pad every other value in `other_np` with nan. - other_np = [] - for n in other: - other_np.append(n) - other_np.append(np.nan) - else: - other_np = other - other_np = np.asarray(other_np) - with np.errstate(all="ignore"): - expecteds = divmod(series.values, np.asarray(other_np)) - - for result, expected in zip(results, expecteds): - # check the values, name, and index separately - tm.assert_almost_equal(np.asarray(result), expected) - - assert result.name == series.name - tm.assert_index_equal(result.index, series.index._with_freq(None)) + for result, expected in zip(results, expecteds): + # check the values, name, and index separately + tm.assert_almost_equal(np.asarray(result), expected) - tser = tm.makeTimeSeries().rename("ts") - check(tser, tser * 2) - check(tser, tser[::2]) - check(tser, 5) + assert result.name == series.name + tm.assert_index_equal(result.index, series.index._with_freq(None)) def test_series_divmod_zero(self): # Check that divmod uses pandas convention for division by zero, diff --git a/pandas/tests/indexing/test_scalar.py b/pandas/tests/indexing/test_scalar.py index bcb76fb078e74..d5268a1b1bc81 100644 --- a/pandas/tests/indexing/test_scalar.py +++ b/pandas/tests/indexing/test_scalar.py @@ -47,31 +47,39 @@ def _check(f, func, values=False): _check(f, "at") @pytest.mark.parametrize("kind", ["series", "frame"]) - def test_at_and_iat_set(self, kind): - def _check(f, func, values=False): + @pytest.mark.parametrize("col", ["ints", "uints"]) + def test_iat_set_ints(self, kind, col): + f = getattr(self, kind)[col] + if f is not None: + indices = self.generate_indices(f, True) + for i in indices: + f.iat[i] = 1 + expected = self.get_value("iat", f, i, True) + tm.assert_almost_equal(expected, 1) - if f is not None: - indices = self.generate_indices(f, values) + @pytest.mark.parametrize("kind", ["series", "frame"]) + @pytest.mark.parametrize("col", ["labels", "ts", "floats"]) + def test_iat_set_other(self, kind, col): + f = getattr(self, kind)[col] + if f is not None: + msg = "iAt based indexing can only have integer indexers" + with pytest.raises(ValueError, match=msg): + indices = self.generate_indices(f, False) for i in indices: - getattr(f, func)[i] = 1 - expected = self.get_value(func, f, i, values) + f.iat[i] = 1 + expected = self.get_value("iat", f, i, False) tm.assert_almost_equal(expected, 1) - d = getattr(self, kind) - - # iat - for f in [d["ints"], d["uints"]]: - _check(f, "iat", values=True) - - for f in [d["labels"], d["ts"], d["floats"]]: - if f is not None: - msg = "iAt based indexing can only have integer indexers" - with pytest.raises(ValueError, match=msg): - _check(f, "iat") - - # at - for f in [d["ints"], d["uints"], d["labels"], d["ts"], d["floats"]]: - _check(f, "at") + @pytest.mark.parametrize("kind", ["series", "frame"]) + @pytest.mark.parametrize("col", ["ints", "uints", "labels", "ts", "floats"]) + def test_at_set_ints_other(self, kind, col): + f = getattr(self, kind)[col] + if f is not None: + indices = self.generate_indices(f, False) + for i in indices: + f.at[i] = 1 + expected = self.get_value("at", f, i, False) + tm.assert_almost_equal(expected, 1) class TestAtAndiAT: diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index 008731b13172e..1c34b5c8e5475 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -91,63 +91,56 @@ def test_properties_business(self): assert control.is_month_end assert control.is_quarter_end - def test_fields(self): - def check(value, equal): - # that we are int like - assert isinstance(value, int) - assert value == equal - + @pytest.mark.parametrize( + "attr, expected", + [ + ["year", 2014], + ["month", 12], + ["day", 31], + ["hour", 23], + ["minute", 59], + ["second", 0], + ["microsecond", 0], + ["nanosecond", 0], + ["dayofweek", 2], + ["day_of_week", 2], + ["quarter", 4], + ["dayofyear", 365], + ["day_of_year", 365], + ["week", 1], + ["daysinmonth", 31], + ], + ) + @pytest.mark.parametrize("tz", [None, "US/Eastern"]) + def test_fields(self, attr, expected, tz): # GH 10050 - ts = Timestamp("2015-05-10 09:06:03.000100001") - check(ts.year, 2015) - check(ts.month, 5) - check(ts.day, 10) - check(ts.hour, 9) - check(ts.minute, 6) - check(ts.second, 3) - msg = "'Timestamp' object has no attribute 'millisecond'" - with pytest.raises(AttributeError, match=msg): - ts.millisecond - check(ts.microsecond, 100) - check(ts.nanosecond, 1) - check(ts.dayofweek, 6) - check(ts.day_of_week, 6) - check(ts.quarter, 2) - check(ts.dayofyear, 130) - check(ts.day_of_year, 130) - check(ts.week, 19) - check(ts.daysinmonth, 31) - check(ts.daysinmonth, 31) - # GH 13303 - ts = Timestamp("2014-12-31 23:59:00-05:00", tz="US/Eastern") - check(ts.year, 2014) - check(ts.month, 12) - check(ts.day, 31) - check(ts.hour, 23) - check(ts.minute, 59) - check(ts.second, 0) + ts = Timestamp("2014-12-31 23:59:00", tz=tz) + result = getattr(ts, attr) + # that we are int like + assert isinstance(result, int) + assert result == expected + + @pytest.mark.parametrize("tz", [None, "US/Eastern"]) + def test_millisecond_raises(self, tz): + ts = Timestamp("2014-12-31 23:59:00", tz=tz) msg = "'Timestamp' object has no attribute 'millisecond'" with pytest.raises(AttributeError, match=msg): ts.millisecond - check(ts.microsecond, 0) - check(ts.nanosecond, 0) - check(ts.dayofweek, 2) - check(ts.day_of_week, 2) - check(ts.quarter, 4) - check(ts.dayofyear, 365) - check(ts.day_of_year, 365) - check(ts.week, 1) - check(ts.daysinmonth, 31) - - ts = Timestamp("2014-01-01 00:00:00+01:00") - starts = ["is_month_start", "is_quarter_start", "is_year_start"] - for start in starts: - assert getattr(ts, start) - ts = Timestamp("2014-12-31 23:59:59+01:00") - ends = ["is_month_end", "is_year_end", "is_quarter_end"] - for end in ends: - assert getattr(ts, end) + + @pytest.mark.parametrize( + "start", ["is_month_start", "is_quarter_start", "is_year_start"] + ) + @pytest.mark.parametrize("tz", [None, "US/Eastern"]) + def test_is_start(self, start, tz): + ts = Timestamp("2014-01-01 00:00:00", tz=tz) + assert getattr(ts, start) + + @pytest.mark.parametrize("end", ["is_month_end", "is_year_end", "is_quarter_end"]) + @pytest.mark.parametrize("tz", [None, "US/Eastern"]) + def test_is_end(self, end, tz): + ts = Timestamp("2014-12-31 23:59:59", tz=tz) + assert getattr(ts, end) # GH 12806 @pytest.mark.parametrize(