diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py index 793992d311502..b657d8d16df81 100644 --- a/pandas/tests/indexes/common.py +++ b/pandas/tests/indexes/common.py @@ -33,10 +33,6 @@ class Base: _holder = None _compat_props = ["shape", "ndim", "size", "nbytes"] - def setup_indices(self): - for name, idx in self.indices.items(): - setattr(self, name, idx) - def test_pickle_compat_construction(self): # need an object to create with msg = ( @@ -205,24 +201,23 @@ def test_reindex_base(self): with pytest.raises(ValueError, match="Invalid fill method"): idx.get_indexer(idx, method="invalid") - def test_get_indexer_consistency(self): + def test_get_indexer_consistency(self, indices): # See GH 16819 - for name, index in self.indices.items(): - if isinstance(index, IntervalIndex): - continue - - if index.is_unique or isinstance(index, CategoricalIndex): - indexer = index.get_indexer(index[0:2]) - assert isinstance(indexer, np.ndarray) - assert indexer.dtype == np.intp - else: - e = "Reindexing only valid with uniquely valued Index objects" - with pytest.raises(InvalidIndexError, match=e): - index.get_indexer(index[0:2]) + if isinstance(indices, IntervalIndex): + return - indexer, _ = index.get_indexer_non_unique(index[0:2]) + if indices.is_unique or isinstance(indices, CategoricalIndex): + indexer = indices.get_indexer(indices[0:2]) assert isinstance(indexer, np.ndarray) assert indexer.dtype == np.intp + else: + e = "Reindexing only valid with uniquely valued Index objects" + with pytest.raises(InvalidIndexError, match=e): + indices.get_indexer(indices[0:2]) + + indexer, _ = indices.get_indexer_non_unique(indices[0:2]) + assert isinstance(indexer, np.ndarray) + assert indexer.dtype == np.intp def test_ndarray_compat_properties(self): idx = self.create_index() @@ -258,146 +253,138 @@ def test_repr_max_seq_item_setting(self): repr(idx) assert "..." not in str(idx) - def test_copy_name(self): + def test_copy_name(self, indices): # gh-12309: Check that the "name" argument # passed at initialization is honored. + if isinstance(indices, MultiIndex): + return - for name, index in self.indices.items(): - if isinstance(index, MultiIndex): - continue - - first = index.__class__(index, copy=True, name="mario") - second = first.__class__(first, copy=False) + first = indices.__class__(indices, copy=True, name="mario") + second = first.__class__(first, copy=False) - # Even though "copy=False", we want a new object. - assert first is not second + # Even though "copy=False", we want a new object. + assert first is not second - # Not using tm.assert_index_equal() since names differ. - assert index.equals(first) + # Not using tm.assert_index_equal() since names differ. + assert indices.equals(first) - assert first.name == "mario" - assert second.name == "mario" + assert first.name == "mario" + assert second.name == "mario" - s1 = Series(2, index=first) - s2 = Series(3, index=second[:-1]) + s1 = Series(2, index=first) + s2 = Series(3, index=second[:-1]) - if not isinstance(index, CategoricalIndex): - # See gh-13365 - s3 = s1 * s2 - assert s3.index.name == "mario" + if not isinstance(indices, CategoricalIndex): + # See gh-13365 + s3 = s1 * s2 + assert s3.index.name == "mario" - def test_ensure_copied_data(self): + def test_ensure_copied_data(self, indices): # Check the "copy" argument of each Index.__new__ is honoured # GH12309 - for name, index in self.indices.items(): - init_kwargs = {} - if isinstance(index, PeriodIndex): - # Needs "freq" specification: - init_kwargs["freq"] = index.freq - elif isinstance(index, (RangeIndex, MultiIndex, CategoricalIndex)): - # RangeIndex cannot be initialized from data - # MultiIndex and CategoricalIndex are tested separately - continue - - index_type = index.__class__ - result = index_type(index.values, copy=True, **init_kwargs) - tm.assert_index_equal(index, result) + init_kwargs = {} + if isinstance(indices, PeriodIndex): + # Needs "freq" specification: + init_kwargs["freq"] = indices.freq + elif isinstance(indices, (RangeIndex, MultiIndex, CategoricalIndex)): + # RangeIndex cannot be initialized from data + # MultiIndex and CategoricalIndex are tested separately + return + + index_type = indices.__class__ + result = index_type(indices.values, copy=True, **init_kwargs) + tm.assert_index_equal(indices, result) + tm.assert_numpy_array_equal( + indices._ndarray_values, result._ndarray_values, check_same="copy" + ) + + if isinstance(indices, PeriodIndex): + # .values an object array of Period, thus copied + result = index_type(ordinal=indices.asi8, copy=False, **init_kwargs) tm.assert_numpy_array_equal( - index._ndarray_values, result._ndarray_values, check_same="copy" + indices._ndarray_values, result._ndarray_values, check_same="same" + ) + elif isinstance(indices, IntervalIndex): + # checked in test_interval.py + pass + else: + result = index_type(indices.values, copy=False, **init_kwargs) + tm.assert_numpy_array_equal( + indices.values, result.values, check_same="same" + ) + tm.assert_numpy_array_equal( + indices._ndarray_values, result._ndarray_values, check_same="same" ) - if isinstance(index, PeriodIndex): - # .values an object array of Period, thus copied - result = index_type(ordinal=index.asi8, copy=False, **init_kwargs) - tm.assert_numpy_array_equal( - index._ndarray_values, result._ndarray_values, check_same="same" - ) - elif isinstance(index, IntervalIndex): - # checked in test_interval.py - pass - else: - result = index_type(index.values, copy=False, **init_kwargs) - tm.assert_numpy_array_equal( - index.values, result.values, check_same="same" - ) - tm.assert_numpy_array_equal( - index._ndarray_values, result._ndarray_values, check_same="same" - ) - - def test_memory_usage(self): - for name, index in self.indices.items(): - result = index.memory_usage() - if len(index): - index.get_loc(index[0]) - result2 = index.memory_usage() - result3 = index.memory_usage(deep=True) - - # RangeIndex, IntervalIndex - # don't have engines - if not isinstance(index, (RangeIndex, IntervalIndex)): - assert result2 > result - - if index.inferred_type == "object": - assert result3 > result2 - - else: - - # we report 0 for no-length - assert result == 0 - - def test_argsort(self): - for k, ind in self.indices.items(): - - # separately tested - if k in ["catIndex"]: - continue - - result = ind.argsort() - expected = np.array(ind).argsort() - tm.assert_numpy_array_equal(result, expected, check_dtype=False) - - def test_numpy_argsort(self): - for k, ind in self.indices.items(): - result = np.argsort(ind) - expected = ind.argsort() - tm.assert_numpy_array_equal(result, expected) - - # these are the only two types that perform - # pandas compatibility input validation - the - # rest already perform separate (or no) such - # validation via their 'values' attribute as - # defined in pandas.core.indexes/base.py - they - # cannot be changed at the moment due to - # backwards compatibility concerns - if isinstance(type(ind), (CategoricalIndex, RangeIndex)): - msg = "the 'axis' parameter is not supported" - with pytest.raises(ValueError, match=msg): - np.argsort(ind, axis=1) - - msg = "the 'kind' parameter is not supported" - with pytest.raises(ValueError, match=msg): - np.argsort(ind, kind="mergesort") - - msg = "the 'order' parameter is not supported" - with pytest.raises(ValueError, match=msg): - np.argsort(ind, order=("a", "b")) - - def test_take(self): + def test_memory_usage(self, indices): + indices._engine.clear_mapping() + result = indices.memory_usage() + if indices.empty: + # we report 0 for no-length + assert result == 0 + return + + # non-zero length + indices.get_loc(indices[0]) + result2 = indices.memory_usage() + result3 = indices.memory_usage(deep=True) + + # RangeIndex, IntervalIndex + # don't have engines + if not isinstance(indices, (RangeIndex, IntervalIndex)): + assert result2 > result + + if indices.inferred_type == "object": + assert result3 > result2 + + def test_argsort(self, request, indices): + # separately tested + if isinstance(indices, CategoricalIndex): + return + + result = indices.argsort() + expected = np.array(indices).argsort() + tm.assert_numpy_array_equal(result, expected, check_dtype=False) + + def test_numpy_argsort(self, indices): + result = np.argsort(indices) + expected = indices.argsort() + tm.assert_numpy_array_equal(result, expected) + + # these are the only two types that perform + # pandas compatibility input validation - the + # rest already perform separate (or no) such + # validation via their 'values' attribute as + # defined in pandas.core.indexes/base.py - they + # cannot be changed at the moment due to + # backwards compatibility concerns + if isinstance(type(indices), (CategoricalIndex, RangeIndex)): + msg = "the 'axis' parameter is not supported" + with pytest.raises(ValueError, match=msg): + np.argsort(indices, axis=1) + + msg = "the 'kind' parameter is not supported" + with pytest.raises(ValueError, match=msg): + np.argsort(indices, kind="mergesort") + + msg = "the 'order' parameter is not supported" + with pytest.raises(ValueError, match=msg): + np.argsort(indices, order=("a", "b")) + + def test_take(self, indices): indexer = [4, 3, 0, 2] - for k, ind in self.indices.items(): - - # separate - if k in ["boolIndex", "tuples", "empty"]: - continue + if len(indices) < 5: + # not enough elements; ignore + return - result = ind.take(indexer) - expected = ind[indexer] - assert result.equals(expected) + result = indices.take(indexer) + expected = indices[indexer] + assert result.equals(expected) - if not isinstance(ind, (DatetimeIndex, PeriodIndex, TimedeltaIndex)): - # GH 10791 - with pytest.raises(AttributeError): - ind.freq + if not isinstance(indices, (DatetimeIndex, PeriodIndex, TimedeltaIndex)): + # GH 10791 + with pytest.raises(AttributeError): + indices.freq def test_take_invalid_kwargs(self): idx = self.create_index() @@ -454,173 +441,152 @@ def test_where(self, klass): @pytest.mark.parametrize( "method", ["intersection", "union", "difference", "symmetric_difference"] ) - def test_set_ops_error_cases(self, case, method): - for name, idx in self.indices.items(): - # non-iterable input + def test_set_ops_error_cases(self, case, method, indices): + # non-iterable input + msg = "Input must be Index or array-like" + with pytest.raises(TypeError, match=msg): + getattr(indices, method)(case) - msg = "Input must be Index or array-like" - with pytest.raises(TypeError, match=msg): - getattr(idx, method)(case) + def test_intersection_base(self, indices): + if isinstance(indices, CategoricalIndex): + return - def test_intersection_base(self): - for name, idx in self.indices.items(): - first = idx[:5] - second = idx[:3] - intersect = first.intersection(second) + first = indices[:5] + second = indices[:3] + intersect = first.intersection(second) + assert tm.equalContents(intersect, second) - if isinstance(idx, CategoricalIndex): - pass - else: - assert tm.equalContents(intersect, second) - - # GH 10149 - cases = [klass(second.values) for klass in [np.array, Series, list]] - for case in cases: - if isinstance(idx, CategoricalIndex): - pass - else: - result = first.intersection(case) - assert tm.equalContents(result, second) - - if isinstance(idx, MultiIndex): - msg = "other must be a MultiIndex or a list of tuples" - with pytest.raises(TypeError, match=msg): - first.intersection([1, 2, 3]) - - def test_union_base(self): - for name, idx in self.indices.items(): - first = idx[3:] - second = idx[:5] - everything = idx - union = first.union(second) - assert tm.equalContents(union, everything) - - # GH 10149 - cases = [klass(second.values) for klass in [np.array, Series, list]] - for case in cases: - if isinstance(idx, CategoricalIndex): - pass - else: - result = first.union(case) - assert tm.equalContents(result, everything) - - if isinstance(idx, MultiIndex): - msg = "other must be a MultiIndex or a list of tuples" - with pytest.raises(TypeError, match=msg): - first.union([1, 2, 3]) + # GH 10149 + cases = [klass(second.values) for klass in [np.array, Series, list]] + for case in cases: + result = first.intersection(case) + assert tm.equalContents(result, second) - @pytest.mark.parametrize("sort", [None, False]) - def test_difference_base(self, sort): - for name, idx in self.indices.items(): - first = idx[2:] - second = idx[:4] - answer = idx[4:] - result = first.difference(second, sort) - - if isinstance(idx, CategoricalIndex): - pass - else: - assert tm.equalContents(result, answer) + if isinstance(indices, MultiIndex): + msg = "other must be a MultiIndex or a list of tuples" + with pytest.raises(TypeError, match=msg): + first.intersection([1, 2, 3]) + + def test_union_base(self, indices): + first = indices[3:] + second = indices[:5] + everything = indices + union = first.union(second) + assert tm.equalContents(union, everything) + + # GH 10149 + cases = [klass(second.values) for klass in [np.array, Series, list]] + for case in cases: + if not isinstance(indices, CategoricalIndex): + result = first.union(case) + assert tm.equalContents(result, everything) + + if isinstance(indices, MultiIndex): + msg = "other must be a MultiIndex or a list of tuples" + with pytest.raises(TypeError, match=msg): + first.union([1, 2, 3]) - # GH 10149 - cases = [klass(second.values) for klass in [np.array, Series, list]] - for case in cases: - if isinstance(idx, CategoricalIndex): - pass - elif isinstance(idx, (DatetimeIndex, TimedeltaIndex)): - assert result.__class__ == answer.__class__ - tm.assert_numpy_array_equal( - result.sort_values().asi8, answer.sort_values().asi8 - ) - else: - result = first.difference(case, sort) - assert tm.equalContents(result, answer) - - if isinstance(idx, MultiIndex): - msg = "other must be a MultiIndex or a list of tuples" - with pytest.raises(TypeError, match=msg): - first.difference([1, 2, 3], sort) - - def test_symmetric_difference(self): - for name, idx in self.indices.items(): - first = idx[1:] - second = idx[:-1] - if isinstance(idx, CategoricalIndex): - pass + @pytest.mark.parametrize("sort", [None, False]) + def test_difference_base(self, sort, indices): + if isinstance(indices, CategoricalIndex): + return + + first = indices[2:] + second = indices[:4] + answer = indices[4:] + result = first.difference(second, sort) + assert tm.equalContents(result, answer) + + # GH 10149 + cases = [klass(second.values) for klass in [np.array, Series, list]] + for case in cases: + if isinstance(indices, (DatetimeIndex, TimedeltaIndex)): + assert result.__class__ == answer.__class__ + tm.assert_numpy_array_equal( + result.sort_values().asi8, answer.sort_values().asi8 + ) else: - answer = idx[[0, -1]] - result = first.symmetric_difference(second) + result = first.difference(case, sort) assert tm.equalContents(result, answer) - # GH 10149 - cases = [klass(second.values) for klass in [np.array, Series, list]] - for case in cases: - if isinstance(idx, CategoricalIndex): - pass - else: - result = first.symmetric_difference(case) - assert tm.equalContents(result, answer) - - if isinstance(idx, MultiIndex): - msg = "other must be a MultiIndex or a list of tuples" - with pytest.raises(TypeError, match=msg): - first.symmetric_difference([1, 2, 3]) - - def test_insert_base(self): - - for name, idx in self.indices.items(): - result = idx[1:4] - - if not len(idx): - continue + if isinstance(indices, MultiIndex): + msg = "other must be a MultiIndex or a list of tuples" + with pytest.raises(TypeError, match=msg): + first.difference([1, 2, 3], sort) + + def test_symmetric_difference(self, indices): + if isinstance(indices, CategoricalIndex): + return + + first = indices[1:] + second = indices[:-1] + answer = indices[[0, -1]] + result = first.symmetric_difference(second) + assert tm.equalContents(result, answer) + + # GH 10149 + cases = [klass(second.values) for klass in [np.array, Series, list]] + for case in cases: + result = first.symmetric_difference(case) + assert tm.equalContents(result, answer) + + if isinstance(indices, MultiIndex): + msg = "other must be a MultiIndex or a list of tuples" + with pytest.raises(TypeError, match=msg): + first.symmetric_difference([1, 2, 3]) - # test 0th element - assert idx[0:4].equals(result.insert(0, idx[0])) + def test_insert_base(self, indices): + result = indices[1:4] - def test_delete_base(self): + if not len(indices): + return - for name, idx in self.indices.items(): + # test 0th element + assert indices[0:4].equals(result.insert(0, indices[0])) - if not len(idx): - continue + def test_delete_base(self, indices): + if not len(indices): + return - if isinstance(idx, RangeIndex): - # tested in class - continue + if isinstance(indices, RangeIndex): + # tested in class + return - expected = idx[1:] - result = idx.delete(0) - assert result.equals(expected) - assert result.name == expected.name + expected = indices[1:] + result = indices.delete(0) + assert result.equals(expected) + assert result.name == expected.name - expected = idx[:-1] - result = idx.delete(-1) - assert result.equals(expected) - assert result.name == expected.name + expected = indices[:-1] + result = indices.delete(-1) + assert result.equals(expected) + assert result.name == expected.name - with pytest.raises((IndexError, ValueError)): - # either depending on numpy version - idx.delete(len(idx)) + with pytest.raises((IndexError, ValueError)): + # either depending on numpy version + indices.delete(len(indices)) - def test_equals(self): + def test_equals(self, indices): + if isinstance(indices, IntervalIndex): + # IntervalIndex tested separately + return - for name, idx in self.indices.items(): - assert idx.equals(idx) - assert idx.equals(idx.copy()) - assert idx.equals(idx.astype(object)) + assert indices.equals(indices) + assert indices.equals(indices.copy()) + assert indices.equals(indices.astype(object)) - assert not idx.equals(list(idx)) - assert not idx.equals(np.array(idx)) + assert not indices.equals(list(indices)) + assert not indices.equals(np.array(indices)) - # Cannot pass in non-int64 dtype to RangeIndex - if not isinstance(idx, RangeIndex): - same_values = Index(idx, dtype=object) - assert idx.equals(same_values) - assert same_values.equals(idx) + # Cannot pass in non-int64 dtype to RangeIndex + if not isinstance(indices, RangeIndex): + same_values = Index(indices, dtype=object) + assert indices.equals(same_values) + assert same_values.equals(indices) - if idx.nlevels == 1: - # do not test MultiIndex - assert not idx.equals(pd.Series(idx)) + if indices.nlevels == 1: + # do not test MultiIndex + assert not indices.equals(Series(indices)) def test_equals_op(self): # GH9947, GH10637 @@ -686,107 +652,99 @@ def test_equals_op(self): tm.assert_numpy_array_equal(index_a == item, expected3) tm.assert_series_equal(series_a == item, Series(expected3)) - def test_hasnans_isnans(self): + def test_hasnans_isnans(self, indices): # GH 11343, added tests for hasnans / isnans + if isinstance(indices, MultiIndex): + return + + # cases in indices doesn't include NaN + idx = indices.copy(deep=True) + expected = np.array([False] * len(idx), dtype=bool) + tm.assert_numpy_array_equal(idx._isnan, expected) + assert idx.hasnans is False + + idx = indices.copy(deep=True) + values = np.asarray(idx.values) + + if len(indices) == 0: + return + elif isinstance(indices, DatetimeIndexOpsMixin): + values[1] = iNaT + elif isinstance(indices, (Int64Index, UInt64Index)): + return + else: + values[1] = np.nan - for name, index in self.indices.items(): - if isinstance(index, MultiIndex): - pass - else: - idx = index.copy() - - # cases in indices doesn't include NaN - expected = np.array([False] * len(idx), dtype=bool) - tm.assert_numpy_array_equal(idx._isnan, expected) - assert idx.hasnans is False - - idx = index.copy() - values = np.asarray(idx.values) - - if len(index) == 0: - continue - elif isinstance(index, DatetimeIndexOpsMixin): - values[1] = iNaT - elif isinstance(index, (Int64Index, UInt64Index)): - continue - else: - values[1] = np.nan - - if isinstance(index, PeriodIndex): - idx = index.__class__(values, freq=index.freq) - else: - idx = index.__class__(values) - - expected = np.array([False] * len(idx), dtype=bool) - expected[1] = True - tm.assert_numpy_array_equal(idx._isnan, expected) - assert idx.hasnans is True - - def test_fillna(self): + if isinstance(indices, PeriodIndex): + idx = indices.__class__(values, freq=indices.freq) + else: + idx = indices.__class__(values) + + expected = np.array([False] * len(idx), dtype=bool) + expected[1] = True + tm.assert_numpy_array_equal(idx._isnan, expected) + assert idx.hasnans is True + + def test_fillna(self, indices): # GH 11343 - for name, index in self.indices.items(): - if len(index) == 0: - pass - elif isinstance(index, MultiIndex): - idx = index.copy() - msg = "isna is not defined for MultiIndex" - with pytest.raises(NotImplementedError, match=msg): - idx.fillna(idx[0]) + if len(indices) == 0: + pass + elif isinstance(indices, MultiIndex): + idx = indices.copy(deep=True) + msg = "isna is not defined for MultiIndex" + with pytest.raises(NotImplementedError, match=msg): + idx.fillna(idx[0]) + else: + idx = indices.copy(deep=True) + result = idx.fillna(idx[0]) + tm.assert_index_equal(result, idx) + assert result is not idx + + msg = "'value' must be a scalar, passed: " + with pytest.raises(TypeError, match=msg): + idx.fillna([idx[0]]) + + idx = indices.copy(deep=True) + values = np.asarray(idx.values) + + if isinstance(indices, DatetimeIndexOpsMixin): + values[1] = iNaT + elif isinstance(indices, (Int64Index, UInt64Index)): + return else: - idx = index.copy() - result = idx.fillna(idx[0]) - tm.assert_index_equal(result, idx) - assert result is not idx - - msg = "'value' must be a scalar, passed: " - with pytest.raises(TypeError, match=msg): - idx.fillna([idx[0]]) - - idx = index.copy() - values = np.asarray(idx.values) - - if isinstance(index, DatetimeIndexOpsMixin): - values[1] = iNaT - elif isinstance(index, (Int64Index, UInt64Index)): - continue - else: - values[1] = np.nan - - if isinstance(index, PeriodIndex): - idx = index.__class__(values, freq=index.freq) - else: - idx = index.__class__(values) - - expected = np.array([False] * len(idx), dtype=bool) - expected[1] = True - tm.assert_numpy_array_equal(idx._isnan, expected) - assert idx.hasnans is True - - def test_nulls(self): - # this is really a smoke test for the methods - # as these are adequately tested for function elsewhere + values[1] = np.nan - for name, index in self.indices.items(): - if len(index) == 0: - tm.assert_numpy_array_equal(index.isna(), np.array([], dtype=bool)) - elif isinstance(index, MultiIndex): - idx = index.copy() - msg = "isna is not defined for MultiIndex" - with pytest.raises(NotImplementedError, match=msg): - idx.isna() + if isinstance(indices, PeriodIndex): + idx = indices.__class__(values, freq=indices.freq) else: + idx = indices.__class__(values) - if not index.hasnans: - tm.assert_numpy_array_equal( - index.isna(), np.zeros(len(index), dtype=bool) - ) - tm.assert_numpy_array_equal( - index.notna(), np.ones(len(index), dtype=bool) - ) - else: - result = isna(index) - tm.assert_numpy_array_equal(index.isna(), result) - tm.assert_numpy_array_equal(index.notna(), ~result) + expected = np.array([False] * len(idx), dtype=bool) + expected[1] = True + tm.assert_numpy_array_equal(idx._isnan, expected) + assert idx.hasnans is True + + def test_nulls(self, indices): + # this is really a smoke test for the methods + # as these are adequately tested for function elsewhere + if len(indices) == 0: + tm.assert_numpy_array_equal(indices.isna(), np.array([], dtype=bool)) + elif isinstance(indices, MultiIndex): + idx = indices.copy() + msg = "isna is not defined for MultiIndex" + with pytest.raises(NotImplementedError, match=msg): + idx.isna() + elif not indices.hasnans: + tm.assert_numpy_array_equal( + indices.isna(), np.zeros(len(indices), dtype=bool) + ) + tm.assert_numpy_array_equal( + indices.notna(), np.ones(len(indices), dtype=bool) + ) + else: + result = isna(indices) + tm.assert_numpy_array_equal(indices.isna(), result) + tm.assert_numpy_array_equal(indices.notna(), ~result) def test_empty(self): # GH 15270 diff --git a/pandas/tests/indexes/conftest.py b/pandas/tests/indexes/conftest.py index 12c5fb8339549..2a9a8bf8d824f 100644 --- a/pandas/tests/indexes/conftest.py +++ b/pandas/tests/indexes/conftest.py @@ -5,28 +5,29 @@ from pandas.core.indexes.api import Index, MultiIndex import pandas.util.testing as tm -indices_list = [ - tm.makeUnicodeIndex(100), - tm.makeStringIndex(100), - tm.makeDateIndex(100), - tm.makePeriodIndex(100), - tm.makeTimedeltaIndex(100), - tm.makeIntIndex(100), - tm.makeUIntIndex(100), - tm.makeRangeIndex(100), - tm.makeFloatIndex(100), - Index([True, False]), - tm.makeCategoricalIndex(100), - tm.makeIntervalIndex(100), - Index([]), - MultiIndex.from_tuples(zip(["foo", "bar", "baz"], [1, 2, 3])), - Index([0, 0, 1, 1, 2, 2]), -] - - -@pytest.fixture(params=indices_list, ids=lambda x: type(x).__name__) +indices_dict = { + "unicode": tm.makeUnicodeIndex(100), + "string": tm.makeStringIndex(100), + "datetime": tm.makeDateIndex(100), + "period": tm.makePeriodIndex(100), + "timedelta": tm.makeTimedeltaIndex(100), + "int": tm.makeIntIndex(100), + "uint": tm.makeUIntIndex(100), + "range": tm.makeRangeIndex(100), + "float": tm.makeFloatIndex(100), + "bool": Index([True, False]), + "categorical": tm.makeCategoricalIndex(100), + "interval": tm.makeIntervalIndex(100), + "empty": Index([]), + "tuples": MultiIndex.from_tuples(zip(["foo", "bar", "baz"], [1, 2, 3])), + "repeats": Index([0, 0, 1, 1, 2, 2]), +} + + +@pytest.fixture(params=indices_dict.keys()) def indices(request): - return request.param + # copy to avoid mutation, e.g. setting .name + return indices_dict[request.param].copy() @pytest.fixture(params=[1, np.array(1, dtype=np.int64)]) diff --git a/pandas/tests/indexes/datetimelike.py b/pandas/tests/indexes/datetimelike.py index 7523b250ea291..f7cded9f44918 100644 --- a/pandas/tests/indexes/datetimelike.py +++ b/pandas/tests/indexes/datetimelike.py @@ -58,13 +58,14 @@ def test_view(self): tm.assert_index_equal(result, i_view) def test_map_callable(self): - expected = self.index + self.index.freq - result = self.index.map(lambda x: x + x.freq) + index = self.create_index() + expected = index + index.freq + result = index.map(lambda x: x + x.freq) tm.assert_index_equal(result, expected) # map to NaT - result = self.index.map(lambda x: pd.NaT if x == self.index[0] else x) - expected = pd.Index([pd.NaT] + self.index[1:].tolist()) + result = index.map(lambda x: pd.NaT if x == index[0] else x) + expected = pd.Index([pd.NaT] + index[1:].tolist()) tm.assert_index_equal(result, expected) @pytest.mark.parametrize( @@ -75,23 +76,24 @@ def test_map_callable(self): ], ) def test_map_dictlike(self, mapper): - expected = self.index + self.index.freq + index = self.create_index() + expected = index + index.freq # don't compare the freqs if isinstance(expected, pd.DatetimeIndex): expected.freq = None - result = self.index.map(mapper(expected, self.index)) + result = index.map(mapper(expected, index)) tm.assert_index_equal(result, expected) - expected = pd.Index([pd.NaT] + self.index[1:].tolist()) - result = self.index.map(mapper(expected, self.index)) + expected = pd.Index([pd.NaT] + index[1:].tolist()) + result = index.map(mapper(expected, index)) tm.assert_index_equal(result, expected) # empty map; these map to np.nan because we cannot know # to re-infer things - expected = pd.Index([np.nan] * len(self.index)) - result = self.index.map(mapper([], [])) + expected = pd.Index([np.nan] * len(index)) + result = index.map(mapper([], [])) tm.assert_index_equal(result, expected) def test_asobject_deprecated(self): diff --git a/pandas/tests/indexes/datetimes/test_datetimelike.py b/pandas/tests/indexes/datetimes/test_datetimelike.py index 0f1d7927ee3b4..8fa87f55f404b 100644 --- a/pandas/tests/indexes/datetimes/test_datetimelike.py +++ b/pandas/tests/indexes/datetimes/test_datetimelike.py @@ -1,4 +1,5 @@ """ generic tests from the Datetimelike class """ +import pytest from pandas import DatetimeIndex, date_range from pandas.util import testing as tm @@ -9,12 +10,12 @@ class TestDatetimeIndex(DatetimeLike): _holder = DatetimeIndex - def setup_method(self, method): - self.indices = dict( - index=tm.makeDateIndex(10), - index_dec=date_range("20130110", periods=10, freq="-1D"), - ) - self.setup_indices() + @pytest.fixture( + params=[tm.makeDateIndex(10), date_range("20130110", periods=10, freq="-1D")], + ids=["index_inc", "index_dec"], + ) + def indices(self, request): + return request.param def create_index(self): return date_range("20130101", periods=5) diff --git a/pandas/tests/indexes/interval/test_base.py b/pandas/tests/indexes/interval/test_base.py index b2cb29dafac09..339bdaf79c690 100644 --- a/pandas/tests/indexes/interval/test_base.py +++ b/pandas/tests/indexes/interval/test_base.py @@ -14,10 +14,9 @@ class TestBase(Base): _holder = IntervalIndex - def setup_method(self, method): - self.index = IntervalIndex.from_arrays([0, 1], [1, 2]) - self.index_with_nan = IntervalIndex.from_tuples([(0, 1), np.nan, (1, 2)]) - self.indices = dict(intervalIndex=tm.makeIntervalIndex(10)) + @pytest.fixture + def indices(self): + return tm.makeIntervalIndex(10) def create_index(self, closed="right"): return IntervalIndex.from_breaks(range(11), closed=closed) diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py index ee37be7ab4c14..1a2c58bdfce37 100644 --- a/pandas/tests/indexes/period/test_period.py +++ b/pandas/tests/indexes/period/test_period.py @@ -25,12 +25,15 @@ class TestPeriodIndex(DatetimeLike): _holder = PeriodIndex - def setup_method(self, method): - self.indices = dict( - index=tm.makePeriodIndex(10), - index_dec=period_range("20130101", periods=10, freq="D")[::-1], - ) - self.setup_indices() + @pytest.fixture( + params=[ + tm.makePeriodIndex(10), + period_range("20130101", periods=10, freq="D")[::-1], + ], + ids=["index_inc", "index_dec"], + ) + def indices(self, request): + return request.param def create_index(self): return period_range("20130101", periods=5, freq="D") diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 82d5ddd1ac358..0dc6d24202c34 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -41,6 +41,7 @@ from pandas.core.indexes.api import Index, MultiIndex from pandas.core.sorting import safe_sort from pandas.tests.indexes.common import Base +from pandas.tests.indexes.conftest import indices_dict import pandas.util.testing as tm from pandas.util.testing import assert_almost_equal @@ -48,73 +49,57 @@ class TestIndex(Base): _holder = Index - def setup_method(self, method): - self.indices = dict( - unicodeIndex=tm.makeUnicodeIndex(100), - strIndex=tm.makeStringIndex(100), - dateIndex=tm.makeDateIndex(100), - periodIndex=tm.makePeriodIndex(100), - tdIndex=tm.makeTimedeltaIndex(100), - intIndex=tm.makeIntIndex(100), - uintIndex=tm.makeUIntIndex(100), - rangeIndex=tm.makeRangeIndex(100), - floatIndex=tm.makeFloatIndex(100), - boolIndex=Index([True, False]), - catIndex=tm.makeCategoricalIndex(100), - empty=Index([]), - tuples=MultiIndex.from_tuples(zip(["foo", "bar", "baz"], [1, 2, 3])), - repeats=Index([0, 0, 1, 1, 2, 2]), - ) - self.setup_indices() + @pytest.fixture + def index(self, request): + """ + Fixture for selectively parametrizing indices_dict via indirect parametrization + (parametrize over indices_dict keys with indirect=True). Defaults to string + index if no keys are provided. + """ + key = getattr(request, "param", "string") + + # copy to avoid mutation, e.g. setting .name + return indices_dict[key].copy() def create_index(self): return Index(list("abcde")) - def generate_index_types(self, skip_index_keys=[]): - """ - Return a generator of the various index types, leaving - out the ones with a key in skip_index_keys - """ - for key, index in self.indices.items(): - if key not in skip_index_keys: - yield key, index - def test_can_hold_identifiers(self): index = self.create_index() key = index[0] assert index._can_hold_identifiers_and_holds_name(key) is True - def test_new_axis(self): - new_index = self.dateIndex[None, :] + @pytest.mark.parametrize("index", ["datetime"], indirect=True) + def test_new_axis(self, index): + new_index = index[None, :] assert new_index.ndim == 2 assert isinstance(new_index, np.ndarray) - def test_copy_and_deepcopy(self): - new_copy2 = self.intIndex.copy(dtype=int) + @pytest.mark.parametrize("index", ["int", "uint", "float"], indirect=True) + def test_copy_and_deepcopy(self, index): + new_copy2 = index.copy(dtype=int) assert new_copy2.dtype.kind == "i" - @pytest.mark.parametrize("attr", ["strIndex", "dateIndex"]) - def test_constructor_regular(self, attr): - # regular instance creation - index = getattr(self, attr) - tm.assert_contains_all(index, index) + def test_constructor_regular(self, indices): + tm.assert_contains_all(indices, indices) - def test_constructor_casting(self): + def test_constructor_casting(self, index): # casting - arr = np.array(self.strIndex) - index = Index(arr) - tm.assert_contains_all(arr, index) - tm.assert_index_equal(self.strIndex, index) + arr = np.array(index) + new_index = Index(arr) + tm.assert_contains_all(arr, new_index) + tm.assert_index_equal(index, new_index) - def test_constructor_copy(self): + def test_constructor_copy(self, index): # copy - arr = np.array(self.strIndex) - index = Index(arr, copy=True, name="name") - assert isinstance(index, Index) - assert index.name == "name" - tm.assert_numpy_array_equal(arr, index.values) + # index = self.create_index() + arr = np.array(index) + new_index = Index(arr, copy=True, name="name") + assert isinstance(new_index, Index) + assert new_index.name == "name" + tm.assert_numpy_array_equal(arr, new_index.values) arr[0] = "SOMEBIGLONGSTRING" - assert index[0] != "SOMEBIGLONGSTRING" + assert new_index[0] != "SOMEBIGLONGSTRING" # what to do here? # arr = np.array(5.) @@ -570,37 +555,50 @@ def test_constructor_cast(self): with pytest.raises(ValueError, match=msg): Index(["a", "b", "c"], dtype=float) - def test_view_with_args(self): - restricted = ["unicodeIndex", "strIndex", "catIndex", "boolIndex", "empty"] - for i in list(set(self.indices.keys()) - set(restricted)): - ind = self.indices[i] - ind.view("i8") + @pytest.mark.parametrize( + "index", + [ + "datetime", + "float", + "int", + "period", + "range", + "repeats", + "timedelta", + "tuples", + "uint", + ], + indirect=True, + ) + def test_view_with_args(self, index): + index.view("i8") @pytest.mark.parametrize( - "index_type", + "index", [ - "unicodeIndex", - "strIndex", - pytest.param("catIndex", marks=pytest.mark.xfail(reason="gh-25464")), - "boolIndex", + "unicode", + "string", + pytest.param("categorical", marks=pytest.mark.xfail(reason="gh-25464")), + "bool", "empty", ], + indirect=True, ) - def test_view_with_args_object_array_raises(self, index_type): - ind = self.indices[index_type] + def test_view_with_args_object_array_raises(self, index): msg = "Cannot change data-type for object array" with pytest.raises(TypeError, match=msg): - ind.view("i8") + index.view("i8") - def test_astype(self): - casted = self.intIndex.astype("i8") + @pytest.mark.parametrize("index", ["int", "range"], indirect=True) + def test_astype(self, index): + casted = index.astype("i8") # it works! casted.get_loc(5) # pass on name - self.intIndex.name = "foobar" - casted = self.intIndex.astype("i8") + index.name = "foobar" + casted = index.astype("i8") assert casted.name == "foobar" def test_equals_object(self): @@ -700,16 +698,17 @@ def test_is_(self): ind2 = Index(arr, copy=False) assert not ind1.is_(ind2) - def test_asof(self): - d = self.dateIndex[0] - assert self.dateIndex.asof(d) == d - assert isna(self.dateIndex.asof(d - timedelta(1))) + @pytest.mark.parametrize("index", ["datetime"], indirect=True) + def test_asof(self, index): + d = index[0] + assert index.asof(d) == d + assert isna(index.asof(d - timedelta(1))) - d = self.dateIndex[-1] - assert self.dateIndex.asof(d + timedelta(1)) == d + d = index[-1] + assert index.asof(d + timedelta(1)) == d - d = self.dateIndex[0].to_pydatetime() - assert isinstance(self.dateIndex.asof(d), Timestamp) + d = index[0].to_pydatetime() + assert isinstance(index.asof(d), Timestamp) def test_asof_datetime_partial(self): index = pd.date_range("2010-01-01", periods=2, freq="m") @@ -731,40 +730,39 @@ def test_nanosecond_index_access(self): expected_ts = np_datetime64_compat("2013-01-01 00:00:00.000000050+0000", "ns") assert first_value == x[Timestamp(expected_ts)] - def test_booleanindex(self): - boolIndex = np.repeat(True, len(self.strIndex)).astype(bool) - boolIndex[5:30:2] = False + def test_booleanindex(self, index): + bool_index = np.repeat(True, len(index)).astype(bool) + bool_index[5:30:2] = False - subIndex = self.strIndex[boolIndex] + sub_index = index[bool_index] - for i, val in enumerate(subIndex): - assert subIndex.get_loc(val) == i + for i, val in enumerate(sub_index): + assert sub_index.get_loc(val) == i - subIndex = self.strIndex[list(boolIndex)] - for i, val in enumerate(subIndex): - assert subIndex.get_loc(val) == i + sub_index = index[list(bool_index)] + for i, val in enumerate(sub_index): + assert sub_index.get_loc(val) == i def test_fancy(self): - sl = self.strIndex[[1, 2, 3]] + index = self.create_index() + sl = index[[1, 2, 3]] for i in sl: assert i == sl[sl.get_loc(i)] - @pytest.mark.parametrize("attr", ["strIndex", "intIndex", "floatIndex"]) + @pytest.mark.parametrize("index", ["string", "int", "float"], indirect=True) @pytest.mark.parametrize("dtype", [np.int_, np.bool_]) - def test_empty_fancy(self, attr, dtype): + def test_empty_fancy(self, index, dtype): empty_arr = np.array([], dtype=dtype) - index = getattr(self, attr) empty_index = index.__class__([]) assert index[[]].identical(empty_index) assert index[empty_arr].identical(empty_index) - @pytest.mark.parametrize("attr", ["strIndex", "intIndex", "floatIndex"]) - def test_empty_fancy_raises(self, attr): + @pytest.mark.parametrize("index", ["string", "int", "float"], indirect=True) + def test_empty_fancy_raises(self, index): # pd.DatetimeIndex is excluded, because it overrides getitem and should # be tested separately. empty_farr = np.array([], dtype=np.float_) - index = getattr(self, attr) empty_index = index.__class__([]) assert index[[]].identical(empty_index) @@ -774,9 +772,9 @@ def test_empty_fancy_raises(self, attr): index[empty_farr] @pytest.mark.parametrize("sort", [None, False]) - def test_intersection(self, sort): - first = self.strIndex[:20] - second = self.strIndex[:10] + def test_intersection(self, index, sort): + first = index[:20] + second = index[:10] intersect = first.intersection(second, sort=sort) if sort is None: tm.assert_index_equal(intersect, second.sort_values()) @@ -812,10 +810,10 @@ def test_intersection_name_preservation(self, index2, keeps_name, sort): ) @pytest.mark.parametrize("sort", [None, False]) def test_intersection_name_preservation2( - self, first_name, second_name, expected_name, sort + self, index, first_name, second_name, expected_name, sort ): - first = self.strIndex[5:20] - second = self.strIndex[:10] + first = index[5:20] + second = index[:10] first.name = first_name second.name = second_name intersect = first.intersection(second, sort=sort) @@ -900,11 +898,10 @@ def test_chained_union(self, sort): tm.assert_index_equal(union, expected) @pytest.mark.parametrize("sort", [None, False]) - def test_union(self, sort): - # TODO: Replace with fixturesult - first = self.strIndex[5:20] - second = self.strIndex[:10] - everything = self.strIndex[:20] + def test_union(self, index, sort): + first = index[5:20] + second = index[:10] + everything = index[:20] union = first.union(second, sort=sort) if sort is None: @@ -965,12 +962,11 @@ def test_union_sort_other_incomparable_true(self): @pytest.mark.parametrize("klass", [np.array, Series, list]) @pytest.mark.parametrize("sort", [None, False]) - def test_union_from_iterables(self, klass, sort): + def test_union_from_iterables(self, index, klass, sort): # GH 10149 - # TODO: Replace with fixturesult - first = self.strIndex[5:20] - second = self.strIndex[:10] - everything = self.strIndex[:20] + first = index[5:20] + second = index[:10] + everything = index[:20] case = klass(second.values) result = first.union(case, sort=sort) @@ -979,9 +975,8 @@ def test_union_from_iterables(self, klass, sort): assert tm.equalContents(result, everything) @pytest.mark.parametrize("sort", [None, False]) - def test_union_identity(self, sort): - # TODO: replace with fixturesult - first = self.strIndex[5:20] + def test_union_identity(self, index, sort): + first = index[5:20] union = first.union(first, sort=sort) # i.e. identity is not preserved when sort is True @@ -1021,19 +1016,21 @@ def test_union_name_preservation( @pytest.mark.parametrize("sort", [None, False]) def test_union_dt_as_obj(self, sort): # TODO: Replace with fixturesult - firstCat = self.strIndex.union(self.dateIndex) - secondCat = self.strIndex.union(self.strIndex) + index = self.create_index() + date_index = pd.date_range("2019-01-01", periods=10) + first_cat = index.union(date_index) + second_cat = index.union(index) - if self.dateIndex.dtype == np.object_: - appended = np.append(self.strIndex, self.dateIndex) + if date_index.dtype == np.object_: + appended = np.append(index, date_index) else: - appended = np.append(self.strIndex, self.dateIndex.astype("O")) + appended = np.append(index, date_index.astype("O")) - assert tm.equalContents(firstCat, appended) - assert tm.equalContents(secondCat, self.strIndex) - tm.assert_contains_all(self.strIndex, firstCat) - tm.assert_contains_all(self.strIndex, secondCat) - tm.assert_contains_all(self.dateIndex, firstCat) + assert tm.equalContents(first_cat, appended) + assert tm.equalContents(second_cat, index) + tm.assert_contains_all(index, first_cat) + tm.assert_contains_all(index, second_cat) + tm.assert_contains_all(date_index, first_cat) @pytest.mark.parametrize( "method", ["union", "intersection", "difference", "symmetric_difference"] @@ -1045,11 +1042,9 @@ def test_setops_disallow_true(self, method): with pytest.raises(ValueError, match="The 'sort' keyword only takes"): getattr(idx1, method)(idx2, sort=True) - def test_map_identity_mapping(self): + def test_map_identity_mapping(self, indices): # GH 12766 - # TODO: replace with fixture - for name, cur_index in self.indices.items(): - tm.assert_index_equal(cur_index, cur_index.map(lambda x: x)) + tm.assert_index_equal(indices, indices.map(lambda x: x)) def test_map_with_tuples(self): # GH 12766 @@ -1096,31 +1091,37 @@ def test_map_tseries_indices_accsr_return_index(self): lambda values, index: pd.Series(values, index), ], ) - def test_map_dictlike(self, mapper): + def test_map_dictlike_simple(self, mapper): # GH 12756 expected = Index(["foo", "bar", "baz"]) index = tm.makeIntIndex(3) result = index.map(mapper(expected.values, index)) tm.assert_index_equal(result, expected) - # TODO: replace with fixture - for name in self.indices.keys(): - if name == "catIndex": - # Tested in test_categorical - continue - elif name == "repeats": - # Cannot map duplicated index - continue - - index = self.indices[name] - expected = Index(np.arange(len(index), 0, -1)) - + @pytest.mark.parametrize( + "mapper", + [ + lambda values, index: {i: e for e, i in zip(values, index)}, + lambda values, index: pd.Series(values, index), + ], + ) + def test_map_dictlike(self, indices, mapper): + # GH 12756 + if isinstance(indices, CategoricalIndex): + # Tested in test_categorical + return + elif not indices.is_unique: + # Cannot map duplicated index + return + + if indices.empty: # to match proper result coercion for uints - if name == "empty": - expected = Index([]) + expected = Index([]) + else: + expected = Index(np.arange(len(indices), 0, -1)) - result = index.map(mapper(expected, index)) - tm.assert_index_equal(result, expected) + result = indices.map(mapper(expected, indices)) + tm.assert_index_equal(result, expected) @pytest.mark.parametrize( "mapper", @@ -1169,11 +1170,10 @@ def test_append_empty_preserve_name(self, name, expected): @pytest.mark.parametrize("second_name,expected", [(None, None), ("name", "name")]) @pytest.mark.parametrize("sort", [None, False]) - def test_difference_name_preservation(self, second_name, expected, sort): - # TODO: replace with fixturesult - first = self.strIndex[5:20] - second = self.strIndex[:10] - answer = self.strIndex[10:20] + def test_difference_name_preservation(self, index, second_name, expected, sort): + first = index[5:20] + second = index[:10] + answer = index[10:20] first.name = "name" second.name = second_name @@ -1187,8 +1187,8 @@ def test_difference_name_preservation(self, second_name, expected, sort): assert result.name == expected @pytest.mark.parametrize("sort", [None, False]) - def test_difference_empty_arg(self, sort): - first = self.strIndex[5:20] + def test_difference_empty_arg(self, index, sort): + first = index[5:20] first.name == "name" result = first.difference([], sort) @@ -1196,8 +1196,8 @@ def test_difference_empty_arg(self, sort): assert result.name == first.name @pytest.mark.parametrize("sort", [None, False]) - def test_difference_identity(self, sort): - first = self.strIndex[5:20] + def test_difference_identity(self, index, sort): + first = index[5:20] first.name == "name" result = first.difference(first, sort) @@ -1205,12 +1205,12 @@ def test_difference_identity(self, sort): assert result.name == first.name @pytest.mark.parametrize("sort", [None, False]) - def test_difference_sort(self, sort): - first = self.strIndex[5:20] - second = self.strIndex[:10] + def test_difference_sort(self, index, sort): + first = index[5:20] + second = index[:10] result = first.difference(second, sort) - expected = self.strIndex[10:20] + expected = index[10:20] if sort is None: expected = expected.sort_values() @@ -1267,7 +1267,7 @@ def test_difference_incomparable_true(self, opname): @pytest.mark.parametrize("sort", [None, False]) def test_symmetric_difference_mi(self, sort): - index1 = MultiIndex.from_tuples(self.tuples) + index1 = MultiIndex.from_tuples(zip(["foo", "bar", "baz"], [1, 2, 3])) index2 = MultiIndex.from_tuples([("foo", 1), ("bar", 3)]) result = index1.symmetric_difference(index2, sort=sort) expected = MultiIndex.from_tuples([("bar", 2), ("baz", 3), ("bar", 3)]) @@ -1308,73 +1308,78 @@ def test_symmetric_difference_non_index(self, sort): assert result.name == "new_name" @pytest.mark.parametrize("sort", [None, False]) - def test_difference_type(self, sort): + def test_difference_type(self, indices, sort): # GH 20040 # If taking difference of a set and itself, it # needs to preserve the type of the index - skip_index_keys = ["repeats"] - for key, index in self.generate_index_types(skip_index_keys): - result = index.difference(index, sort=sort) - expected = index.drop(index) - tm.assert_index_equal(result, expected) + if not indices.is_unique: + return + result = indices.difference(indices, sort=sort) + expected = indices.drop(indices) + tm.assert_index_equal(result, expected) @pytest.mark.parametrize("sort", [None, False]) - def test_intersection_difference(self, sort): + def test_intersection_difference(self, indices, sort): # GH 20040 # Test that the intersection of an index with an # empty index produces the same index as the difference # of an index with itself. Test for all types - skip_index_keys = ["repeats"] - for key, index in self.generate_index_types(skip_index_keys): - inter = index.intersection(index.drop(index)) - diff = index.difference(index, sort=sort) - tm.assert_index_equal(inter, diff) + if not indices.is_unique: + return + inter = indices.intersection(indices.drop(indices)) + diff = indices.difference(indices, sort=sort) + tm.assert_index_equal(inter, diff) @pytest.mark.parametrize( - "attr,expected", + "index, expected", [ - ("strIndex", False), - ("boolIndex", False), - ("catIndex", False), - ("intIndex", True), - ("dateIndex", False), - ("floatIndex", True), + ("string", False), + ("bool", False), + ("categorical", False), + ("int", True), + ("datetime", False), + ("float", True), ], + indirect=["index"], ) - def test_is_numeric(self, attr, expected): - assert getattr(self, attr).is_numeric() == expected + def test_is_numeric(self, index, expected): + assert index.is_numeric() is expected @pytest.mark.parametrize( - "attr,expected", + "index, expected", [ - ("strIndex", True), - ("boolIndex", True), - ("catIndex", False), - ("intIndex", False), - ("dateIndex", False), - ("floatIndex", False), + ("string", True), + ("bool", True), + ("categorical", False), + ("int", False), + ("datetime", False), + ("float", False), ], + indirect=["index"], ) - def test_is_object(self, attr, expected): - assert getattr(self, attr).is_object() == expected + def test_is_object(self, index, expected): + assert index.is_object() is expected @pytest.mark.parametrize( - "attr,expected", + "index, expected", [ - ("strIndex", False), - ("boolIndex", False), - ("catIndex", False), - ("intIndex", False), - ("dateIndex", True), - ("floatIndex", False), + ("string", False), + ("bool", False), + ("categorical", False), + ("int", False), + ("datetime", True), + ("float", False), ], + indirect=["index"], ) - def test_is_all_dates(self, attr, expected): - assert getattr(self, attr).is_all_dates == expected + def test_is_all_dates(self, index, expected): + assert index.is_all_dates is expected + + def test_summary(self, indices): + self._check_method_works(Index._summary, indices) - def test_summary(self): - self._check_method_works(Index._summary) - # GH3869 + def test_summary_bug(self): + # GH3869` ind = Index(["{other}%s", "~:{range}:0"], name="A") result = ind._summary() # shouldn't be formatted accidentally. @@ -1388,9 +1393,10 @@ def test_summary_deprecated(self): with tm.assert_produces_warning(FutureWarning): ind.summary() - def test_format(self): - self._check_method_works(Index.format) + def test_format(self, indices): + self._check_method_works(Index.format, indices) + def test_format_bug(self): # GH 14626 # windows has different precision on datetime.datetime.now (it doesn't # include us since the default for Timestamp shows these but Index @@ -1402,7 +1408,7 @@ def test_format(self): expected = [str(index[0])] assert formatted == expected - self.strIndex[:0].format() + Index([]).format() @pytest.mark.parametrize("vals", [[1, 2.0 + 3.0j, 4.0], ["a", "b", "c"]]) def test_format_missing(self, vals, nulls_fixture): @@ -1419,8 +1425,7 @@ def test_format_missing(self, vals, nulls_fixture): def test_format_with_name_time_info(self): # bug I fixed 12/20/2011 - inc = timedelta(hours=4) - dates = Index([dt + inc for dt in self.dateIndex], name="something") + dates = date_range("2011-01-01 04:00:00", periods=10, name="something") formatted = dates.format(name=True) assert formatted[0] == "something" @@ -1438,15 +1443,8 @@ def test_logical_compat(self, op): index = self.create_index() assert getattr(index, op)() == getattr(index.values, op)() - def _check_method_works(self, method): - # TODO: make this a dedicated test with parametrized methods - method(self.empty) - method(self.dateIndex) - method(self.unicodeIndex) - method(self.strIndex) - method(self.intIndex) - method(self.tuples) - method(self.catIndex) + def _check_method_works(self, method, index): + method(index) def test_get_indexer(self): index1 = Index([1, 2, 3, 4, 5]) @@ -1766,38 +1764,37 @@ def test_slice_locs_negative_step(self, in_slice, expected): expected = pd.Index(list(expected)) tm.assert_index_equal(result, expected) - def test_drop_by_str_label(self): - # TODO: Parametrize these after replacing self.strIndex with fixture - n = len(self.strIndex) - drop = self.strIndex[list(range(5, 10))] - dropped = self.strIndex.drop(drop) + @pytest.mark.parametrize("index", ["string", "int", "float"], indirect=True) + def test_drop_by_str_label(self, index): + n = len(index) + drop = index[list(range(5, 10))] + dropped = index.drop(drop) - expected = self.strIndex[list(range(5)) + list(range(10, n))] + expected = index[list(range(5)) + list(range(10, n))] tm.assert_index_equal(dropped, expected) - dropped = self.strIndex.drop(self.strIndex[0]) - expected = self.strIndex[1:] + dropped = index.drop(index[0]) + expected = index[1:] tm.assert_index_equal(dropped, expected) + @pytest.mark.parametrize("index", ["string", "int", "float"], indirect=True) @pytest.mark.parametrize("keys", [["foo", "bar"], ["1", "bar"]]) - def test_drop_by_str_label_raises_missing_keys(self, keys): + def test_drop_by_str_label_raises_missing_keys(self, index, keys): with pytest.raises(KeyError, match=""): - self.strIndex.drop(keys) + index.drop(keys) - def test_drop_by_str_label_errors_ignore(self): - # TODO: Parametrize these after replacing self.strIndex with fixture - - # errors='ignore' - n = len(self.strIndex) - drop = self.strIndex[list(range(5, 10))] + @pytest.mark.parametrize("index", ["string", "int", "float"], indirect=True) + def test_drop_by_str_label_errors_ignore(self, index): + n = len(index) + drop = index[list(range(5, 10))] mixed = drop.tolist() + ["foo"] - dropped = self.strIndex.drop(mixed, errors="ignore") + dropped = index.drop(mixed, errors="ignore") - expected = self.strIndex[list(range(5)) + list(range(10, n))] + expected = index[list(range(5)) + list(range(10, n))] tm.assert_index_equal(dropped, expected) - dropped = self.strIndex.drop(["foo", "bar"], errors="ignore") - expected = self.strIndex[list(range(n))] + dropped = index.drop(["foo", "bar"], errors="ignore") + expected = index[list(range(n))] tm.assert_index_equal(dropped, expected) def test_drop_by_numeric_label_loc(self): @@ -1916,12 +1913,15 @@ def test_set_value_deprecated(self): idx.set_value(arr, idx[1], 80) assert arr[1] == 80 - def test_get_value(self): + @pytest.mark.parametrize( + "index", ["string", "int", "datetime", "timedelta"], indirect=True + ) + def test_get_value(self, index): # TODO: Remove function? GH 19728 values = np.random.randn(100) - date = self.dateIndex[67] + value = index[67] - assert_almost_equal(self.dateIndex.get_value(values, date), values[67]) + assert_almost_equal(index.get_value(values, value), values[67]) @pytest.mark.parametrize("values", [["foo", "bar", "quux"], {"foo", "bar", "quux"}]) @pytest.mark.parametrize( @@ -2040,8 +2040,8 @@ def test_boolean_cmp(self, values): tm.assert_numpy_array_equal(result, expected) @pytest.mark.parametrize("name,level", [(None, 0), ("a", "a")]) - def test_get_level_values(self, name, level): - expected = self.strIndex.copy() + def test_get_level_values(self, index, name, level): + expected = index.copy() if name: expected.name = name @@ -2052,14 +2052,12 @@ def test_slice_keep_name(self): index = Index(["a", "b"], name="asdf") assert index.name == index[1:].name - # instance attributes of the form self.Index - @pytest.mark.parametrize("index_kind", ["unicode", "str", "date", "int", "float"]) - def test_join_self(self, join_type, index_kind): - - res = getattr(self, "{0}Index".format(index_kind)) - - joined = res.join(res, how=join_type) - assert res is joined + @pytest.mark.parametrize( + "index", ["unicode", "string", "datetime", "int", "float"], indirect=True + ) + def test_join_self(self, index, join_type): + joined = index.join(index, how=join_type) + assert index is joined @pytest.mark.parametrize("method", ["strip", "rstrip", "lstrip"]) def test_str_attribute(self, method): @@ -2424,10 +2422,11 @@ def test_tab_complete_warning(self, ip): with provisionalcompleter("ignore"): list(ip.Completer.completions("idx.", 4)) - def test_deprecated_contains(self): - for index in self.indices.values(): - with tm.assert_produces_warning(FutureWarning): - index.contains(1) + def test_deprecated_contains(self, indices): + # deprecated for all types except IntervalIndex + warning = FutureWarning if not isinstance(indices, pd.IntervalIndex) else None + with tm.assert_produces_warning(warning): + indices.contains(1) class TestMixedIntIndex(Base): @@ -2437,12 +2436,12 @@ class TestMixedIntIndex(Base): _holder = Index - def setup_method(self, method): - self.indices = dict(mixedIndex=Index([0, "a", 1, "b", 2, "c"])) - self.setup_indices() + @pytest.fixture(params=[[0, "a", 1, "b", 2, "c"]], ids=["mixedIndex"]) + def indices(self, request): + return Index(request.param) def create_index(self): - return self.mixedIndex + return Index([0, "a", 1, "b", 2, "c"]) def test_argsort(self): index = self.create_index() @@ -2766,13 +2765,12 @@ def test_ensure_index_mixed_closed_intervals(self): ], ) def test_generated_op_names(opname, indices): - index = indices - if isinstance(index, ABCIndex) and opname == "rsub": + if isinstance(indices, ABCIndex) and opname == "rsub": # pd.Index.__rsub__ does not exist; though the method does exist # for subclasses. see GH#19723 return opname = "__{name}__".format(name=opname) - method = getattr(index, opname) + method = getattr(indices, opname) assert method.__name__ == opname diff --git a/pandas/tests/indexes/test_category.py b/pandas/tests/indexes/test_category.py index 67bf9bd20e716..4326c3f8188fc 100644 --- a/pandas/tests/indexes/test_category.py +++ b/pandas/tests/indexes/test_category.py @@ -19,9 +19,9 @@ class TestCategoricalIndex(Base): _holder = CategoricalIndex - def setup_method(self, method): - self.indices = dict(catIndex=tm.makeCategoricalIndex(100)) - self.setup_indices() + @pytest.fixture + def indices(self, request): + return tm.makeCategoricalIndex(100) def create_index(self, categories=None, ordered=False): if categories is None: @@ -780,7 +780,7 @@ def test_identical(self): assert ci1.identical(ci1.copy()) assert not ci1.identical(ci2) - def test_ensure_copied_data(self): + def test_ensure_copied_data(self, indices): # gh-12309: Check the "copy" argument of each # Index.__new__ is honored. # @@ -788,13 +788,12 @@ def test_ensure_copied_data(self): # self.value is not an ndarray. _base = lambda ar: ar if ar.base is None else ar.base - for index in self.indices.values(): - result = CategoricalIndex(index.values, copy=True) - tm.assert_index_equal(index, result) - assert _base(index.values) is not _base(result.values) + result = CategoricalIndex(indices.values, copy=True) + tm.assert_index_equal(indices, result) + assert _base(indices.values) is not _base(result.values) - result = CategoricalIndex(index.values, copy=False) - assert _base(index.values) is _base(result.values) + result = CategoricalIndex(indices.values, copy=False) + assert _base(indices.values) is _base(result.values) def test_equals_categorical(self): ci1 = CategoricalIndex(["a", "b"], categories=["a", "b"], ordered=True) diff --git a/pandas/tests/indexes/test_numeric.py b/pandas/tests/indexes/test_numeric.py index 8bc9783694492..e424b3601a4b2 100644 --- a/pandas/tests/indexes/test_numeric.py +++ b/pandas/tests/indexes/test_numeric.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timedelta import re import numpy as np @@ -87,32 +87,42 @@ def test_where(self, klass): result = i.where(klass(cond)) tm.assert_index_equal(result, expected) - def test_insert(self): + def test_insert(self, nulls_fixture): # GH 18295 (test missing) - expected = Float64Index([0, np.nan, 1, 2, 3, 4]) - for na in (np.nan, pd.NaT, None): - result = self.create_index().insert(1, na) - tm.assert_index_equal(result, expected) + index = self.create_index() + expected = Float64Index([index[0], np.nan] + list(index[1:])) + result = index.insert(1, nulls_fixture) + tm.assert_index_equal(result, expected) class TestFloat64Index(Numeric): _holder = Float64Index - def setup_method(self, method): - self.indices = dict( - mixed=Float64Index([1.5, 2, 3, 4, 5]), - float=Float64Index(np.arange(5) * 2.5), - mixed_dec=Float64Index([5, 4, 3, 2, 1.5]), - float_dec=Float64Index(np.arange(4, -1, -1) * 2.5), - ) - self.setup_indices() + @pytest.fixture( + params=[ + [1.5, 2, 3, 4, 5], + [0.0, 2.5, 5.0, 7.5, 10.0], + [5, 4, 3, 2, 1.5], + [10.0, 7.5, 5.0, 2.5, 0.0], + ], + ids=["mixed", "float", "mixed_dec", "float_dec"], + ) + def indices(self, request): + return Float64Index(request.param) + + @pytest.fixture + def mixed_index(self): + return Float64Index([1.5, 2, 3, 4, 5]) + + @pytest.fixture + def float_index(self): + return Float64Index([0.0, 2.5, 5.0, 7.5, 10.0]) def create_index(self): return Float64Index(np.arange(5, dtype="float64")) - def test_repr_roundtrip(self): - for ind in (self.mixed, self.float): - tm.assert_index_equal(eval(repr(ind)), ind) + def test_repr_roundtrip(self, indices): + tm.assert_index_equal(eval(repr(indices)), indices) def check_is_index(self, i): assert isinstance(i, Index) @@ -176,30 +186,32 @@ def test_constructor_invalid(self): with pytest.raises(TypeError, match=msg): Float64Index([Timestamp("20130101")]) - def test_constructor_coerce(self): + def test_constructor_coerce(self, mixed_index, float_index): - self.check_coerce(self.mixed, Index([1.5, 2, 3, 4, 5])) - self.check_coerce(self.float, Index(np.arange(5) * 2.5)) - self.check_coerce(self.float, Index(np.array(np.arange(5) * 2.5, dtype=object))) + self.check_coerce(mixed_index, Index([1.5, 2, 3, 4, 5])) + self.check_coerce(float_index, Index(np.arange(5) * 2.5)) + self.check_coerce( + float_index, Index(np.array(np.arange(5) * 2.5, dtype=object)) + ) - def test_constructor_explicit(self): + def test_constructor_explicit(self, mixed_index, float_index): # these don't auto convert self.check_coerce( - self.float, Index((np.arange(5) * 2.5), dtype=object), is_float_index=False + float_index, Index((np.arange(5) * 2.5), dtype=object), is_float_index=False ) self.check_coerce( - self.mixed, Index([1.5, 2, 3, 4, 5], dtype=object), is_float_index=False + mixed_index, Index([1.5, 2, 3, 4, 5], dtype=object), is_float_index=False ) - def test_astype(self): + def test_astype(self, mixed_index, float_index): - result = self.float.astype(object) - assert result.equals(self.float) - assert self.float.equals(result) + result = float_index.astype(object) + assert result.equals(float_index) + assert float_index.equals(result) self.check_is_index(result) - i = self.mixed.copy() + i = mixed_index.copy() i.name = "foo" result = i.astype(object) assert result.equals(i) @@ -451,11 +463,12 @@ def test_view(self): tm.assert_index_equal(i, self._holder(i_view, name="Foo")) def test_is_monotonic(self): - assert self.index.is_monotonic is True - assert self.index.is_monotonic_increasing is True - assert self.index._is_strictly_monotonic_increasing is True - assert self.index.is_monotonic_decreasing is False - assert self.index._is_strictly_monotonic_decreasing is False + index = self._holder([1, 2, 3, 4]) + assert index.is_monotonic is True + assert index.is_monotonic_increasing is True + assert index._is_strictly_monotonic_increasing is True + assert index.is_monotonic_decreasing is False + assert index._is_strictly_monotonic_decreasing is False index = self._holder([4, 3, 2, 1]) assert index.is_monotonic is False @@ -490,23 +503,22 @@ def test_logical_compat(self): assert idx.any() == idx.values.any() def test_identical(self): - i = Index(self.index.copy()) - assert i.identical(self.index) + index = self.create_index() + i = Index(index.copy()) + assert i.identical(index) same_values_different_type = Index(i, dtype=object) assert not i.identical(same_values_different_type) - i = self.index.copy(dtype=object) + i = index.copy(dtype=object) i = i.rename("foo") same_values = Index(i, dtype=object) assert same_values.identical(i) - assert not i.identical(self.index) + assert not i.identical(index) assert Index(same_values, name="foo", dtype=object).identical(i) - assert not self.index.copy(dtype=object).identical( - self.index.copy(dtype=self._dtype) - ) + assert not index.copy(dtype=object).identical(index.copy(dtype=self._dtype)) def test_join_non_unique(self): left = Index([4, 4, 3, 3]) @@ -522,23 +534,21 @@ def test_join_non_unique(self): exp_ridx = np.array([2, 3, 2, 3, 0, 1, 0, 1], dtype=np.intp) tm.assert_numpy_array_equal(ridx, exp_ridx) - @pytest.mark.parametrize("kind", ["outer", "inner", "left", "right"]) - def test_join_self(self, kind): - joined = self.index.join(self.index, how=kind) - assert self.index is joined + def test_join_self(self, join_type): + index = self.create_index() + joined = index.join(index, how=join_type) + assert index is joined def test_union_noncomparable(self): - from datetime import datetime, timedelta - # corner case, non-Int64Index - now = datetime.now() - other = Index([now + timedelta(i) for i in range(4)], dtype=object) - result = self.index.union(other) - expected = Index(np.concatenate((self.index, other))) + index = self.create_index() + other = Index([datetime.now() + timedelta(i) for i in range(4)], dtype=object) + result = index.union(other) + expected = Index(np.concatenate((index, other))) tm.assert_index_equal(result, expected) - result = other.union(self.index) - expected = Index(np.concatenate((other, self.index))) + result = other.union(index) + expected = Index(np.concatenate((other, index))) tm.assert_index_equal(result, expected) def test_cant_or_shouldnt_cast(self): @@ -557,10 +567,12 @@ def test_cant_or_shouldnt_cast(self): self._holder(data) def test_view_index(self): - self.index.view(Index) + index = self.create_index() + index.view(Index) def test_prevent_casting(self): - result = self.index.astype("O") + index = self.create_index() + result = index.astype("O") assert result.dtype == np.object_ def test_take_preserve_name(self): @@ -604,15 +616,15 @@ class TestInt64Index(NumericInt): _dtype = "int64" _holder = Int64Index - def setup_method(self, method): - self.indices = dict( - index=Int64Index(np.arange(0, 20, 2)), - index_dec=Int64Index(np.arange(19, -1, -1)), - ) - self.setup_indices() + @pytest.fixture( + params=[range(0, 20, 2), range(19, -1, -1)], ids=["index_inc", "index_dec"] + ) + def indices(self, request): + return Int64Index(request.param) def create_index(self): - return Int64Index(np.arange(5, dtype="int64")) + # return Int64Index(np.arange(5, dtype="int64")) + return Int64Index(range(0, 20, 2)) def test_constructor(self): # pass list, coerce fine @@ -633,9 +645,9 @@ def test_constructor(self): Int64Index(5) # copy - arr = self.index.values + arr = index.values new_index = Int64Index(arr, copy=True) - tm.assert_index_equal(new_index, self.index) + tm.assert_index_equal(new_index, index) val = arr[0] + 3000 # this should not change index @@ -691,39 +703,42 @@ def test_coerce_list(self): assert isinstance(arr, Index) def test_get_indexer(self): + index = self.create_index() target = Int64Index(np.arange(10)) - indexer = self.index.get_indexer(target) + indexer = index.get_indexer(target) expected = np.array([0, -1, 1, -1, 2, -1, 3, -1, 4, -1], dtype=np.intp) tm.assert_numpy_array_equal(indexer, expected) target = Int64Index(np.arange(10)) - indexer = self.index.get_indexer(target, method="pad") + indexer = index.get_indexer(target, method="pad") expected = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4], dtype=np.intp) tm.assert_numpy_array_equal(indexer, expected) target = Int64Index(np.arange(10)) - indexer = self.index.get_indexer(target, method="backfill") + indexer = index.get_indexer(target, method="backfill") expected = np.array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5], dtype=np.intp) tm.assert_numpy_array_equal(indexer, expected) def test_intersection(self): + index = self.create_index() other = Index([1, 2, 3, 4, 5]) - result = self.index.intersection(other) - expected = Index(np.sort(np.intersect1d(self.index.values, other.values))) + result = index.intersection(other) + expected = Index(np.sort(np.intersect1d(index.values, other.values))) tm.assert_index_equal(result, expected) - result = other.intersection(self.index) + result = other.intersection(index) expected = Index( - np.sort(np.asarray(np.intersect1d(self.index.values, other.values))) + np.sort(np.asarray(np.intersect1d(index.values, other.values))) ) tm.assert_index_equal(result, expected) def test_join_inner(self): + index = self.create_index() other = Int64Index([7, 12, 25, 1, 2, 5]) other_mono = Int64Index([1, 2, 5, 7, 12, 25]) # not monotonic - res, lidx, ridx = self.index.join(other, how="inner", return_indexers=True) + res, lidx, ridx = index.join(other, how="inner", return_indexers=True) # no guarantee of sortedness, so sort for comparison purposes ind = res.argsort() @@ -741,9 +756,9 @@ def test_join_inner(self): tm.assert_numpy_array_equal(ridx, eridx) # monotonic - res, lidx, ridx = self.index.join(other_mono, how="inner", return_indexers=True) + res, lidx, ridx = index.join(other_mono, how="inner", return_indexers=True) - res2 = self.index.intersection(other_mono) + res2 = index.intersection(other_mono) tm.assert_index_equal(res, res2) elidx = np.array([1, 6], dtype=np.intp) @@ -754,12 +769,13 @@ def test_join_inner(self): tm.assert_numpy_array_equal(ridx, eridx) def test_join_left(self): + index = self.create_index() other = Int64Index([7, 12, 25, 1, 2, 5]) other_mono = Int64Index([1, 2, 5, 7, 12, 25]) # not monotonic - res, lidx, ridx = self.index.join(other, how="left", return_indexers=True) - eres = self.index + res, lidx, ridx = index.join(other, how="left", return_indexers=True) + eres = index eridx = np.array([-1, 4, -1, -1, -1, -1, 1, -1, -1, -1], dtype=np.intp) assert isinstance(res, Int64Index) @@ -768,7 +784,7 @@ def test_join_left(self): tm.assert_numpy_array_equal(ridx, eridx) # monotonic - res, lidx, ridx = self.index.join(other_mono, how="left", return_indexers=True) + res, lidx, ridx = index.join(other_mono, how="left", return_indexers=True) eridx = np.array([-1, 1, -1, -1, -1, -1, 4, -1, -1, -1], dtype=np.intp) assert isinstance(res, Int64Index) tm.assert_index_equal(res, eres) @@ -787,11 +803,12 @@ def test_join_left(self): tm.assert_numpy_array_equal(ridx, eridx) def test_join_right(self): + index = self.create_index() other = Int64Index([7, 12, 25, 1, 2, 5]) other_mono = Int64Index([1, 2, 5, 7, 12, 25]) # not monotonic - res, lidx, ridx = self.index.join(other, how="right", return_indexers=True) + res, lidx, ridx = index.join(other, how="right", return_indexers=True) eres = other elidx = np.array([-1, 6, -1, -1, 1, -1], dtype=np.intp) @@ -801,7 +818,7 @@ def test_join_right(self): assert ridx is None # monotonic - res, lidx, ridx = self.index.join(other_mono, how="right", return_indexers=True) + res, lidx, ridx = index.join(other_mono, how="right", return_indexers=True) eres = other_mono elidx = np.array([-1, 1, -1, -1, 6, -1], dtype=np.intp) assert isinstance(other, Int64Index) @@ -821,40 +838,42 @@ def test_join_right(self): tm.assert_numpy_array_equal(ridx, eridx) def test_join_non_int_index(self): + index = self.create_index() other = Index([3, 6, 7, 8, 10], dtype=object) - outer = self.index.join(other, how="outer") - outer2 = other.join(self.index, how="outer") + outer = index.join(other, how="outer") + outer2 = other.join(index, how="outer") expected = Index([0, 2, 3, 4, 6, 7, 8, 10, 12, 14, 16, 18]) tm.assert_index_equal(outer, outer2) tm.assert_index_equal(outer, expected) - inner = self.index.join(other, how="inner") - inner2 = other.join(self.index, how="inner") + inner = index.join(other, how="inner") + inner2 = other.join(index, how="inner") expected = Index([6, 8, 10]) tm.assert_index_equal(inner, inner2) tm.assert_index_equal(inner, expected) - left = self.index.join(other, how="left") - tm.assert_index_equal(left, self.index.astype(object)) + left = index.join(other, how="left") + tm.assert_index_equal(left, index.astype(object)) - left2 = other.join(self.index, how="left") + left2 = other.join(index, how="left") tm.assert_index_equal(left2, other) - right = self.index.join(other, how="right") + right = index.join(other, how="right") tm.assert_index_equal(right, other) - right2 = other.join(self.index, how="right") - tm.assert_index_equal(right2, self.index.astype(object)) + right2 = other.join(index, how="right") + tm.assert_index_equal(right2, index.astype(object)) def test_join_outer(self): + index = self.create_index() other = Int64Index([7, 12, 25, 1, 2, 5]) other_mono = Int64Index([1, 2, 5, 7, 12, 25]) # not monotonic # guarantee of sortedness - res, lidx, ridx = self.index.join(other, how="outer", return_indexers=True) - noidx_res = self.index.join(other, how="outer") + res, lidx, ridx = index.join(other, how="outer", return_indexers=True) + noidx_res = index.join(other, how="outer") tm.assert_index_equal(res, noidx_res) eres = Int64Index([0, 1, 2, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 25]) @@ -869,8 +888,8 @@ def test_join_outer(self): tm.assert_numpy_array_equal(ridx, eridx) # monotonic - res, lidx, ridx = self.index.join(other_mono, how="outer", return_indexers=True) - noidx_res = self.index.join(other_mono, how="outer") + res, lidx, ridx = index.join(other_mono, how="outer", return_indexers=True) + noidx_res = index.join(other_mono, how="outer") tm.assert_index_equal(res, noidx_res) elidx = np.array([0, -1, 1, 2, -1, 3, -1, 4, 5, 6, 7, 8, 9, -1], dtype=np.intp) @@ -888,14 +907,24 @@ class TestUInt64Index(NumericInt): _dtype = "uint64" _holder = UInt64Index - def setup_method(self, method): - vals = [2 ** 63, 2 ** 63 + 10, 2 ** 63 + 15, 2 ** 63 + 20, 2 ** 63 + 25] - self.indices = dict( - index=UInt64Index(vals), index_dec=UInt64Index(reversed(vals)) - ) - self.setup_indices() + @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 indices(self, request): + return UInt64Index(request.param) + + @pytest.fixture + def index_large(self): + # large values used in TestUInt64Index where no compat needed with Int64/Float64 + large = [2 ** 63, 2 ** 63 + 10, 2 ** 63 + 15, 2 ** 63 + 20, 2 ** 63 + 25] + return UInt64Index(large) def create_index(self): + # compat with shared Int64/Float64 tests; use index_large for UInt64 only tests return UInt64Index(np.arange(5, dtype="uint64")) def test_constructor(self): @@ -915,42 +944,42 @@ def test_constructor(self): res = Index(np.array([-1, 2 ** 63], dtype=object)) tm.assert_index_equal(res, idx) - def test_get_indexer(self): + def test_get_indexer(self, index_large): target = UInt64Index(np.arange(10).astype("uint64") * 5 + 2 ** 63) - indexer = self.index.get_indexer(target) + indexer = index_large.get_indexer(target) expected = np.array([0, -1, 1, 2, 3, 4, -1, -1, -1, -1], dtype=np.intp) tm.assert_numpy_array_equal(indexer, expected) target = UInt64Index(np.arange(10).astype("uint64") * 5 + 2 ** 63) - indexer = self.index.get_indexer(target, method="pad") + indexer = index_large.get_indexer(target, method="pad") expected = np.array([0, 0, 1, 2, 3, 4, 4, 4, 4, 4], dtype=np.intp) tm.assert_numpy_array_equal(indexer, expected) target = UInt64Index(np.arange(10).astype("uint64") * 5 + 2 ** 63) - indexer = self.index.get_indexer(target, method="backfill") + indexer = index_large.get_indexer(target, method="backfill") expected = np.array([0, 1, 1, 2, 3, 4, -1, -1, -1, -1], dtype=np.intp) tm.assert_numpy_array_equal(indexer, expected) - def test_intersection(self): + def test_intersection(self, index_large): other = Index([2 ** 63, 2 ** 63 + 5, 2 ** 63 + 10, 2 ** 63 + 15, 2 ** 63 + 20]) - result = self.index.intersection(other) - expected = Index(np.sort(np.intersect1d(self.index.values, other.values))) + result = index_large.intersection(other) + expected = Index(np.sort(np.intersect1d(index_large.values, other.values))) tm.assert_index_equal(result, expected) - result = other.intersection(self.index) + result = other.intersection(index_large) expected = Index( - np.sort(np.asarray(np.intersect1d(self.index.values, other.values))) + np.sort(np.asarray(np.intersect1d(index_large.values, other.values))) ) tm.assert_index_equal(result, expected) - def test_join_inner(self): + def test_join_inner(self, index_large): other = UInt64Index(2 ** 63 + np.array([7, 12, 25, 1, 2, 10], dtype="uint64")) other_mono = UInt64Index( 2 ** 63 + np.array([1, 2, 7, 10, 12, 25], dtype="uint64") ) # not monotonic - res, lidx, ridx = self.index.join(other, how="inner", return_indexers=True) + res, lidx, ridx = index_large.join(other, how="inner", return_indexers=True) # no guarantee of sortedness, so sort for comparison purposes ind = res.argsort() @@ -968,9 +997,11 @@ def test_join_inner(self): tm.assert_numpy_array_equal(ridx, eridx) # monotonic - res, lidx, ridx = self.index.join(other_mono, how="inner", return_indexers=True) + res, lidx, ridx = index_large.join( + other_mono, how="inner", return_indexers=True + ) - res2 = self.index.intersection(other_mono) + res2 = index_large.intersection(other_mono) tm.assert_index_equal(res, res2) elidx = np.array([1, 4], dtype=np.intp) @@ -981,15 +1012,15 @@ def test_join_inner(self): tm.assert_numpy_array_equal(lidx, elidx) tm.assert_numpy_array_equal(ridx, eridx) - def test_join_left(self): + def test_join_left(self, index_large): other = UInt64Index(2 ** 63 + np.array([7, 12, 25, 1, 2, 10], dtype="uint64")) other_mono = UInt64Index( 2 ** 63 + np.array([1, 2, 7, 10, 12, 25], dtype="uint64") ) # not monotonic - res, lidx, ridx = self.index.join(other, how="left", return_indexers=True) - eres = self.index + res, lidx, ridx = index_large.join(other, how="left", return_indexers=True) + eres = index_large eridx = np.array([-1, 5, -1, -1, 2], dtype=np.intp) assert isinstance(res, UInt64Index) @@ -998,7 +1029,7 @@ def test_join_left(self): tm.assert_numpy_array_equal(ridx, eridx) # monotonic - res, lidx, ridx = self.index.join(other_mono, how="left", return_indexers=True) + res, lidx, ridx = index_large.join(other_mono, how="left", return_indexers=True) eridx = np.array([-1, 3, -1, -1, 5], dtype=np.intp) assert isinstance(res, UInt64Index) @@ -1020,14 +1051,14 @@ def test_join_left(self): tm.assert_numpy_array_equal(lidx, elidx) tm.assert_numpy_array_equal(ridx, eridx) - def test_join_right(self): + def test_join_right(self, index_large): other = UInt64Index(2 ** 63 + np.array([7, 12, 25, 1, 2, 10], dtype="uint64")) other_mono = UInt64Index( 2 ** 63 + np.array([1, 2, 7, 10, 12, 25], dtype="uint64") ) # not monotonic - res, lidx, ridx = self.index.join(other, how="right", return_indexers=True) + res, lidx, ridx = index_large.join(other, how="right", return_indexers=True) eres = other elidx = np.array([-1, -1, 4, -1, -1, 1], dtype=np.intp) @@ -1037,7 +1068,9 @@ def test_join_right(self): assert ridx is None # monotonic - res, lidx, ridx = self.index.join(other_mono, how="right", return_indexers=True) + res, lidx, ridx = index_large.join( + other_mono, how="right", return_indexers=True + ) eres = other_mono elidx = np.array([-1, -1, -1, 1, -1, 4], dtype=np.intp) @@ -1060,38 +1093,38 @@ def test_join_right(self): tm.assert_numpy_array_equal(lidx, elidx) tm.assert_numpy_array_equal(ridx, eridx) - def test_join_non_int_index(self): + def test_join_non_int_index(self, index_large): other = Index( 2 ** 63 + np.array([1, 5, 7, 10, 20], dtype="uint64"), dtype=object ) - outer = self.index.join(other, how="outer") - outer2 = other.join(self.index, how="outer") + outer = index_large.join(other, how="outer") + outer2 = other.join(index_large, how="outer") expected = Index( 2 ** 63 + np.array([0, 1, 5, 7, 10, 15, 20, 25], dtype="uint64") ) tm.assert_index_equal(outer, outer2) tm.assert_index_equal(outer, expected) - inner = self.index.join(other, how="inner") - inner2 = other.join(self.index, how="inner") + inner = index_large.join(other, how="inner") + inner2 = other.join(index_large, how="inner") expected = Index(2 ** 63 + np.array([10, 20], dtype="uint64")) tm.assert_index_equal(inner, inner2) tm.assert_index_equal(inner, expected) - left = self.index.join(other, how="left") - tm.assert_index_equal(left, self.index.astype(object)) + left = index_large.join(other, how="left") + tm.assert_index_equal(left, index_large.astype(object)) - left2 = other.join(self.index, how="left") + left2 = other.join(index_large, how="left") tm.assert_index_equal(left2, other) - right = self.index.join(other, how="right") + right = index_large.join(other, how="right") tm.assert_index_equal(right, other) - right2 = other.join(self.index, how="right") - tm.assert_index_equal(right2, self.index.astype(object)) + right2 = other.join(index_large, how="right") + tm.assert_index_equal(right2, index_large.astype(object)) - def test_join_outer(self): + def test_join_outer(self, index_large): other = UInt64Index(2 ** 63 + np.array([7, 12, 25, 1, 2, 10], dtype="uint64")) other_mono = UInt64Index( 2 ** 63 + np.array([1, 2, 7, 10, 12, 25], dtype="uint64") @@ -1099,8 +1132,8 @@ def test_join_outer(self): # not monotonic # guarantee of sortedness - res, lidx, ridx = self.index.join(other, how="outer", return_indexers=True) - noidx_res = self.index.join(other, how="outer") + res, lidx, ridx = index_large.join(other, how="outer", return_indexers=True) + noidx_res = index_large.join(other, how="outer") tm.assert_index_equal(res, noidx_res) eres = UInt64Index( @@ -1115,8 +1148,10 @@ def test_join_outer(self): tm.assert_numpy_array_equal(ridx, eridx) # monotonic - res, lidx, ridx = self.index.join(other_mono, how="outer", return_indexers=True) - noidx_res = self.index.join(other_mono, how="outer") + res, lidx, ridx = index_large.join( + other_mono, how="outer", return_indexers=True + ) + noidx_res = index_large.join(other_mono, how="outer") tm.assert_index_equal(res, noidx_res) elidx = np.array([0, -1, -1, -1, 1, -1, 2, 3, 4], dtype=np.intp) diff --git a/pandas/tests/indexes/test_range.py b/pandas/tests/indexes/test_range.py index 627c5cc56e010..fa64e1bacb2e5 100644 --- a/pandas/tests/indexes/test_range.py +++ b/pandas/tests/indexes/test_range.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timedelta import numpy as np import pytest @@ -22,15 +22,18 @@ class TestRangeIndex(Numeric): _holder = RangeIndex _compat_props = ["shape", "ndim", "size"] - def setup_method(self, method): - self.indices = dict( - index=RangeIndex(0, 20, 2, name="foo"), - index_dec=RangeIndex(18, -1, -2, name="bar"), - ) - self.setup_indices() + @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 indices(self, request): + return request.param def create_index(self): - return RangeIndex(5) + return RangeIndex(start=0, stop=20, step=2) def test_can_hold_identifiers(self): idx = self.create_index() @@ -38,8 +41,9 @@ def test_can_hold_identifiers(self): assert idx._can_hold_identifiers_and_holds_name(key) is False def test_too_many_names(self): + index = self.create_index() with pytest.raises(ValueError, match="^Length"): - self.index.names = ["roger", "harold"] + index.names = ["roger", "harold"] @pytest.mark.parametrize("name", [None, "foo"]) @pytest.mark.parametrize( @@ -267,7 +271,8 @@ def test_view(self): tm.assert_index_equal(i, i_view) def test_dtype(self): - assert self.index.dtype == np.int64 + index = self.create_index() + assert index.dtype == np.int64 def test_cached_data(self): # GH 26565, GH26617 @@ -326,11 +331,12 @@ def test_cached_data(self): assert isinstance(idx._cached_data, np.ndarray) def test_is_monotonic(self): - assert self.index.is_monotonic is True - assert self.index.is_monotonic_increasing is True - assert self.index.is_monotonic_decreasing is False - assert self.index._is_strictly_monotonic_increasing is True - assert self.index._is_strictly_monotonic_decreasing is False + index = RangeIndex(0, 20, 2) + assert index.is_monotonic is True + assert index.is_monotonic_increasing is True + assert index.is_monotonic_decreasing is False + assert index._is_strictly_monotonic_increasing is True + assert index._is_strictly_monotonic_decreasing is False index = RangeIndex(4, 0, -1) assert index.is_monotonic is False @@ -376,43 +382,45 @@ def test_logical_compat(self): assert idx.any() == idx.values.any() def test_identical(self): - i = Index(self.index.copy()) - assert i.identical(self.index) + index = self.create_index() + i = Index(index.copy()) + assert i.identical(index) # we don't allow object dtype for RangeIndex - if isinstance(self.index, RangeIndex): + if isinstance(index, RangeIndex): return same_values_different_type = Index(i, dtype=object) assert not i.identical(same_values_different_type) - i = self.index.copy(dtype=object) + i = index.copy(dtype=object) i = i.rename("foo") same_values = Index(i, dtype=object) - assert same_values.identical(self.index.copy(dtype=object)) + assert same_values.identical(index.copy(dtype=object)) - assert not i.identical(self.index) + assert not i.identical(index) assert Index(same_values, name="foo", dtype=object).identical(i) - assert not self.index.copy(dtype=object).identical( - self.index.copy(dtype="int64") - ) + assert not index.copy(dtype=object).identical(index.copy(dtype="int64")) def test_get_indexer(self): + index = self.create_index() target = RangeIndex(10) - indexer = self.index.get_indexer(target) + indexer = index.get_indexer(target) expected = np.array([0, -1, 1, -1, 2, -1, 3, -1, 4, -1], dtype=np.intp) tm.assert_numpy_array_equal(indexer, expected) def test_get_indexer_pad(self): + index = self.create_index() target = RangeIndex(10) - indexer = self.index.get_indexer(target, method="pad") + indexer = index.get_indexer(target, method="pad") expected = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4], dtype=np.intp) tm.assert_numpy_array_equal(indexer, expected) def test_get_indexer_backfill(self): + index = self.create_index() target = RangeIndex(10) - indexer = self.index.get_indexer(target, method="backfill") + indexer = index.get_indexer(target, method="backfill") expected = np.array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5], dtype=np.intp) tm.assert_numpy_array_equal(indexer, expected) @@ -434,10 +442,11 @@ def test_get_indexer_decreasing(self, stop): def test_join_outer(self): # join with Int64Index + index = self.create_index() other = Int64Index(np.arange(25, 14, -1)) - res, lidx, ridx = self.index.join(other, how="outer", return_indexers=True) - noidx_res = self.index.join(other, how="outer") + res, lidx, ridx = index.join(other, how="outer", return_indexers=True) + noidx_res = index.join(other, how="outer") tm.assert_index_equal(res, noidx_res) eres = Int64Index( @@ -461,8 +470,8 @@ def test_join_outer(self): # join with RangeIndex other = RangeIndex(25, 14, -1) - res, lidx, ridx = self.index.join(other, how="outer", return_indexers=True) - noidx_res = self.index.join(other, how="outer") + res, lidx, ridx = index.join(other, how="outer", return_indexers=True) + noidx_res = index.join(other, how="outer") tm.assert_index_equal(res, noidx_res) assert isinstance(res, Int64Index) @@ -473,9 +482,10 @@ def test_join_outer(self): def test_join_inner(self): # Join with non-RangeIndex + index = self.create_index() other = Int64Index(np.arange(25, 14, -1)) - res, lidx, ridx = self.index.join(other, how="inner", return_indexers=True) + res, lidx, ridx = index.join(other, how="inner", return_indexers=True) # no guarantee of sortedness, so sort for comparison purposes ind = res.argsort() @@ -495,7 +505,7 @@ def test_join_inner(self): # Join two RangeIndex other = RangeIndex(25, 14, -1) - res, lidx, ridx = self.index.join(other, how="inner", return_indexers=True) + res, lidx, ridx = index.join(other, how="inner", return_indexers=True) assert isinstance(res, RangeIndex) tm.assert_index_equal(res, eres) @@ -504,10 +514,11 @@ def test_join_inner(self): def test_join_left(self): # Join with Int64Index + index = self.create_index() other = Int64Index(np.arange(25, 14, -1)) - res, lidx, ridx = self.index.join(other, how="left", return_indexers=True) - eres = self.index + res, lidx, ridx = index.join(other, how="left", return_indexers=True) + eres = index eridx = np.array([-1, -1, -1, -1, -1, -1, -1, -1, 9, 7], dtype=np.intp) assert isinstance(res, RangeIndex) @@ -518,7 +529,7 @@ def test_join_left(self): # Join withRangeIndex other = Int64Index(np.arange(25, 14, -1)) - res, lidx, ridx = self.index.join(other, how="left", return_indexers=True) + res, lidx, ridx = index.join(other, how="left", return_indexers=True) assert isinstance(res, RangeIndex) tm.assert_index_equal(res, eres) @@ -527,9 +538,10 @@ def test_join_left(self): def test_join_right(self): # Join with Int64Index + index = self.create_index() other = Int64Index(np.arange(25, 14, -1)) - res, lidx, ridx = self.index.join(other, how="right", return_indexers=True) + res, lidx, ridx = index.join(other, how="right", return_indexers=True) eres = other elidx = np.array([-1, -1, -1, -1, -1, -1, -1, 9, -1, 8, -1], dtype=np.intp) @@ -541,7 +553,7 @@ def test_join_right(self): # Join withRangeIndex other = RangeIndex(25, 14, -1) - res, lidx, ridx = self.index.join(other, how="right", return_indexers=True) + res, lidx, ridx = index.join(other, how="right", return_indexers=True) eres = other assert isinstance(other, RangeIndex) @@ -550,36 +562,38 @@ def test_join_right(self): assert ridx is None def test_join_non_int_index(self): + index = self.create_index() other = Index([3, 6, 7, 8, 10], dtype=object) - outer = self.index.join(other, how="outer") - outer2 = other.join(self.index, how="outer") + outer = index.join(other, how="outer") + outer2 = other.join(index, how="outer") expected = Index([0, 2, 3, 4, 6, 7, 8, 10, 12, 14, 16, 18]) tm.assert_index_equal(outer, outer2) tm.assert_index_equal(outer, expected) - inner = self.index.join(other, how="inner") - inner2 = other.join(self.index, how="inner") + inner = index.join(other, how="inner") + inner2 = other.join(index, how="inner") expected = Index([6, 8, 10]) tm.assert_index_equal(inner, inner2) tm.assert_index_equal(inner, expected) - left = self.index.join(other, how="left") - tm.assert_index_equal(left, self.index.astype(object)) + left = index.join(other, how="left") + tm.assert_index_equal(left, index.astype(object)) - left2 = other.join(self.index, how="left") + left2 = other.join(index, how="left") tm.assert_index_equal(left2, other) - right = self.index.join(other, how="right") + right = index.join(other, how="right") tm.assert_index_equal(right, other) - right2 = other.join(self.index, how="right") - tm.assert_index_equal(right2, self.index.astype(object)) + right2 = other.join(index, how="right") + tm.assert_index_equal(right2, index.astype(object)) def test_join_non_unique(self): + index = self.create_index() other = Index([4, 4, 3, 3]) - res, lidx, ridx = self.index.join(other, return_indexers=True) + res, lidx, ridx = index.join(other, return_indexers=True) eres = Int64Index([0, 2, 4, 4, 6, 8, 10, 12, 14, 16, 18]) elidx = np.array([0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9], dtype=np.intp) @@ -589,40 +603,40 @@ def test_join_non_unique(self): tm.assert_numpy_array_equal(lidx, elidx) tm.assert_numpy_array_equal(ridx, eridx) - def test_join_self(self): - kinds = "outer", "inner", "left", "right" - for kind in kinds: - joined = self.index.join(self.index, how=kind) - assert self.index is joined + def test_join_self(self, join_type): + index = self.create_index() + joined = index.join(index, how=join_type) + assert index is joined @pytest.mark.parametrize("sort", [None, False]) def test_intersection(self, sort): # intersect with Int64Index + index = self.create_index() other = Index(np.arange(1, 6)) - result = self.index.intersection(other, sort=sort) - expected = Index(np.sort(np.intersect1d(self.index.values, other.values))) + result = index.intersection(other, sort=sort) + expected = Index(np.sort(np.intersect1d(index.values, other.values))) tm.assert_index_equal(result, expected) - result = other.intersection(self.index, sort=sort) + result = other.intersection(index, sort=sort) expected = Index( - np.sort(np.asarray(np.intersect1d(self.index.values, other.values))) + np.sort(np.asarray(np.intersect1d(index.values, other.values))) ) tm.assert_index_equal(result, expected) # intersect with increasing RangeIndex other = RangeIndex(1, 6) - result = self.index.intersection(other, sort=sort) - expected = Index(np.sort(np.intersect1d(self.index.values, other.values))) + result = index.intersection(other, sort=sort) + expected = Index(np.sort(np.intersect1d(index.values, other.values))) tm.assert_index_equal(result, expected) # intersect with decreasing RangeIndex other = RangeIndex(5, 0, -1) - result = self.index.intersection(other, sort=sort) - expected = Index(np.sort(np.intersect1d(self.index.values, other.values))) + result = index.intersection(other, sort=sort) + expected = Index(np.sort(np.intersect1d(index.values, other.values))) tm.assert_index_equal(result, expected) # reversed (GH 17296) - result = other.intersection(self.index, sort=sort) + result = other.intersection(index, sort=sort) tm.assert_index_equal(result, expected) # GH 17296: intersect two decreasing RangeIndexes @@ -667,17 +681,15 @@ def test_intersection(self, sort): @pytest.mark.parametrize("sort", [False, None]) def test_union_noncomparable(self, sort): - from datetime import datetime, timedelta - # corner case, non-Int64Index - now = datetime.now() - other = Index([now + timedelta(i) for i in range(4)], dtype=object) - result = self.index.union(other, sort=sort) - expected = Index(np.concatenate((self.index, other))) + index = self.create_index() + other = Index([datetime.now() + timedelta(i) for i in range(4)], dtype=object) + result = index.union(other, sort=sort) + expected = Index(np.concatenate((index, other))) tm.assert_index_equal(result, expected) - result = other.union(self.index, sort=sort) - expected = Index(np.concatenate((other, self.index))) + result = other.union(index, sort=sort) + expected = Index(np.concatenate((other, index))) tm.assert_index_equal(result, expected) @pytest.fixture( @@ -785,11 +797,13 @@ def test_cant_or_shouldnt_cast(self): with pytest.raises(TypeError): RangeIndex("0", "1", "2") - def test_view_Index(self): - self.index.view(Index) + def test_view_index(self): + index = self.create_index() + index.view(Index) def test_prevent_casting(self): - result = self.index.astype("O") + index = self.create_index() + result = index.astype("O") assert result.dtype == np.object_ def test_take_preserve_name(self): @@ -828,7 +842,8 @@ def test_print_unicode_columns(self): repr(df.columns) # should not raise UnicodeDecodeError def test_repr_roundtrip(self): - tm.assert_index_equal(eval(repr(self.index)), self.index) + index = self.create_index() + tm.assert_index_equal(eval(repr(index)), index) def test_slice_keep_name(self): idx = RangeIndex(1, 2, name="asdf") @@ -859,20 +874,17 @@ def test_explicit_conversions(self): result = a - fidx tm.assert_index_equal(result, expected) - def test_has_duplicates(self): - for ind in self.indices: - if not len(ind): - continue - idx = self.indices[ind] - assert idx.is_unique - assert not idx.has_duplicates + def test_has_duplicates(self, indices): + assert indices.is_unique + assert not indices.has_duplicates def test_extended_gcd(self): - result = self.index._extended_gcd(6, 10) + index = self.create_index() + result = index._extended_gcd(6, 10) assert result[0] == result[1] * 6 + result[2] * 10 assert 2 == result[0] - result = self.index._extended_gcd(10, 6) + result = index._extended_gcd(10, 6) assert 2 == result[1] * 10 + result[2] * 6 assert 2 == result[0] @@ -917,80 +929,71 @@ def test_pickle_compat_construction(self): pass def test_slice_specialised(self): + index = self.create_index() + index.name = "foo" # scalar indexing - res = self.index[1] + res = index[1] expected = 2 assert res == expected - res = self.index[-1] + res = index[-1] expected = 18 assert res == expected # slicing # slice value completion - index = self.index[:] - expected = self.index - tm.assert_index_equal(index, expected) + index_slice = index[:] + expected = index + tm.assert_index_equal(index_slice, expected) # positive slice values - index = self.index[7:10:2] + index_slice = index[7:10:2] expected = Index(np.array([14, 18]), name="foo") - tm.assert_index_equal(index, expected) + tm.assert_index_equal(index_slice, expected) # negative slice values - index = self.index[-1:-5:-2] + index_slice = index[-1:-5:-2] expected = Index(np.array([18, 14]), name="foo") - tm.assert_index_equal(index, expected) + tm.assert_index_equal(index_slice, expected) # stop overshoot - index = self.index[2:100:4] + index_slice = index[2:100:4] expected = Index(np.array([4, 12]), name="foo") - tm.assert_index_equal(index, expected) + tm.assert_index_equal(index_slice, expected) # reverse - index = self.index[::-1] - expected = Index(self.index.values[::-1], name="foo") - tm.assert_index_equal(index, expected) + index_slice = index[::-1] + expected = Index(index.values[::-1], name="foo") + tm.assert_index_equal(index_slice, expected) - index = self.index[-8::-1] + index_slice = index[-8::-1] expected = Index(np.array([4, 2, 0]), name="foo") - tm.assert_index_equal(index, expected) + tm.assert_index_equal(index_slice, expected) - index = self.index[-40::-1] + index_slice = index[-40::-1] expected = Index(np.array([], dtype=np.int64), name="foo") - tm.assert_index_equal(index, expected) - - index = self.index[40::-1] - expected = Index(self.index.values[40::-1], name="foo") - tm.assert_index_equal(index, expected) - - index = self.index[10::-1] - expected = Index(self.index.values[::-1], name="foo") - tm.assert_index_equal(index, expected) - - def test_len_specialised(self): - - # make sure that our len is the same as - # np.arange calc - - for step in np.arange(1, 6, 1): + tm.assert_index_equal(index_slice, expected) - arr = np.arange(0, 5, step) - i = RangeIndex(0, 5, step) - assert len(i) == len(arr) + index_slice = index[40::-1] + expected = Index(index.values[40::-1], name="foo") + tm.assert_index_equal(index_slice, expected) - i = RangeIndex(5, 0, step) - assert len(i) == 0 + index_slice = index[10::-1] + expected = Index(index.values[::-1], name="foo") + tm.assert_index_equal(index_slice, expected) - for step in np.arange(-6, -1, 1): + @pytest.mark.parametrize("step", set(range(-5, 6)) - {0}) + def test_len_specialised(self, step): + # make sure that our len is the same as np.arange calc + start, stop = (0, 5) if step > 0 else (5, 0) - arr = np.arange(5, 0, step) - i = RangeIndex(5, 0, step) - assert len(i) == len(arr) + arr = np.arange(start, stop, step) + index = RangeIndex(start, stop, step) + assert len(index) == len(arr) - i = RangeIndex(0, 5, step) - assert len(i) == 0 + index = RangeIndex(stop, start, step) + assert len(index) == 0 @pytest.fixture( params=[ diff --git a/pandas/tests/indexes/test_setops.py b/pandas/tests/indexes/test_setops.py index b3850f7a4e09e..d5b23653e8a72 100644 --- a/pandas/tests/indexes/test_setops.py +++ b/pandas/tests/indexes/test_setops.py @@ -13,7 +13,7 @@ import pandas as pd from pandas import Float64Index, Int64Index, RangeIndex, UInt64Index from pandas.api.types import pandas_dtype -from pandas.tests.indexes.conftest import indices_list +from pandas.tests.indexes.conftest import indices_dict import pandas.util.testing as tm COMPATIBLE_INCONSISTENT_PAIRS = OrderedDict( @@ -26,15 +26,12 @@ ) -@pytest.fixture( - params=list(it.combinations(indices_list, 2)), - ids=lambda x: type(x[0]).__name__ + type(x[1]).__name__, -) +@pytest.fixture(params=it.combinations(indices_dict, 2), ids="-".join) def index_pair(request): """ Create all combinations of 2 index types. """ - return request.param + return indices_dict[request.param[0]], indices_dict[request.param[1]] def test_union_same_types(indices): diff --git a/pandas/tests/indexes/timedeltas/test_timedelta.py b/pandas/tests/indexes/timedeltas/test_timedelta.py index e790a913fcac2..2ef86ddf8c8bf 100644 --- a/pandas/tests/indexes/timedeltas/test_timedelta.py +++ b/pandas/tests/indexes/timedeltas/test_timedelta.py @@ -30,9 +30,9 @@ class TestTimedeltaIndex(DatetimeLike): _holder = TimedeltaIndex - def setup_method(self, method): - self.indices = dict(index=tm.makeTimedeltaIndex(10)) - self.setup_indices() + @pytest.fixture + def indices(self): + return tm.makeTimedeltaIndex(10) def create_index(self): return pd.to_timedelta(range(5), unit="d") + pd.offsets.Hour(1)