From f592fb4c3b95efe82ae9f6bc2a63c4e836a8ef2a Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 14 Dec 2021 08:33:20 -0800 Subject: [PATCH 1/5] CLN: simplify tm helpers --- asv_bench/benchmarks/arithmetic.py | 2 +- pandas/_testing/__init__.py | 36 +++++---------------- pandas/core/arrays/datetimelike.py | 2 +- pandas/core/arrays/datetimes.py | 2 +- pandas/core/arrays/period.py | 2 +- pandas/core/arrays/timedeltas.py | 2 +- pandas/core/dtypes/cast.py | 2 +- pandas/core/dtypes/common.py | 4 +-- pandas/core/indexes/base.py | 2 +- pandas/core/indexes/interval.py | 2 +- pandas/core/indexes/multi.py | 2 +- pandas/core/indexes/numeric.py | 2 +- pandas/tests/arithmetic/test_datetime64.py | 8 ----- pandas/tests/arithmetic/test_timedelta64.py | 20 ++++++------ pandas/tests/internals/test_internals.py | 6 ++-- pandas/tests/io/pytables/test_select.py | 4 +-- pandas/tseries/holiday.py | 2 +- 17 files changed, 36 insertions(+), 64 deletions(-) diff --git a/asv_bench/benchmarks/arithmetic.py b/asv_bench/benchmarks/arithmetic.py index bfb1be8705495..edd1132116f76 100644 --- a/asv_bench/benchmarks/arithmetic.py +++ b/asv_bench/benchmarks/arithmetic.py @@ -144,7 +144,7 @@ def setup(self, op, shape): # should already be the case, but just to be sure df._consolidate_inplace() - # TODO: GH#33198 the setting here shoudlnt need two steps + # TODO: GH#33198 the setting here shouldn't need two steps arr1 = np.random.randn(n_rows, max(n_cols // 4, 3)).astype("f8") arr2 = np.random.randn(n_rows, n_cols // 2).astype("i8") arr3 = np.random.randn(n_rows, n_cols // 4).astype("f8") diff --git a/pandas/_testing/__init__.py b/pandas/_testing/__init__.py index 16094bd88d66f..a3ef89e98a2ba 100644 --- a/pandas/_testing/__init__.py +++ b/pandas/_testing/__init__.py @@ -28,17 +28,12 @@ from pandas._typing import Dtype from pandas.core.dtypes.common import ( - is_datetime64_dtype, - is_datetime64tz_dtype, is_float_dtype, is_integer_dtype, - is_period_dtype, is_sequence, - is_timedelta64_dtype, is_unsigned_integer_dtype, pandas_dtype, ) -from pandas.core.dtypes.dtypes import IntervalDtype import pandas as pd from pandas import ( @@ -112,14 +107,11 @@ ) from pandas.core.arrays import ( BaseMaskedArray, - DatetimeArray, ExtensionArray, PandasArray, - PeriodArray, - TimedeltaArray, - period_array, ) from pandas.core.arrays._mixins import NDArrayBackedExtensionArray +from pandas.core.construction import extract_array if TYPE_CHECKING: from pandas import ( @@ -257,13 +249,6 @@ def box_expected(expected, box_cls, transpose=True): # single-row special cases in datetime arithmetic expected = expected.T expected = pd.concat([expected] * 2, ignore_index=True) - elif box_cls is PeriodArray: - # the PeriodArray constructor is not as flexible as period_array - expected = period_array(expected) - elif box_cls is DatetimeArray: - expected = DatetimeArray(expected) - elif box_cls is TimedeltaArray: - expected = TimedeltaArray(expected) elif box_cls is np.ndarray or box_cls is np.array: expected = np.array(expected) elif box_cls is to_array: @@ -277,18 +262,9 @@ def to_array(obj): # temporary implementation until we get pd.array in place dtype = getattr(obj, "dtype", None) - if is_period_dtype(dtype): - return period_array(obj) - elif is_datetime64_dtype(dtype) or is_datetime64tz_dtype(dtype): - return DatetimeArray._from_sequence(obj) - elif is_timedelta64_dtype(dtype): - return TimedeltaArray._from_sequence(obj) - elif isinstance(obj, pd.core.arrays.BooleanArray): - return obj - elif isinstance(dtype, IntervalDtype): - return pd.core.arrays.IntervalArray(obj) - else: - return np.array(obj) + if dtype is None: + return np.asarray(obj) + return extract_array(obj, extract_numpy=True) # ----------------------------------------------------------------------------- @@ -1092,6 +1068,10 @@ def shares_memory(left, right) -> bool: left_pa_data = left._data # type: ignore[attr-defined] # error: "ExtensionArray" has no attribute "_data" right_pa_data = right._data # type: ignore[attr-defined] + + if len(left_pa_data.chunks) != 1 or len(right_pa_data.chunks) != 1: + raise NotImplementedError + left_buf1 = left_pa_data.chunk(0).buffers()[1] right_buf1 = right_pa_data.chunk(0).buffers()[1] return left_buf1 == right_buf1 diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 989abe69a5cc7..6fcba99773607 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -291,7 +291,7 @@ def asi8(self) -> npt.NDArray[np.int64]: # ---------------------------------------------------------------- # Rendering Methods - def _format_native_types(self, na_rep="NaT", date_format=None): + def _format_native_types(self, *, na_rep="NaT", date_format=None): """ Helper method for astype when converting to strings. diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 7bd3403abd5cc..b3a1a4d342355 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -670,7 +670,7 @@ def astype(self, dtype, copy: bool = True): @dtl.ravel_compat def _format_native_types( - self, na_rep="NaT", date_format=None, **kwargs + self, *, na_rep="NaT", date_format=None, **kwargs ) -> npt.NDArray[np.object_]: from pandas.io.formats.format import get_format_datetime64_from_values diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index 01018c7263f32..6112ccccb89ff 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -632,7 +632,7 @@ def _formatter(self, boxed: bool = False): @dtl.ravel_compat def _format_native_types( - self, na_rep="NaT", date_format=None, **kwargs + self, *, na_rep="NaT", date_format=None, **kwargs ) -> np.ndarray: """ actually format my specific types diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 8fe330d0d41dd..4e58ebc518bb4 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -426,7 +426,7 @@ def _formatter(self, boxed: bool = False): @dtl.ravel_compat def _format_native_types( - self, na_rep="NaT", date_format=None, **kwargs + self, *, na_rep="NaT", date_format=None, **kwargs ) -> np.ndarray: from pandas.io.formats.format import get_format_timedelta64 diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py index 3b04490ae098c..b70ea9f816aef 100644 --- a/pandas/core/dtypes/cast.py +++ b/pandas/core/dtypes/cast.py @@ -248,7 +248,7 @@ def maybe_downcast_to_dtype(result: ArrayLike, dtype: str | np.dtype) -> ArrayLi if isinstance(dtype, str): if dtype == "infer": - inferred_type = lib.infer_dtype(ensure_object(result), skipna=False) + inferred_type = lib.infer_dtype(result, skipna=False) if inferred_type == "boolean": dtype = "bool" elif inferred_type == "integer": diff --git a/pandas/core/dtypes/common.py b/pandas/core/dtypes/common.py index b5be0263c492a..b4b08bfe381bd 100644 --- a/pandas/core/dtypes/common.py +++ b/pandas/core/dtypes/common.py @@ -1318,7 +1318,7 @@ def is_bool_dtype(arr_or_dtype) -> bool: except (TypeError, ValueError): return False - if isinstance(arr_or_dtype, CategoricalDtype): + if isinstance(dtype, CategoricalDtype): arr_or_dtype = arr_or_dtype.categories # now we use the special definition for Index @@ -1329,7 +1329,7 @@ def is_bool_dtype(arr_or_dtype) -> bool: # so its object, we need to infer to # guess this return arr_or_dtype.is_object() and arr_or_dtype.inferred_type == "boolean" - elif is_extension_array_dtype(arr_or_dtype): + elif isinstance(dtype, ExtensionDtype): return getattr(dtype, "_is_boolean", False) return issubclass(dtype.type, np.bool_) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 54a13c124c13a..1fa03f93bee4c 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1387,7 +1387,7 @@ def to_native_types(self, slicer=None, **kwargs) -> np.ndarray: values = values[slicer] return values._format_native_types(**kwargs) - def _format_native_types(self, na_rep="", quoting=None, **kwargs): + def _format_native_types(self, *, na_rep="", quoting=None, **kwargs): """ Actually format specific types of the index. """ diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 6d355f1375069..a378fd95b9c03 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -812,7 +812,7 @@ def _format_with_header(self, header: list[str], na_rep: str) -> list[str]: # matches base class except for whitespace padding return header + list(self._format_native_types(na_rep=na_rep)) - def _format_native_types(self, na_rep="NaN", quoting=None, **kwargs): + def _format_native_types(self, *, na_rep="NaN", quoting=None, **kwargs): # GH 28210: use base method but with different default na_rep return super()._format_native_types(na_rep=na_rep, quoting=quoting, **kwargs) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 88b37ffaa9493..448e1d62ba1f2 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -1283,7 +1283,7 @@ def _formatter_func(self, tup): formatter_funcs = [level._formatter_func for level in self.levels] return tuple(func(val) for func, val in zip(formatter_funcs, tup)) - def _format_native_types(self, na_rep="nan", **kwargs): + def _format_native_types(self, *, na_rep="nan", **kwargs): new_levels = [] new_codes = [] diff --git a/pandas/core/indexes/numeric.py b/pandas/core/indexes/numeric.py index 477d4bfc3290b..bb25813e9742b 100644 --- a/pandas/core/indexes/numeric.py +++ b/pandas/core/indexes/numeric.py @@ -343,7 +343,7 @@ def _is_all_dates(self) -> bool: return False def _format_native_types( - self, na_rep="", float_format=None, decimal=".", quoting=None, **kwargs + self, *, na_rep="", float_format=None, decimal=".", quoting=None, **kwargs ): from pandas.io.formats.format import FloatArrayFormatter diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index 49585f3d37924..553fb9d473507 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -229,10 +229,6 @@ def test_nat_comparisons( @pytest.mark.parametrize("dtype", [None, object]) def test_nat_comparisons_scalar(self, dtype, data, box_with_array): box = box_with_array - if box_with_array is tm.to_array and dtype is object: - # dont bother testing ndarray comparison methods as this fails - # on older numpys (since they check object identity) - return left = Series(data, dtype=dtype) left = tm.box_expected(left, box) @@ -434,10 +430,6 @@ def test_dti_cmp_datetimelike(self, other, tz_naive_fixture): @pytest.mark.parametrize("dtype", [None, object]) def test_dti_cmp_nat(self, dtype, box_with_array): - if box_with_array is tm.to_array and dtype is object: - # dont bother testing ndarray comparison methods as this fails - # on older numpys (since they check object identity) - return left = DatetimeIndex([Timestamp("2011-01-01"), NaT, Timestamp("2011-01-03")]) right = DatetimeIndex([NaT, NaT, Timestamp("2011-01-03")]) diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index 29c01e45ed28d..6234c2957e9a5 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -2060,18 +2060,16 @@ def test_td64arr_div_numeric_array( with pytest.raises(TypeError, match=pattern): vector / tdser - if not isinstance(vector, pd.Index): - # Index.__rdiv__ won't try to operate elementwise, just raises - result = tdser / vector.astype(object) - if box_with_array is DataFrame: - expected = [tdser.iloc[0, n] / vector[n] for n in range(len(vector))] - else: - expected = [tdser[n] / vector[n] for n in range(len(tdser))] - expected = pd.Index(expected) # do dtype inference - expected = tm.box_expected(expected, xbox) - assert tm.get_dtype(expected) == "m8[ns]" + result = tdser / vector.astype(object) + if box_with_array is DataFrame: + expected = [tdser.iloc[0, n] / vector[n] for n in range(len(vector))] + else: + expected = [tdser[n] / vector[n] for n in range(len(tdser))] + expected = pd.Index(expected) # do dtype inference + expected = tm.box_expected(expected, xbox) + assert tm.get_dtype(expected) == "m8[ns]" - tm.assert_equal(result, expected) + tm.assert_equal(result, expected) with pytest.raises(TypeError, match=pattern): vector.astype(object) / tdser diff --git a/pandas/tests/internals/test_internals.py b/pandas/tests/internals/test_internals.py index b9b36f828c357..199c4e64f18fd 100644 --- a/pandas/tests/internals/test_internals.py +++ b/pandas/tests/internals/test_internals.py @@ -149,8 +149,10 @@ def create_block(typestr, placement, item_shape=None, num_offset=0, maker=new_bl elif typestr in ("category2",): values = Categorical(["a", "a", "a", "a", "b", "b", "c", "c", "c", "d"]) elif typestr in ("sparse", "sparse_na"): - # FIXME: doesn't support num_rows != 10 - assert shape[-1] == 10 + if shape[-1] != 10: + # We also are implicitly assuming this in the category cases above + raise NotImplementedError + assert all(s == 1 for s in shape[:-1]) if typestr.endswith("_na"): fill_value = np.nan diff --git a/pandas/tests/io/pytables/test_select.py b/pandas/tests/io/pytables/test_select.py index fc8d4506abda0..b644c3420150c 100644 --- a/pandas/tests/io/pytables/test_select.py +++ b/pandas/tests/io/pytables/test_select.py @@ -188,12 +188,12 @@ def test_select_dtypes(setup_path): _maybe_remove(store, "df") store.append("df", df, data_columns=True) - expected = df[df.boolv == True].reindex(columns=["A", "boolv"]) # noqa + expected = df[df.boolv == True].reindex(columns=["A", "boolv"]) # noqa:E712 for v in [True, "true", 1]: result = store.select("df", f"boolv == {v}", columns=["A", "boolv"]) tm.assert_frame_equal(expected, result) - expected = df[df.boolv == False].reindex(columns=["A", "boolv"]) # noqa + expected = df[df.boolv == False].reindex(columns=["A", "boolv"]) # noqa:E712 for v in [False, "false", 0]: result = store.select("df", f"boolv == {v}", columns=["A", "boolv"]) tm.assert_frame_equal(expected, result) diff --git a/pandas/tseries/holiday.py b/pandas/tseries/holiday.py index 0e3a3f3fb6c18..10b09cbc34443 100644 --- a/pandas/tseries/holiday.py +++ b/pandas/tseries/holiday.py @@ -6,7 +6,7 @@ ) import warnings -from dateutil.relativedelta import ( # noqa +from dateutil.relativedelta import ( # noqa:F401 FR, MO, SA, From 4c2284e1ab5407d0865ab421fb2e75d4bffd5f4a Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 14 Dec 2021 11:18:30 -0800 Subject: [PATCH 2/5] revert bit split off into 44884 --- pandas/_testing/__init__.py | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/pandas/_testing/__init__.py b/pandas/_testing/__init__.py index a3ef89e98a2ba..16094bd88d66f 100644 --- a/pandas/_testing/__init__.py +++ b/pandas/_testing/__init__.py @@ -28,12 +28,17 @@ from pandas._typing import Dtype from pandas.core.dtypes.common import ( + is_datetime64_dtype, + is_datetime64tz_dtype, is_float_dtype, is_integer_dtype, + is_period_dtype, is_sequence, + is_timedelta64_dtype, is_unsigned_integer_dtype, pandas_dtype, ) +from pandas.core.dtypes.dtypes import IntervalDtype import pandas as pd from pandas import ( @@ -107,11 +112,14 @@ ) from pandas.core.arrays import ( BaseMaskedArray, + DatetimeArray, ExtensionArray, PandasArray, + PeriodArray, + TimedeltaArray, + period_array, ) from pandas.core.arrays._mixins import NDArrayBackedExtensionArray -from pandas.core.construction import extract_array if TYPE_CHECKING: from pandas import ( @@ -249,6 +257,13 @@ def box_expected(expected, box_cls, transpose=True): # single-row special cases in datetime arithmetic expected = expected.T expected = pd.concat([expected] * 2, ignore_index=True) + elif box_cls is PeriodArray: + # the PeriodArray constructor is not as flexible as period_array + expected = period_array(expected) + elif box_cls is DatetimeArray: + expected = DatetimeArray(expected) + elif box_cls is TimedeltaArray: + expected = TimedeltaArray(expected) elif box_cls is np.ndarray or box_cls is np.array: expected = np.array(expected) elif box_cls is to_array: @@ -262,9 +277,18 @@ def to_array(obj): # temporary implementation until we get pd.array in place dtype = getattr(obj, "dtype", None) - if dtype is None: - return np.asarray(obj) - return extract_array(obj, extract_numpy=True) + if is_period_dtype(dtype): + return period_array(obj) + elif is_datetime64_dtype(dtype) or is_datetime64tz_dtype(dtype): + return DatetimeArray._from_sequence(obj) + elif is_timedelta64_dtype(dtype): + return TimedeltaArray._from_sequence(obj) + elif isinstance(obj, pd.core.arrays.BooleanArray): + return obj + elif isinstance(dtype, IntervalDtype): + return pd.core.arrays.IntervalArray(obj) + else: + return np.array(obj) # ----------------------------------------------------------------------------- @@ -1068,10 +1092,6 @@ def shares_memory(left, right) -> bool: left_pa_data = left._data # type: ignore[attr-defined] # error: "ExtensionArray" has no attribute "_data" right_pa_data = right._data # type: ignore[attr-defined] - - if len(left_pa_data.chunks) != 1 or len(right_pa_data.chunks) != 1: - raise NotImplementedError - left_buf1 = left_pa_data.chunk(0).buffers()[1] right_buf1 = right_pa_data.chunk(0).buffers()[1] return left_buf1 == right_buf1 From d33231c8ff067b08f9a983fc7ed870f5d9fefb72 Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 14 Dec 2021 11:47:24 -0800 Subject: [PATCH 3/5] TST: skip less --- pandas/tests/tools/test_to_time.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pandas/tests/tools/test_to_time.py b/pandas/tests/tools/test_to_time.py index 317b6daf05bc9..195a3ee2b2678 100644 --- a/pandas/tests/tools/test_to_time.py +++ b/pandas/tests/tools/test_to_time.py @@ -3,8 +3,6 @@ import numpy as np import pytest -import pandas.util._test_decorators as td - from pandas import Series import pandas._testing as tm from pandas.core.tools.datetimes import to_time as to_time_alias @@ -12,7 +10,6 @@ class TestToTime: - @td.skip_if_has_locale @pytest.mark.parametrize( "time_string", [ @@ -31,7 +28,6 @@ def test_parsers_time(self, time_string): # GH#11818 assert to_time(time_string) == time(14, 15) - @td.skip_if_has_locale def test_odd_format(self): new_string = "14.15" msg = r"Cannot convert arg \['14\.15'\] to a time" @@ -39,7 +35,6 @@ def test_odd_format(self): to_time(new_string) assert to_time(new_string, format="%H.%M") == time(14, 15) - @td.skip_if_has_locale def test_arraylike(self): arg = ["14:15", "20:20"] expected_arr = [time(14, 15), time(20, 20)] From 33bb1d26c4c0ba8d0e178694feb476af27401f7d Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 14 Dec 2021 14:25:15 -0800 Subject: [PATCH 4/5] CLN/TST: parametrize --- pandas/compat/pickle_compat.py | 3 -- pandas/core/api.py | 2 +- pandas/core/computation/api.py | 3 +- pandas/core/dtypes/api.py | 2 +- pandas/core/reshape/api.py | 2 +- pandas/errors/__init__.py | 6 +-- pandas/tests/arithmetic/test_numeric.py | 6 +-- pandas/tests/arithmetic/test_period.py | 54 +++++++++++++-------- pandas/tests/arithmetic/test_timedelta64.py | 17 +++---- pandas/tests/test_common.py | 4 +- 10 files changed, 54 insertions(+), 45 deletions(-) diff --git a/pandas/compat/pickle_compat.py b/pandas/compat/pickle_compat.py index ca539eefd3aee..61d3b2ef079ac 100644 --- a/pandas/compat/pickle_compat.py +++ b/pandas/compat/pickle_compat.py @@ -35,9 +35,6 @@ def load_reduce(self): args = stack.pop() func = stack[-1] - if len(args) and type(args[0]) is type: - n = args[0].__name__ # noqa - try: stack[-1] = func(*args) return diff --git a/pandas/core/api.py b/pandas/core/api.py index a03293ce13144..cf082d2013d3b 100644 --- a/pandas/core/api.py +++ b/pandas/core/api.py @@ -1,4 +1,4 @@ -# flake8: noqa +# flake8: noqa:F401 from pandas._libs import ( NaT, diff --git a/pandas/core/computation/api.py b/pandas/core/computation/api.py index 31e8a4873b0ad..bd3be5b3f8c42 100644 --- a/pandas/core/computation/api.py +++ b/pandas/core/computation/api.py @@ -1,3 +1,2 @@ -# flake8: noqa - +__all__ = ["eval"] from pandas.core.computation.eval import eval diff --git a/pandas/core/dtypes/api.py b/pandas/core/dtypes/api.py index 051affd0af1f9..bb6bfda183802 100644 --- a/pandas/core/dtypes/api.py +++ b/pandas/core/dtypes/api.py @@ -1,4 +1,4 @@ -# flake8: noqa +# flake8: noqa:F401 from pandas.core.dtypes.common import ( is_array_like, diff --git a/pandas/core/reshape/api.py b/pandas/core/reshape/api.py index 58d741c2c6988..bffdadb96c972 100644 --- a/pandas/core/reshape/api.py +++ b/pandas/core/reshape/api.py @@ -1,4 +1,4 @@ -# flake8: noqa +# flake8: noqa:F401 from pandas.core.reshape.concat import concat from pandas.core.reshape.melt import ( diff --git a/pandas/errors/__init__.py b/pandas/errors/__init__.py index 8fae2d1d1179d..cbe94673a8122 100644 --- a/pandas/errors/__init__.py +++ b/pandas/errors/__init__.py @@ -1,12 +1,10 @@ -# flake8: noqa - """ Expose public exceptions & warnings """ -from pandas._config.config import OptionError +from pandas._config.config import OptionError # noqa:F401 -from pandas._libs.tslibs import ( +from pandas._libs.tslibs import ( # noqa:F401 OutOfBoundsDatetime, OutOfBoundsTimedelta, ) diff --git a/pandas/tests/arithmetic/test_numeric.py b/pandas/tests/arithmetic/test_numeric.py index 4935151ec986e..552e24fe15ca9 100644 --- a/pandas/tests/arithmetic/test_numeric.py +++ b/pandas/tests/arithmetic/test_numeric.py @@ -128,8 +128,6 @@ def test_numeric_cmp_string_numexpr_path(self, box_with_array): class TestNumericArraylikeArithmeticWithDatetimeLike: - - # TODO: also check name retentention @pytest.mark.parametrize("box_cls", [np.array, Index, Series]) @pytest.mark.parametrize( "left", lefts, ids=lambda x: type(x).__name__ + str(x.dtype) @@ -149,7 +147,6 @@ def test_mul_td64arr(self, left, box_cls): result = right * left tm.assert_equal(result, expected) - # TODO: also check name retentention @pytest.mark.parametrize("box_cls", [np.array, Index, Series]) @pytest.mark.parametrize( "left", lefts, ids=lambda x: type(x).__name__ + str(x.dtype) @@ -1241,7 +1238,7 @@ def test_binops_pow(self): idxs = [RangeIndex(0, 10, 1), RangeIndex(0, 20, 2)] self.check_binop(ops, scalars, idxs) - # TODO: mod, divmod? + # TODO: divmod? @pytest.mark.parametrize( "op", [ @@ -1251,6 +1248,7 @@ def test_binops_pow(self): operator.floordiv, operator.truediv, operator.pow, + operator.mod, ], ) def test_arithmetic_with_frame_or_series(self, op): diff --git a/pandas/tests/arithmetic/test_period.py b/pandas/tests/arithmetic/test_period.py index 97f6aa3872c81..c31556064eece 100644 --- a/pandas/tests/arithmetic/test_period.py +++ b/pandas/tests/arithmetic/test_period.py @@ -636,12 +636,12 @@ def test_pi_sub_pi_with_nat(self): expected = pd.Index([pd.NaT, 0 * off, 0 * off, 0 * off, 0 * off]) tm.assert_index_equal(result, expected) - def test_parr_sub_pi_mismatched_freq(self, box_with_array): + def test_parr_sub_pi_mismatched_freq(self, box_with_array, box_with_array2): rng = period_range("1/1/2000", freq="D", periods=5) other = period_range("1/6/2000", freq="H", periods=5) - # TODO: parametrize over boxes for other? rng = tm.box_expected(rng, box_with_array) + other = tm.box_expected(other, box_with_array2) msg = r"Input has different freq=[HD] from PeriodArray\(freq=[DH]\)" with pytest.raises(IncompatibleFrequency, match=msg): rng - other @@ -998,58 +998,67 @@ def test_pi_sub_intarray(self, int_holder): # Timedelta-like (timedelta, timedelta64, Timedelta, Tick) # TODO: Some of these are misnomers because of non-Tick DateOffsets - def test_pi_add_timedeltalike_minute_gt1(self, three_days): + def test_parr_add_timedeltalike_minute_gt1(self, three_days, box_with_array): # GH#23031 adding a time-delta-like offset to a PeriodArray that has # minute frequency with n != 1. A more general case is tested below # in test_pi_add_timedeltalike_tick_gt1, but here we write out the # expected result more explicitly. other = three_days rng = period_range("2014-05-01", periods=3, freq="2D") + rng = tm.box_expected(rng, box_with_array) expected = PeriodIndex(["2014-05-04", "2014-05-06", "2014-05-08"], freq="2D") + expected = tm.box_expected(expected, box_with_array) result = rng + other - tm.assert_index_equal(result, expected) + tm.assert_equal(result, expected) result = other + rng - tm.assert_index_equal(result, expected) + tm.assert_equal(result, expected) # subtraction expected = PeriodIndex(["2014-04-28", "2014-04-30", "2014-05-02"], freq="2D") + expected = tm.box_expected(expected, box_with_array) result = rng - other - tm.assert_index_equal(result, expected) + tm.assert_equal(result, expected) msg = "|".join( [ - r"(:?bad operand type for unary -: 'PeriodArray')", - r"(:?cannot subtract PeriodArray from timedelta64\[[hD]\])", + r"bad operand type for unary -: 'PeriodArray'", + r"cannot subtract PeriodArray from timedelta64\[[hD]\]", ] ) with pytest.raises(TypeError, match=msg): other - rng @pytest.mark.parametrize("freqstr", ["5ns", "5us", "5ms", "5s", "5T", "5h", "5d"]) - def test_pi_add_timedeltalike_tick_gt1(self, three_days, freqstr): + def test_parr_add_timedeltalike_tick_gt1(self, three_days, freqstr, box_with_array): # GH#23031 adding a time-delta-like offset to a PeriodArray that has # tick-like frequency with n != 1 other = three_days rng = period_range("2014-05-01", periods=6, freq=freqstr) + first = rng[0] + rng = tm.box_expected(rng, box_with_array) - expected = period_range(rng[0] + other, periods=6, freq=freqstr) + expected = period_range(first + other, periods=6, freq=freqstr) + expected = tm.box_expected(expected, box_with_array) result = rng + other - tm.assert_index_equal(result, expected) + tm.assert_equal(result, expected) result = other + rng - tm.assert_index_equal(result, expected) + tm.assert_equal(result, expected) # subtraction - expected = period_range(rng[0] - other, periods=6, freq=freqstr) + expected = period_range(first - other, periods=6, freq=freqstr) + expected = tm.box_expected(expected, box_with_array) result = rng - other - tm.assert_index_equal(result, expected) - msg = ( - r"(:?bad operand type for unary -: 'PeriodArray')" - r"|(:?cannot subtract PeriodArray from timedelta64\[[hD]\])" + tm.assert_equal(result, expected) + msg = "|".join( + [ + r"bad operand type for unary -: 'PeriodArray'", + r"cannot subtract PeriodArray from timedelta64\[[hD]\]", + ] ) with pytest.raises(TypeError, match=msg): other - rng @@ -1078,9 +1087,13 @@ def test_pi_sub_isub_timedeltalike_daily(self, three_days): rng -= other tm.assert_index_equal(rng, expected) - def test_pi_add_sub_timedeltalike_freq_mismatch_daily(self, not_daily): + def test_parr_add_sub_timedeltalike_freq_mismatch_daily( + self, not_daily, box_with_array + ): other = not_daily rng = period_range("2014-05-01", "2014-05-15", freq="D") + rng = tm.box_expected(rng, box_with_array) + msg = "Input has different freq(=.+)? from Period.*?\\(freq=D\\)" with pytest.raises(IncompatibleFrequency, match=msg): rng + other @@ -1102,9 +1115,12 @@ def test_pi_add_iadd_timedeltalike_hourly(self, two_hours): rng += other tm.assert_index_equal(rng, expected) - def test_pi_add_timedeltalike_mismatched_freq_hourly(self, not_hourly): + def test_parr_add_timedeltalike_mismatched_freq_hourly( + self, not_hourly, box_with_array + ): other = not_hourly rng = period_range("2014-01-01 10:00", "2014-01-05 10:00", freq="H") + rng = tm.box_expected(rng, box_with_array) msg = "Input has different freq(=.+)? from Period.*?\\(freq=H\\)" with pytest.raises(IncompatibleFrequency, match=msg): diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index 6234c2957e9a5..765708bd195dd 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -1099,21 +1099,24 @@ def test_td64arr_add_datetime64_nat(self, box_with_array): @pytest.mark.parametrize("pi_freq", ["D", "W", "Q", "H"]) @pytest.mark.parametrize("tdi_freq", [None, "H"]) - def test_td64arr_sub_periodlike(self, box_with_array, tdi_freq, pi_freq): + def test_td64arr_sub_periodlike( + self, box_with_array, box_with_array2, tdi_freq, pi_freq + ): # GH#20049 subtracting PeriodIndex should raise TypeError tdi = TimedeltaIndex(["1 hours", "2 hours"], freq=tdi_freq) dti = Timestamp("2018-03-07 17:16:40") + tdi pi = dti.to_period(pi_freq) + per = pi[0] - # TODO: parametrize over box for pi? tdi = tm.box_expected(tdi, box_with_array) + pi = tm.box_expected(pi, box_with_array2) msg = "cannot subtract|unsupported operand type" with pytest.raises(TypeError, match=msg): tdi - pi # GH#13078 subtraction of Period scalar not supported with pytest.raises(TypeError, match=msg): - tdi - pi[0] + tdi - per @pytest.mark.parametrize( "other", @@ -2099,12 +2102,8 @@ def test_td64arr_mul_int_series(self, box_with_array, names): result = ser * tdi tm.assert_equal(result, expected) - # The direct operation tdi * ser still needs to be fixed. - result = ser.__rmul__(tdi) - if box is DataFrame: - assert result is NotImplemented - else: - tm.assert_equal(result, expected) + result = tdi * ser + tm.assert_equal(result, expected) # TODO: Should we be parametrizing over types for `ser` too? def test_float_series_rdiv_td64arr(self, box_with_array, names): diff --git a/pandas/tests/test_common.py b/pandas/tests/test_common.py index f81e3d61c8ba5..0850ba66bbdbd 100644 --- a/pandas/tests/test_common.py +++ b/pandas/tests/test_common.py @@ -25,7 +25,9 @@ def fn(x): class somecall: def __call__(self): - return x # noqa + # This shouldn't actually get called below; somecall.__init__ + # should. + raise NotImplementedError assert getname(fn) == "fn" assert getname(lambda_) From 85714861b1b4be2ee089233a33ebb806dbe28b94 Mon Sep 17 00:00:00 2001 From: Brock Date: Tue, 14 Dec 2021 16:32:36 -0800 Subject: [PATCH 5/5] xfail on zh_CN --- pandas/tests/tools/test_to_time.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pandas/tests/tools/test_to_time.py b/pandas/tests/tools/test_to_time.py index 195a3ee2b2678..968102ce9edde 100644 --- a/pandas/tests/tools/test_to_time.py +++ b/pandas/tests/tools/test_to_time.py @@ -1,4 +1,5 @@ from datetime import time +import locale import numpy as np import pytest @@ -8,6 +9,11 @@ from pandas.core.tools.datetimes import to_time as to_time_alias from pandas.core.tools.times import to_time +fails_on_zh_cn = pytest.mark.xfail( + locale.getlocale()[0] == "zh_CN", + reason="fail on a CI build with LC_ALL=zh_CN.utf8", +) + class TestToTime: @pytest.mark.parametrize( @@ -15,12 +21,12 @@ class TestToTime: [ "14:15", "1415", - "2:15pm", - "0215pm", + pytest.param("2:15pm", marks=fails_on_zh_cn), + pytest.param("0215pm", marks=fails_on_zh_cn), "14:15:00", "141500", - "2:15:00pm", - "021500pm", + pytest.param("2:15:00pm", marks=fails_on_zh_cn), + pytest.param("021500pm", marks=fails_on_zh_cn), time(14, 15), ], )