diff --git a/pandas/tests/indexes/categorical/test_category.py b/pandas/tests/indexes/categorical/test_category.py index d7fdbb39f3e69..232d966e39a01 100644 --- a/pandas/tests/indexes/categorical/test_category.py +++ b/pandas/tests/indexes/categorical/test_category.py @@ -14,27 +14,15 @@ CategoricalIndex, Index, ) -from pandas.tests.indexes.common import Base -class TestCategoricalIndex(Base): - _index_cls = CategoricalIndex - +class TestCategoricalIndex: @pytest.fixture def simple_index(self) -> CategoricalIndex: - return self._index_cls(list("aabbca"), categories=list("cab"), ordered=False) - - @pytest.fixture - def index(self): - return tm.makeCategoricalIndex(100) - - def create_index(self, *, categories=None, ordered=False): - if categories is None: - categories = list("cab") - return CategoricalIndex(list("aabbca"), categories=categories, ordered=ordered) + return CategoricalIndex(list("aabbca"), categories=list("cab"), ordered=False) def test_can_hold_identifiers(self): - idx = self.create_index(categories=list("abcd")) + idx = CategoricalIndex(list("aabbca"), categories=None, ordered=False) key = idx[0] assert idx._can_hold_identifiers_and_holds_name(key) is True @@ -247,12 +235,13 @@ def test_identical(self): assert ci1.identical(ci1.copy()) assert not ci1.identical(ci2) - def test_ensure_copied_data(self, index): + def test_ensure_copied_data(self): # gh-12309: Check the "copy" argument of each # Index.__new__ is honored. # # Must be tested separately from other indexes because # self.values is not an ndarray. + index = tm.makeCategoricalIndex(10) result = CategoricalIndex(index.values, copy=True) tm.assert_index_equal(index, result) @@ -267,18 +256,8 @@ def test_frame_repr(self): expected = " A\na 1\nb 2\nc 3" assert result == expected - def test_reindex_base(self): - # See test_reindex.py - pass - - def test_map_str(self): - # See test_map.py - pass - class TestCategoricalIndex2: - # Tests that are not overriding a test in Base - def test_view_i8(self): # GH#25464 ci = tm.makeCategoricalIndex(100) diff --git a/pandas/tests/indexes/datetimes/test_datetimelike.py b/pandas/tests/indexes/datetimes/test_datetimelike.py index 31ec8c497299e..a6bee20d3d3ec 100644 --- a/pandas/tests/indexes/datetimes/test_datetimelike.py +++ b/pandas/tests/indexes/datetimes/test_datetimelike.py @@ -1,39 +1,10 @@ """ generic tests from the Datetimelike class """ -import pytest +from pandas import date_range -from pandas import ( - DatetimeIndex, - date_range, -) -import pandas._testing as tm -from pandas.tests.indexes.datetimelike import DatetimeLike - -class TestDatetimeIndex(DatetimeLike): - _index_cls = DatetimeIndex - - @pytest.fixture - def simple_index(self) -> DatetimeIndex: - return date_range("20130101", periods=5) - - @pytest.fixture( - params=[tm.makeDateIndex(10), date_range("20130110", periods=10, freq="-1D")], - ids=["index_inc", "index_dec"], - ) - def index(self, request): - return request.param - - def test_format(self, simple_index): +class TestDatetimeIndex: + def test_format(self): # GH35439 - idx = simple_index + idx = date_range("20130101", periods=5) expected = [f"{x:%Y-%m-%d}" for x in idx] assert idx.format() == expected - - def test_shift(self): - pass # handled in test_ops - - def test_intersection(self): - pass # handled in test_setops - - def test_union(self): - pass # handled in test_setops diff --git a/pandas/tests/indexes/interval/test_base.py b/pandas/tests/indexes/interval/test_base.py index de9d8be21ae60..e0155a13481ac 100644 --- a/pandas/tests/indexes/interval/test_base.py +++ b/pandas/tests/indexes/interval/test_base.py @@ -3,38 +3,24 @@ from pandas import IntervalIndex import pandas._testing as tm -from pandas.tests.indexes.common import Base -class TestBase(Base): +class TestInterval: """ Tests specific to the shared common index tests; unrelated tests should be placed in test_interval.py or the specific test file (e.g. test_astype.py) """ - _index_cls = IntervalIndex - @pytest.fixture def simple_index(self) -> IntervalIndex: - return self._index_cls.from_breaks(range(11), closed="right") + return IntervalIndex.from_breaks(range(11), closed="right") @pytest.fixture def index(self): return tm.makeIntervalIndex(10) - def create_index(self, *, closed="right"): - return IntervalIndex.from_breaks(range(11), closed=closed) - - def test_repr_max_seq_item_setting(self): - # override base test: not a valid repr as we use interval notation - pass - - def test_repr_roundtrip(self): - # override base test: not a valid repr as we use interval notation - pass - def test_take(self, closed): - index = self.create_index(closed=closed) + index = IntervalIndex.from_breaks(range(11), closed=closed) result = index.take(range(10)) tm.assert_index_equal(result, index) diff --git a/pandas/tests/indexes/numeric/test_numeric.py b/pandas/tests/indexes/numeric/test_numeric.py index 284b7f782a3f2..4080dc7081771 100644 --- a/pandas/tests/indexes/numeric/test_numeric.py +++ b/pandas/tests/indexes/numeric/test_numeric.py @@ -7,12 +7,9 @@ Series, ) import pandas._testing as tm -from pandas.tests.indexes.common import NumericBase -class TestFloatNumericIndex(NumericBase): - _index_cls = Index - +class TestFloatNumericIndex: @pytest.fixture(params=[np.float64, np.float32]) def dtype(self, request): return request.param @@ -20,7 +17,7 @@ def dtype(self, request): @pytest.fixture def simple_index(self, dtype): values = np.arange(5, dtype=dtype) - return self._index_cls(values) + return Index(values) @pytest.fixture( params=[ @@ -32,15 +29,15 @@ def simple_index(self, dtype): ids=["mixed", "float", "mixed_dec", "float_dec"], ) def index(self, request, dtype): - return self._index_cls(request.param, dtype=dtype) + return Index(request.param, dtype=dtype) @pytest.fixture def mixed_index(self, dtype): - return self._index_cls([1.5, 2, 3, 4, 5], dtype=dtype) + return Index([1.5, 2, 3, 4, 5], dtype=dtype) @pytest.fixture def float_index(self, dtype): - return self._index_cls([0.0, 2.5, 5.0, 7.5, 10.0], dtype=dtype) + return Index([0.0, 2.5, 5.0, 7.5, 10.0], dtype=dtype) def test_repr_roundtrip(self, index): tm.assert_index_equal(eval(repr(index)), index, exact=True) @@ -49,16 +46,16 @@ def check_coerce(self, a, b, is_float_index=True): assert a.equals(b) tm.assert_index_equal(a, b, exact=False) if is_float_index: - assert isinstance(b, self._index_cls) + assert isinstance(b, Index) else: assert type(b) is Index def test_constructor_from_list_no_dtype(self): - index = self._index_cls([1.5, 2.5, 3.5]) + index = Index([1.5, 2.5, 3.5]) assert index.dtype == np.float64 def test_constructor(self, dtype): - index_cls = self._index_cls + index_cls = Index # explicit construction index = index_cls([1, 2, 3, 4, 5], dtype=dtype) @@ -97,7 +94,7 @@ def test_constructor(self, dtype): assert pd.isna(result.values).all() def test_constructor_invalid(self): - index_cls = self._index_cls + index_cls = Index cls_name = index_cls.__name__ # invalid msg = ( @@ -131,7 +128,7 @@ def test_type_coercion_fail(self, any_int_numpy_dtype): Index([1, 2, 3.5], dtype=any_int_numpy_dtype) def test_equals_numeric(self): - index_cls = self._index_cls + index_cls = Index idx = index_cls([1.0, 2.0]) assert idx.equals(idx) @@ -156,7 +153,7 @@ def test_equals_numeric(self): ), ) def test_equals_numeric_other_index_type(self, other): - idx = self._index_cls([1.0, 2.0]) + idx = Index([1.0, 2.0]) assert idx.equals(other) assert other.equals(idx) @@ -198,13 +195,13 @@ def test_lookups_datetimelike_values(self, vals, dtype): assert isinstance(result, type(expected)) and result == expected def test_doesnt_contain_all_the_things(self): - idx = self._index_cls([np.nan]) + idx = Index([np.nan]) assert not idx.isin([0]).item() assert not idx.isin([1]).item() assert idx.isin([np.nan]).item() def test_nan_multiple_containment(self): - index_cls = self._index_cls + index_cls = Index idx = index_cls([1.0, np.nan]) tm.assert_numpy_array_equal(idx.isin([1.0]), np.array([True, False])) @@ -215,7 +212,7 @@ def test_nan_multiple_containment(self): tm.assert_numpy_array_equal(idx.isin([np.nan]), np.array([False, False])) def test_fillna_float64(self): - index_cls = self._index_cls + index_cls = Index # GH 11343 idx = Index([1.0, np.nan, 3.0], dtype=float, name="x") # can't downcast @@ -231,11 +228,17 @@ def test_fillna_float64(self): tm.assert_index_equal(idx.fillna("obj"), exp, exact=True) -class NumericInt(NumericBase): - _index_cls = Index +class TestNumericInt: + @pytest.fixture(params=[np.int64, np.int32, np.int16, np.int8, np.uint64]) + def dtype(self, request): + return request.param + + @pytest.fixture + def simple_index(self, dtype): + return Index(range(0, 20, 2), dtype=dtype) def test_is_monotonic(self): - index_cls = self._index_cls + index_cls = Index index = index_cls([1, 2, 3, 4]) assert index.is_monotonic_increasing is True @@ -257,7 +260,7 @@ def test_is_monotonic(self): assert index._is_strictly_monotonic_decreasing is True def test_is_strictly_monotonic(self): - index_cls = self._index_cls + index_cls = Index index = index_cls([1, 1, 2, 3]) assert index.is_monotonic_increasing is True @@ -303,7 +306,7 @@ def test_cant_or_shouldnt_cast(self, dtype): # can't data = ["foo", "bar", "baz"] with pytest.raises(ValueError, match=msg): - self._index_cls(data, dtype=dtype) + Index(data, dtype=dtype) def test_view_index(self, simple_index): index = simple_index @@ -315,27 +318,17 @@ def test_prevent_casting(self, simple_index): assert result.dtype == np.object_ -class TestIntNumericIndex(NumericInt): +class TestIntNumericIndex: @pytest.fixture(params=[np.int64, np.int32, np.int16, np.int8]) def dtype(self, request): return request.param - @pytest.fixture - def simple_index(self, dtype): - return self._index_cls(range(0, 20, 2), dtype=dtype) - - @pytest.fixture( - params=[range(0, 20, 2), range(19, -1, -1)], ids=["index_inc", "index_dec"] - ) - def index(self, request, dtype): - return self._index_cls(request.param, dtype=dtype) - def test_constructor_from_list_no_dtype(self): - index = self._index_cls([1, 2, 3]) + index = Index([1, 2, 3]) assert index.dtype == np.int64 def test_constructor(self, dtype): - index_cls = self._index_cls + index_cls = Index # scalar raise Exception msg = ( @@ -379,7 +372,7 @@ def test_constructor(self, dtype): tm.assert_index_equal(idx, expected) def test_constructor_corner(self, dtype): - index_cls = self._index_cls + index_cls = Index arr = np.array([1, 2, 3, 4], dtype=object) @@ -426,7 +419,7 @@ def test_constructor_np_unsigned(self, any_unsigned_int_numpy_dtype): def test_coerce_list(self): # coerce things arr = Index([1, 2, 3, 4]) - assert isinstance(arr, self._index_cls) + assert isinstance(arr, Index) # but not if explicit dtype passed arr = Index([1, 2, 3, 4], dtype=object) @@ -436,10 +429,8 @@ def test_coerce_list(self): class TestFloat16Index: # float 16 indexes not supported # GH 49535 - _index_cls = Index - def test_constructor(self): - index_cls = self._index_cls + index_cls = Index dtype = np.float16 msg = "float16 indexes are not supported" @@ -471,27 +462,6 @@ def test_constructor(self): index_cls(np.array([np.nan]), dtype=dtype) -class TestUIntNumericIndex(NumericInt): - @pytest.fixture(params=[np.uint64]) - def dtype(self, request): - return request.param - - @pytest.fixture - def simple_index(self, dtype): - # compat with shared Int64/Float64 tests - return self._index_cls(np.arange(5, dtype=dtype)) - - @pytest.fixture( - params=[ - [2**63, 2**63 + 10, 2**63 + 15, 2**63 + 20, 2**63 + 25], - [2**63 + 25, 2**63 + 20, 2**63 + 15, 2**63 + 10, 2**63], - ], - ids=["index_inc", "index_dec"], - ) - def index(self, request): - return self._index_cls(request.param, dtype=np.uint64) - - @pytest.mark.parametrize( "box", [list, lambda x: np.array(x, dtype=object), lambda x: Index(x, dtype=object)], diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py index e5c85edfaaffa..412d66de11ba3 100644 --- a/pandas/tests/indexes/period/test_period.py +++ b/pandas/tests/indexes/period/test_period.py @@ -14,30 +14,9 @@ period_range, ) import pandas._testing as tm -from pandas.tests.indexes.datetimelike import DatetimeLike -class TestPeriodIndex(DatetimeLike): - _index_cls = PeriodIndex - - @pytest.fixture - def simple_index(self) -> Index: - return period_range("20130101", periods=5, freq="D") - - @pytest.fixture( - params=[ - tm.makePeriodIndex(10), - period_range("20130101", periods=10, freq="D")[::-1], - ], - ids=["index_inc", "index_dec"], - ) - def index(self, request): - return request.param - - def test_where(self): - # This is handled in test_indexing - pass - +class TestPeriodIndex: def test_make_time_series(self): index = period_range(freq="A", start="1/1/2001", end="12/1/2009") series = Series(1, index=index) @@ -147,42 +126,9 @@ def test_period_index_length(self): with pytest.raises(ValueError, match=msg): PeriodIndex(vals) - def test_fields(self): - # year, month, day, hour, minute - # second, weekofyear, week, dayofweek, weekday, dayofyear, quarter - # qyear - pi = period_range(freq="A", start="1/1/2001", end="12/1/2005") - self._check_all_fields(pi) - - pi = period_range(freq="Q", start="1/1/2001", end="12/1/2002") - self._check_all_fields(pi) - - pi = period_range(freq="M", start="1/1/2001", end="1/1/2002") - self._check_all_fields(pi) - - pi = period_range(freq="D", start="12/1/2001", end="6/1/2001") - self._check_all_fields(pi) - - pi = period_range(freq="B", start="12/1/2001", end="6/1/2001") - self._check_all_fields(pi) - - pi = period_range(freq="H", start="12/31/2001", end="1/1/2002 23:00") - self._check_all_fields(pi) - - pi = period_range(freq="Min", start="12/31/2001", end="1/1/2002 00:20") - self._check_all_fields(pi) - - pi = period_range( - freq="S", start="12/31/2001 00:00:00", end="12/31/2001 00:05:00" - ) - self._check_all_fields(pi) - - end_intv = Period("2006-12-31", "W") - i1 = period_range(end=end_intv, periods=10) - self._check_all_fields(i1) - - def _check_all_fields(self, periodindex): - fields = [ + @pytest.mark.parametrize( + "field", + [ "year", "month", "day", @@ -198,24 +144,40 @@ def _check_all_fields(self, periodindex): "quarter", "qyear", "days_in_month", - ] - + ], + ) + @pytest.mark.parametrize( + "periodindex", + [ + period_range(freq="A", start="1/1/2001", end="12/1/2005"), + period_range(freq="Q", start="1/1/2001", end="12/1/2002"), + period_range(freq="M", start="1/1/2001", end="1/1/2002"), + period_range(freq="D", start="12/1/2001", end="6/1/2001"), + period_range(freq="B", start="12/1/2001", end="6/1/2001"), + period_range(freq="H", start="12/31/2001", end="1/1/2002 23:00"), + period_range(freq="Min", start="12/31/2001", end="1/1/2002 00:20"), + period_range( + freq="S", start="12/31/2001 00:00:00", end="12/31/2001 00:05:00" + ), + period_range(end=Period("2006-12-31", "W"), periods=10), + ], + ) + def test_fields(self, periodindex, field): periods = list(periodindex) ser = Series(periodindex) - for field in fields: - field_idx = getattr(periodindex, field) - assert len(periodindex) == len(field_idx) - for x, val in zip(periods, field_idx): - assert getattr(x, field) == val + field_idx = getattr(periodindex, field) + assert len(periodindex) == len(field_idx) + for x, val in zip(periods, field_idx): + assert getattr(x, field) == val - if len(ser) == 0: - continue + if len(ser) == 0: + return - field_s = getattr(ser.dt, field) - assert len(periodindex) == len(field_s) - for x, val in zip(periods, field_s): - assert getattr(x, field) == val + field_s = getattr(ser.dt, field) + assert len(periodindex) == len(field_s) + for x, val in zip(periods, field_s): + assert getattr(x, field) == val def test_is_(self): create_index = lambda: period_range(freq="A", start="1/1/2001", end="12/1/2009") @@ -241,10 +203,6 @@ def test_index_unique(self): tm.assert_index_equal(idx.unique(), expected) assert idx.nunique() == 3 - def test_shift(self): - # This is tested in test_arithmetic - pass - def test_negative_ordinals(self): Period(ordinal=-1000, freq="A") Period(ordinal=0, freq="A") @@ -307,7 +265,7 @@ def test_map(self): def test_format_empty(self): # GH35712 - empty_idx = self._index_cls([], freq="A") + empty_idx = PeriodIndex([], freq="A") assert empty_idx.format() == [] assert empty_idx.format(name=True) == [""] diff --git a/pandas/tests/indexes/ranges/test_range.py b/pandas/tests/indexes/ranges/test_range.py index b964fb43f1560..06ad1f3c865c8 100644 --- a/pandas/tests/indexes/ranges/test_range.py +++ b/pandas/tests/indexes/ranges/test_range.py @@ -9,42 +9,19 @@ RangeIndex, ) import pandas._testing as tm -from pandas.tests.indexes.common import NumericBase # aliases to make some tests easier to read RI = RangeIndex -class TestRangeIndex(NumericBase): - _index_cls = RangeIndex - - @pytest.fixture - def dtype(self): - return np.int64 - - @pytest.fixture( - params=["uint64", "float64", "category", "datetime64", "object"], - ) - def invalid_dtype(self, request): - return request.param - +class TestRangeIndex: @pytest.fixture def simple_index(self): - return self._index_cls(start=0, stop=20, step=2) + return RangeIndex(start=0, stop=20, step=2) - @pytest.fixture( - params=[ - RangeIndex(start=0, stop=20, step=2, name="foo"), - RangeIndex(start=18, stop=-1, step=-2, name="bar"), - ], - ids=["index_inc", "index_dec"], - ) - def index(self, request): - return request.param - - def test_constructor_unwraps_index(self, dtype): - result = self._index_cls(1, 3) - expected = np.array([1, 2], dtype=dtype) + def test_constructor_unwraps_index(self): + result = RangeIndex(1, 3) + expected = np.array([1, 2], dtype=np.int64) tm.assert_numpy_array_equal(result._data, expected) def test_can_hold_identifiers(self, simple_index): @@ -330,16 +307,18 @@ def test_is_monotonic(self): assert index._is_strictly_monotonic_increasing is True assert index._is_strictly_monotonic_decreasing is True - def test_equals_range(self): - equiv_pairs = [ + @pytest.mark.parametrize( + "left,right", + [ (RangeIndex(0, 9, 2), RangeIndex(0, 10, 2)), (RangeIndex(0), RangeIndex(1, -1, 3)), (RangeIndex(1, 2, 3), RangeIndex(1, 3, 4)), (RangeIndex(0, -9, -2), RangeIndex(0, -10, -2)), - ] - for left, right in equiv_pairs: - assert left.equals(right) - assert right.equals(left) + ], + ) + def test_equals_range(self, left, right): + assert left.equals(right) + assert right.equals(left) def test_logical_compat(self, simple_index): idx = simple_index @@ -408,6 +387,14 @@ def test_slice_keep_name(self): idx = RangeIndex(1, 2, name="asdf") assert idx.name == idx[1:].name + @pytest.mark.parametrize( + "index", + [ + RangeIndex(start=0, stop=20, step=2, name="foo"), + RangeIndex(start=18, stop=-1, step=-2, name="bar"), + ], + ids=["index_inc", "index_dec"], + ) def test_has_duplicates(self, index): assert index.is_unique assert not index.has_duplicates @@ -440,10 +427,6 @@ def test_min_fitting_element(self): result = RangeIndex(5, big_num * 2, 1)._min_fitting_element(big_num) assert big_num == result - def test_pickle_compat_construction(self): - # RangeIndex() is a valid constructor - pass - def test_slice_specialised(self, simple_index): index = simple_index index.name = "foo" @@ -511,8 +494,9 @@ def test_len_specialised(self, step): index = RangeIndex(stop, start, step) assert len(index) == 0 - @pytest.fixture( - params=[ + @pytest.mark.parametrize( + "indices, expected", + [ ([RI(1, 12, 5)], RI(1, 12, 5)), ([RI(0, 6, 4)], RI(0, 6, 4)), ([RI(1, 3), RI(3, 7)], RI(1, 7)), @@ -532,17 +516,10 @@ def test_len_specialised(self, step): ([RI(3), Index([-1, 3.1, 15.0])], Index([0, 1, 2, -1, 3.1, 15.0])), ([RI(3), Index(["a", None, 14])], Index([0, 1, 2, "a", None, 14])), ([RI(3, 1), Index(["a", None, 14])], Index(["a", None, 14])), - ] + ], ) - def appends(self, request): - """Inputs and expected outputs for RangeIndex.append test""" - return request.param - - def test_append(self, appends): + def test_append(self, indices, expected): # GH16212 - - indices, expected = appends - result = indices[0].append(indices[1:]) tm.assert_index_equal(result, expected, exact=True) @@ -575,7 +552,7 @@ def test_engineless_lookup(self): def test_format_empty(self): # GH35712 - empty_idx = self._index_cls(0) + empty_idx = RangeIndex(0) assert empty_idx.format() == [] assert empty_idx.format(name=True) == [""] @@ -610,9 +587,6 @@ def test_sort_values_key(self): expected = Index([4, 8, 6, 0, 2], dtype="int64") tm.assert_index_equal(result, expected, check_exact=True) - def test_cast_string(self, dtype): - pytest.skip("casting of strings not relevant for RangeIndex") - def test_range_index_rsub_by_const(self): # GH#53255 result = 3 - RangeIndex(0, 4, 1) diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index db317a819c520..41a0d25af7b52 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -39,15 +39,12 @@ ensure_index, ensure_index_from_sequences, ) -from pandas.tests.indexes.common import Base -class TestIndex(Base): - _index_cls = Index - +class TestIndex: @pytest.fixture def simple_index(self) -> Index: - return self._index_cls(list("abcde")) + return Index(list("abcde")) def test_can_hold_identifiers(self, simple_index): index = simple_index @@ -1303,19 +1300,13 @@ def test_index_round(self, decimals, expected_results): tm.assert_index_equal(result, expected) -class TestMixedIntIndex(Base): +class TestMixedIntIndex: # Mostly the tests from common.py for which the results differ # in py2 and py3 because ints and strings are uncomparable in py3 # (GH 13514) - _index_cls = Index - @pytest.fixture def simple_index(self) -> Index: - return self._index_cls([0, "a", 1, "b", 2, "c"]) - - @pytest.fixture(params=[[0, "a", 1, "b", 2, "c"]], ids=["mixedIndex"]) - def index(self, request): - return Index(request.param) + return Index([0, "a", 1, "b", 2, "c"]) def test_argsort(self, simple_index): index = simple_index diff --git a/pandas/tests/indexes/datetimelike.py b/pandas/tests/indexes/test_datetimelike.py similarity index 81% rename from pandas/tests/indexes/datetimelike.py rename to pandas/tests/indexes/test_datetimelike.py index 1a050e606277b..b315b1ac141cd 100644 --- a/pandas/tests/indexes/datetimelike.py +++ b/pandas/tests/indexes/test_datetimelike.py @@ -5,10 +5,33 @@ import pandas as pd import pandas._testing as tm -from pandas.tests.indexes.common import Base -class DatetimeLike(Base): +class TestDatetimeLike: + @pytest.fixture( + params=[ + pd.period_range("20130101", periods=5, freq="D"), + pd.TimedeltaIndex( + [ + "0 days 01:00:00", + "1 days 01:00:00", + "2 days 01:00:00", + "3 days 01:00:00", + "4 days 01:00:00", + ], + dtype="timedelta64[ns]", + freq="D", + ), + pd.DatetimeIndex( + ["2013-01-01", "2013-01-02", "2013-01-03", "2013-01-04", "2013-01-05"], + dtype="datetime64[ns]", + freq="D", + ), + ] + ) + def simple_index(self, request): + return request.param + def test_isin(self, simple_index): index = simple_index[:4] result = index.isin(index) @@ -45,7 +68,7 @@ def test_shift_empty(self, simple_index): def test_str(self, simple_index): # test the string repr - idx = simple_index + idx = simple_index.copy() idx.name = "foo" assert f"length={len(idx)}" not in str(idx) assert "'foo'" in str(idx) @@ -63,11 +86,11 @@ def test_view(self, simple_index): idx = simple_index idx_view = idx.view("i8") - result = self._index_cls(idx) + result = type(simple_index)(idx) tm.assert_index_equal(result, idx) - idx_view = idx.view(self._index_cls) - result = self._index_cls(idx) + idx_view = idx.view(type(simple_index)) + result = type(simple_index)(idx) tm.assert_index_equal(result, idx_view) def test_map_callable(self, simple_index): diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/test_old_base.py similarity index 86% rename from pandas/tests/indexes/common.py rename to pandas/tests/indexes/test_old_base.py index 73de3ee60339a..ff23c8a8ba5a4 100644 --- a/pandas/tests/indexes/common.py +++ b/pandas/tests/indexes/test_old_base.py @@ -8,7 +8,10 @@ from pandas._libs.tslibs import Timestamp -from pandas.core.dtypes.common import is_integer_dtype +from pandas.core.dtypes.common import ( + is_integer_dtype, + is_numeric_dtype, +) from pandas.core.dtypes.dtypes import CategoricalDtype import pandas as pd @@ -24,27 +27,52 @@ Series, TimedeltaIndex, isna, + period_range, ) import pandas._testing as tm from pandas.core.arrays import BaseMaskedArray -class Base: - """ - Base class for index sub-class tests. - """ - - _index_cls: type[Index] - - @pytest.fixture - def simple_index(self): - raise NotImplementedError("Method not implemented") - - def create_index(self) -> Index: - raise NotImplementedError("Method not implemented") +class TestBase: + @pytest.fixture( + params=[ + RangeIndex(start=0, stop=20, step=2), + Index(np.arange(5, dtype=np.float64)), + Index(np.arange(5, dtype=np.float32)), + Index(np.arange(5, dtype=np.uint64)), + Index(range(0, 20, 2), dtype=np.int64), + Index(range(0, 20, 2), dtype=np.int32), + Index(range(0, 20, 2), dtype=np.int16), + Index(range(0, 20, 2), dtype=np.int8), + Index(list("abcde")), + Index([0, "a", 1, "b", 2, "c"]), + period_range("20130101", periods=5, freq="D"), + TimedeltaIndex( + [ + "0 days 01:00:00", + "1 days 01:00:00", + "2 days 01:00:00", + "3 days 01:00:00", + "4 days 01:00:00", + ], + dtype="timedelta64[ns]", + freq="D", + ), + DatetimeIndex( + ["2013-01-01", "2013-01-02", "2013-01-03", "2013-01-04", "2013-01-05"], + dtype="datetime64[ns]", + freq="D", + ), + IntervalIndex.from_breaks(range(11), closed="right"), + ] + ) + def simple_index(self, request): + return request.param - def test_pickle_compat_construction(self): + def test_pickle_compat_construction(self, simple_index): # need an object to create with + if isinstance(simple_index, RangeIndex): + pytest.skip("RangeIndex() is a valid constructor") msg = "|".join( [ r"Index\(\.\.\.\) must be called with a collection of some " @@ -58,10 +86,12 @@ def test_pickle_compat_construction(self): ] ) with pytest.raises(TypeError, match=msg): - self._index_cls() + type(simple_index)() def test_shift(self, simple_index): # GH8083 test the base class for shift + if isinstance(simple_index, (DatetimeIndex, TimedeltaIndex, PeriodIndex)): + pytest.skip("Tested in test_ops/test_arithmetic") idx = simple_index msg = ( f"This method is only implemented for DatetimeIndex, PeriodIndex and " @@ -82,7 +112,7 @@ def test_constructor_name_unhashable(self, simple_index): def test_create_index_existing_name(self, simple_index): # GH11193, when an existing index is passed, and a new name is not # specified, the new index should inherit the previous object name - expected = simple_index + expected = simple_index.copy() if not isinstance(expected, MultiIndex): expected.name = "foo" result = Index(expected) @@ -138,6 +168,10 @@ def test_numeric_compat(self, simple_index): assert not isinstance(idx, MultiIndex) if type(idx) is Index: return + if is_numeric_dtype(simple_index.dtype) or isinstance( + simple_index, TimedeltaIndex + ): + pytest.skip("Tested elsewhere.") typ = type(idx._data).__name__ cls = type(idx).__name__ @@ -175,6 +209,12 @@ def test_numeric_compat(self, simple_index): 1 // idx def test_logical_compat(self, simple_index): + if ( + isinstance(simple_index, RangeIndex) + or is_numeric_dtype(simple_index.dtype) + or simple_index.dtype == object + ): + pytest.skip("Tested elsewhere.") idx = simple_index with pytest.raises(TypeError, match="cannot perform all"): idx.all() @@ -182,11 +222,15 @@ def test_logical_compat(self, simple_index): idx.any() def test_repr_roundtrip(self, simple_index): + if isinstance(simple_index, IntervalIndex): + pytest.skip(f"Not a valid repr for {type(simple_index).__name__}") idx = simple_index tm.assert_index_equal(eval(repr(idx)), idx) def test_repr_max_seq_item_setting(self, simple_index): # GH10182 + if isinstance(simple_index, IntervalIndex): + pytest.skip(f"Not a valid repr for {type(simple_index).__name__}") idx = simple_index idx = idx.repeat(50) with pd.option_context("display.max_seq_items", None): @@ -330,6 +374,10 @@ def test_numpy_repeat(self, simple_index): np.repeat(idx, rep, axis=0) def test_where(self, listlike_box, simple_index): + if isinstance(simple_index, (IntervalIndex, PeriodIndex)) or is_numeric_dtype( + simple_index.dtype + ): + pytest.skip("Tested elsewhere.") klass = listlike_box idx = simple_index @@ -497,13 +545,19 @@ def test_equals_op(self, simple_index): def test_format(self, simple_index): # GH35439 + if is_numeric_dtype(simple_index.dtype) or isinstance( + simple_index, DatetimeIndex + ): + pytest.skip("Tested elsewhere.") idx = simple_index expected = [str(x) for x in idx] assert idx.format() == expected - def test_format_empty(self): + def test_format_empty(self, simple_index): # GH35712 - empty_idx = self._index_cls([]) + if isinstance(simple_index, (PeriodIndex, RangeIndex)): + pytest.skip("Tested elsewhere") + empty_idx = type(simple_index)([]) assert empty_idx.format() == [] assert empty_idx.format(name=True) == [""] @@ -580,6 +634,8 @@ def test_join_self_unique(self, join_type, simple_index): def test_map(self, simple_index): # callable + if isinstance(simple_index, (TimedeltaIndex, PeriodIndex)): + pytest.skip("Tested elsewhere.") idx = simple_index result = idx.map(lambda x: x) @@ -601,6 +657,8 @@ def test_map_dictlike(self, mapper, simple_index): # non-unique values, which raises. This _should_ work fine for # CategoricalIndex. pytest.skip(f"skipping tests for {type(idx)}") + elif isinstance(idx, (DatetimeIndex, TimedeltaIndex, PeriodIndex)): + pytest.skip("Tested elsewhere.") identity = mapper(idx.values, idx) @@ -619,6 +677,8 @@ def test_map_dictlike(self, mapper, simple_index): def test_map_str(self, simple_index): # GH 31202 + if isinstance(simple_index, CategoricalIndex): + pytest.skip("See test_map.py") idx = simple_index result = idx.map(str) expected = Index([str(x) for x in idx], dtype=object) @@ -682,6 +742,8 @@ def test_engine_reference_cycle(self, simple_index): def test_getitem_2d_deprecated(self, simple_index): # GH#30588, GH#31479 + if isinstance(simple_index, IntervalIndex): + pytest.skip("Tested elsewhere") idx = simple_index msg = "Multi-dimensional indexing" with pytest.raises(ValueError, match=msg): @@ -834,30 +896,43 @@ def test_is_object_is_deprecated(self, simple_index): idx.is_object() -class NumericBase(Base): - """ - Base class for numeric index (incl. RangeIndex) sub-class tests. - """ +class TestNumericBase: + @pytest.fixture( + params=[ + RangeIndex(start=0, stop=20, step=2), + Index(np.arange(5, dtype=np.float64)), + Index(np.arange(5, dtype=np.float32)), + Index(np.arange(5, dtype=np.uint64)), + Index(range(0, 20, 2), dtype=np.int64), + Index(range(0, 20, 2), dtype=np.int32), + Index(range(0, 20, 2), dtype=np.int16), + Index(range(0, 20, 2), dtype=np.int8), + ] + ) + def simple_index(self, request): + return request.param - def test_constructor_unwraps_index(self, dtype): - index_cls = self._index_cls + def test_constructor_unwraps_index(self, simple_index): + if isinstance(simple_index, RangeIndex): + pytest.skip("Tested elsewhere.") + index_cls = type(simple_index) + dtype = simple_index.dtype idx = Index([1, 2], dtype=dtype) result = index_cls(idx) expected = np.array([1, 2], dtype=idx.dtype) tm.assert_numpy_array_equal(result._data, expected) - def test_where(self): - # Tested in numeric.test_indexing - pass - def test_can_hold_identifiers(self, simple_index): idx = simple_index key = idx[0] assert idx._can_hold_identifiers_and_holds_name(key) is False - def test_view(self, dtype): - index_cls = self._index_cls + def test_view(self, simple_index): + if isinstance(simple_index, RangeIndex): + pytest.skip("Tested elsewhere.") + index_cls = type(simple_index) + dtype = simple_index.dtype idx = index_cls([], dtype=dtype, name="Foo") idx_view = idx.view() @@ -871,14 +946,13 @@ def test_view(self, dtype): def test_format(self, simple_index): # GH35439 + if isinstance(simple_index, DatetimeIndex): + pytest.skip("Tested elsewhere") idx = simple_index max_width = max(len(str(x)) for x in idx) expected = [str(x).ljust(max_width) for x in idx] assert idx.format() == expected - def test_numeric_compat(self): - pass # override Base method - def test_insert_non_na(self, simple_index): # GH#43921 inserting an element that we know we can hold should # not change dtype or type (except for RangeIndex) @@ -905,10 +979,10 @@ def test_insert_na(self, nulls_fixture, simple_index): result = index.insert(1, na_val) tm.assert_index_equal(result, expected, exact=True) - def test_arithmetic_explicit_conversions(self): + def test_arithmetic_explicit_conversions(self, simple_index): # GH 8608 # add/sub are overridden explicitly for Float/Int Index - index_cls = self._index_cls + index_cls = type(simple_index) if index_cls is RangeIndex: idx = RangeIndex(5) else: @@ -939,7 +1013,9 @@ def test_astype_to_complex(self, complex_dtype, simple_index): assert type(result) is Index and result.dtype == complex_dtype - def test_cast_string(self, dtype): - result = self._index_cls(["0", "1", "2"], dtype=dtype) - expected = self._index_cls([0, 1, 2], dtype=dtype) + def test_cast_string(self, simple_index): + if isinstance(simple_index, RangeIndex): + pytest.skip("casting of strings not relevant for RangeIndex") + result = type(simple_index)(["0", "1", "2"], dtype=simple_index.dtype) + expected = type(simple_index)([0, 1, 2], dtype=simple_index.dtype) tm.assert_index_equal(result, expected) diff --git a/pandas/tests/indexes/timedeltas/test_timedelta.py b/pandas/tests/indexes/timedeltas/test_timedelta.py index 0cbc4bde4b07f..8e71d1fd9078f 100644 --- a/pandas/tests/indexes/timedeltas/test_timedelta.py +++ b/pandas/tests/indexes/timedeltas/test_timedelta.py @@ -3,45 +3,22 @@ import numpy as np import pytest -import pandas as pd from pandas import ( Index, NaT, Series, Timedelta, - TimedeltaIndex, timedelta_range, ) import pandas._testing as tm from pandas.core.arrays import TimedeltaArray -from pandas.tests.indexes.datetimelike import DatetimeLike -randn = np.random.randn - - -class TestTimedeltaIndex(DatetimeLike): - _index_cls = TimedeltaIndex - - @pytest.fixture - def simple_index(self) -> TimedeltaIndex: - index = pd.to_timedelta(range(5), unit="d")._with_freq("infer") - assert index.freq == "D" - ret = index + pd.offsets.Hour(1) - assert ret.freq == "D" - return ret +class TestTimedeltaIndex: @pytest.fixture def index(self): return tm.makeTimedeltaIndex(10) - def test_numeric_compat(self): - # Dummy method to override super's version; this test is now done - # in test_arithmetic.py - pass - - def test_shift(self): - pass # this is handled in test_arithmetic.py - def test_misc_coverage(self): rng = timedelta_range("1 day", periods=5) result = rng.groupby(rng.days)