diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py index 7f1cf143a3a6e..9f5885fb80bba 100644 --- a/pandas/tests/indexes/common.py +++ b/pandas/tests/indexes/common.py @@ -7,7 +7,6 @@ import pandas.compat as compat from pandas.compat import PY3 -from pandas.core.dtypes.common import needs_i8_conversion from pandas.core.dtypes.dtypes import CategoricalDtype import pandas as pd @@ -29,10 +28,6 @@ def setup_indices(self): for name, idx in self.indices.items(): setattr(self, name, idx) - def verify_pickle(self, indices): - unpickled = tm.round_trip_pickle(indices) - assert indices.equals(unpickled) - def test_pickle_compat_construction(self): # need an object to create with pytest.raises(TypeError, self._holder) @@ -214,11 +209,6 @@ def test_str(self): assert "'foo'" in str(idx) assert idx.__class__.__name__ in str(idx) - def test_dtype_str(self, indices): - dtype = indices.dtype_str - assert isinstance(dtype, compat.string_types) - assert dtype == str(indices.dtype) - def test_repr_max_seq_item_setting(self): # GH10182 idx = self.create_index() @@ -227,44 +217,6 @@ def test_repr_max_seq_item_setting(self): repr(idx) assert '...' not in str(idx) - def test_wrong_number_names(self, indices): - with pytest.raises(ValueError, match="^Length"): - indices.names = ["apple", "banana", "carrot"] - - def test_set_name_methods(self, indices): - new_name = "This is the new name for this index" - - # don't tests a MultiIndex here (as its tested separated) - if isinstance(indices, MultiIndex): - pytest.skip('Skip check for MultiIndex') - original_name = indices.name - new_ind = indices.set_names([new_name]) - assert new_ind.name == new_name - assert indices.name == original_name - res = indices.rename(new_name, inplace=True) - - # should return None - assert res is None - assert indices.name == new_name - assert indices.names == [new_name] - # with pytest.raises(TypeError, match="list-like"): - # # should still fail even if it would be the right length - # ind.set_names("a") - with pytest.raises(ValueError, match="Level must be None"): - indices.set_names("a", level=0) - - # rename in place just leaves tuples and other containers alone - name = ('A', 'B') - indices.rename(name, inplace=True) - assert indices.name == name - assert indices.names == [name] - - def test_hash_error(self, indices): - index = indices - with pytest.raises(TypeError, match=("unhashable type: %r" % - type(index).__name__)): - hash(indices) - def test_copy_name(self): # gh-12309: Check that the "name" argument # passed at initialization is honored. @@ -331,140 +283,6 @@ def test_ensure_copied_data(self): result._ndarray_values, check_same='same') - def test_copy_and_deepcopy(self, indices): - from copy import copy, deepcopy - - if isinstance(indices, MultiIndex): - pytest.skip('Skip check for MultiIndex') - - for func in (copy, deepcopy): - idx_copy = func(indices) - assert idx_copy is not indices - assert idx_copy.equals(indices) - - new_copy = indices.copy(deep=True, name="banana") - assert new_copy.name == "banana" - - def test_has_duplicates(self, indices): - if type(indices) is not self._holder: - pytest.skip('Can only check if we have the correct type') - if not len(indices) or isinstance(indices, MultiIndex): - # MultiIndex tested separately in: - # tests/indexes/multi/test_unique_and_duplicates - pytest.skip('Skip check for empty Index and MultiIndex') - - idx = self._holder([indices[0]] * 5) - assert idx.is_unique is False - assert idx.has_duplicates is True - - @pytest.mark.parametrize('keep', ['first', 'last', False]) - def test_duplicated(self, indices, keep): - if type(indices) is not self._holder: - pytest.skip('Can only check if we know the index type') - if not len(indices) or isinstance(indices, (MultiIndex, RangeIndex)): - # MultiIndex tested separately in: - # tests/indexes/multi/test_unique_and_duplicates - pytest.skip('Skip check for empty Index, MultiIndex, RangeIndex') - - idx = self._holder(indices) - if idx.has_duplicates: - # We are testing the duplicated-method here, so we need to know - # exactly which indices are duplicate and how (for the result). - # This is not possible if "idx" has duplicates already, which we - # therefore remove. This is seemingly circular, as drop_duplicates - # invokes duplicated, but in the end, it all works out because we - # cross-check with Series.duplicated, which is tested separately. - idx = idx.drop_duplicates() - - n, k = len(idx), 10 - duplicated_selection = np.random.choice(n, k * n) - expected = pd.Series(duplicated_selection).duplicated(keep=keep).values - idx = self._holder(idx.values[duplicated_selection]) - - result = idx.duplicated(keep=keep) - tm.assert_numpy_array_equal(result, expected) - - def test_unique(self, indices): - # don't test a MultiIndex here (as its tested separated) - # don't test a CategoricalIndex because categories change (GH 18291) - if isinstance(indices, (MultiIndex, CategoricalIndex)): - pytest.skip('Skip check for MultiIndex/CategoricalIndex') - - # GH 17896 - expected = indices.drop_duplicates() - for level in 0, indices.name, None: - result = indices.unique(level=level) - tm.assert_index_equal(result, expected) - - for level in 3, 'wrong': - pytest.raises((IndexError, KeyError), indices.unique, level=level) - - def test_unique_na(self): - idx = pd.Index([2, np.nan, 2, 1], name='my_index') - expected = pd.Index([2, np.nan, 1], name='my_index') - result = idx.unique() - tm.assert_index_equal(result, expected) - - def test_get_unique_index(self, indices): - # MultiIndex tested separately - if not len(indices) or isinstance(indices, MultiIndex): - pytest.skip('Skip check for empty Index and MultiIndex') - - idx = indices[[0] * 5] - idx_unique = indices[[0]] - - # We test against `idx_unique`, so first we make sure it's unique - # and doesn't contain nans. - assert idx_unique.is_unique is True - try: - assert idx_unique.hasnans is False - except NotImplementedError: - pass - - for dropna in [False, True]: - result = idx._get_unique_index(dropna=dropna) - tm.assert_index_equal(result, idx_unique) - - # nans: - if not indices._can_hold_na: - pytest.skip('Skip na-check if index cannot hold na') - - if needs_i8_conversion(indices): - vals = indices.asi8[[0] * 5] - vals[0] = iNaT - else: - vals = indices.values[[0] * 5] - vals[0] = np.nan - - vals_unique = vals[:2] - idx_nan = indices._shallow_copy(vals) - idx_unique_nan = indices._shallow_copy(vals_unique) - assert idx_unique_nan.is_unique is True - - assert idx_nan.dtype == indices.dtype - assert idx_unique_nan.dtype == indices.dtype - - for dropna, expected in zip([False, True], - [idx_unique_nan, - idx_unique]): - for i in [idx_nan, idx_unique_nan]: - result = i._get_unique_index(dropna=dropna) - tm.assert_index_equal(result, expected) - - def test_sort(self, indices): - pytest.raises(TypeError, indices.sort) - - def test_mutability(self, indices): - if not len(indices): - pytest.skip('Skip check for empty Index') - pytest.raises(TypeError, indices.__setitem__, 0, indices[0]) - - def test_view(self, indices): - assert indices.view().name == indices.name - - def test_compat(self, indices): - assert indices.tolist() == list(indices) - def test_memory_usage(self): for name, index in compat.iteritems(self.indices): result = index.memory_usage() @@ -523,12 +341,6 @@ def test_numpy_argsort(self): with pytest.raises(ValueError, match=msg): np.argsort(ind, order=('a', 'b')) - def test_pickle(self, indices): - self.verify_pickle(indices) - original_name, indices.name = indices.name, 'foo' - self.verify_pickle(indices) - indices.name = original_name - def test_take(self): indexer = [4, 3, 0, 2] for k, ind in self.indices.items(): @@ -1015,51 +827,6 @@ def test_join_self_unique(self, join_type): joined = index.join(index, how=join_type) assert (index == joined).all() - def test_searchsorted_monotonic(self, indices): - # GH17271 - # not implemented for tuple searches in MultiIndex - # or Intervals searches in IntervalIndex - if isinstance(indices, (MultiIndex, IntervalIndex)): - pytest.skip('Skip check for MultiIndex/IntervalIndex') - - # nothing to test if the index is empty - if indices.empty: - pytest.skip('Skip check for empty Index') - value = indices[0] - - # determine the expected results (handle dupes for 'right') - expected_left, expected_right = 0, (indices == value).argmin() - if expected_right == 0: - # all values are the same, expected_right should be length - expected_right = len(indices) - - # test _searchsorted_monotonic in all cases - # test searchsorted only for increasing - if indices.is_monotonic_increasing: - ssm_left = indices._searchsorted_monotonic(value, side='left') - assert expected_left == ssm_left - - ssm_right = indices._searchsorted_monotonic(value, side='right') - assert expected_right == ssm_right - - ss_left = indices.searchsorted(value, side='left') - assert expected_left == ss_left - - ss_right = indices.searchsorted(value, side='right') - assert expected_right == ss_right - - elif indices.is_monotonic_decreasing: - ssm_left = indices._searchsorted_monotonic(value, side='left') - assert expected_left == ssm_left - - ssm_right = indices._searchsorted_monotonic(value, side='right') - assert expected_right == ssm_right - - else: - # non-monotonic should raise. - with pytest.raises(ValueError): - indices._searchsorted_monotonic(value, side='left') - def test_map(self): # callable index = self.create_index() diff --git a/pandas/tests/indexes/datetimelike.py b/pandas/tests/indexes/datetimelike.py index b798ac34255f1..180033c2d2619 100644 --- a/pandas/tests/indexes/datetimelike.py +++ b/pandas/tests/indexes/datetimelike.py @@ -47,9 +47,7 @@ def test_str(self): if hasattr(idx, 'freq'): assert "freq='%s'" % idx.freqstr in str(idx) - def test_view(self, indices): - super(DatetimeLike, self).test_view(indices) - + def test_view(self): i = self.create_index() i_view = i.view('i8') diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 1b3b48075e292..7028b5c23225c 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -15,14 +15,16 @@ from pandas import ( CategoricalIndex, DataFrame, DatetimeIndex, Float64Index, Int64Index, PeriodIndex, RangeIndex, Series, TimedeltaIndex, UInt64Index, date_range, - isna, period_range + isna, period_range, ) from pandas._libs.tslib import Timestamp from pandas.compat import ( PY3, PY35, PY36, StringIO, lrange, lzip, range, text_type, u, zip ) from pandas.compat.numpy import np_datetime64_compat -from pandas.core.dtypes.common import is_unsigned_integer_dtype +from pandas.core.dtypes.common import ( + is_unsigned_integer_dtype, +) from pandas.core.dtypes.generic import ABCIndex from pandas.core.index import _get_combined_index, ensure_index_from_sequences from pandas.core.indexes.api import Index, MultiIndex @@ -75,9 +77,7 @@ def test_new_axis(self): assert new_index.ndim == 2 assert isinstance(new_index, np.ndarray) - def test_copy_and_deepcopy(self, indices): - super(TestIndex, self).test_copy_and_deepcopy(indices) - + def test_copy_and_deepcopy(self): new_copy2 = self.intIndex.copy(dtype=int) assert new_copy2.dtype.kind == 'i' @@ -252,25 +252,6 @@ def test_constructor_int_dtype_nan(self): result = Index(data, dtype='float') tm.assert_index_equal(result, expected) - def test_droplevel(self, indices): - # GH 21115 - if isinstance(indices, MultiIndex): - # Tested separately in test_multi.py - return - - assert indices.droplevel([]).equals(indices) - - for level in indices.name, [indices.name]: - if isinstance(indices.name, tuple) and level is indices.name: - # GH 21121 : droplevel with tuple name - continue - with pytest.raises(ValueError): - indices.droplevel(level) - - for level in 'wrong', ['wrong']: - with pytest.raises(KeyError): - indices.droplevel(level) - @pytest.mark.parametrize("dtype", ['int64', 'uint64']) def test_constructor_int_dtype_nan_raises(self, dtype): # see gh-15187 @@ -473,23 +454,6 @@ def test_constructor_empty_special(self, empty, klass): assert isinstance(empty, klass) assert not len(empty) - def test_constructor_non_hashable_name(self, indices): - # GH 20527 - - if isinstance(indices, MultiIndex): - pytest.skip("multiindex handled in test_multi.py") - - message = "Index.name must be a hashable type" - renamed = [['1']] - - # With .rename() - with pytest.raises(TypeError, match=message): - indices.rename(name=renamed) - - # With .set_names() - with pytest.raises(TypeError, match=message): - indices.set_names(names=renamed) - def test_constructor_overflow_int64(self): # see gh-15832 msg = ("The elements provided in the data cannot " @@ -505,13 +469,6 @@ def test_constructor_cast(self): with pytest.raises(ValueError, match=msg): Index(["a", "b", "c"], dtype=float) - def test_constructor_unwraps_index(self, indices): - if isinstance(indices, pd.MultiIndex): - raise pytest.skip("MultiIndex has no ._data") - a = indices - b = type(a)(a) - tm.assert_equal(a._data, b._data) - def test_view_with_args(self): restricted = ['unicodeIndex', 'strIndex', 'catIndex', 'boolIndex', @@ -726,13 +683,6 @@ def test_empty_fancy_raises(self, attr): # np.ndarray only accepts ndarray of int & bool dtypes, so should Index pytest.raises(IndexError, index.__getitem__, empty_farr) - @pytest.mark.parametrize("itm", [101, 'no_int']) - # FutureWarning from non-tuple sequence of nd indexing - @pytest.mark.filterwarnings("ignore::FutureWarning") - def test_getitem_error(self, indices, itm): - with pytest.raises(IndexError): - indices[itm] - def test_intersection(self): first = self.strIndex[:20] second = self.strIndex[:10] @@ -801,51 +751,6 @@ def test_intersect_str_dates(self): assert len(result) == 0 - @pytest.mark.parametrize( - 'fname, sname, expected_name', - [ - ('A', 'A', 'A'), - ('A', 'B', None), - ('A', None, None), - (None, 'B', None), - (None, None, None), - ]) - def test_corner_union(self, indices, fname, sname, expected_name): - # GH 9943 9862 - # Test unions with various name combinations - # Do not test MultiIndex or repeats - - if isinstance(indices, MultiIndex) or not indices.is_unique: - pytest.skip("Not for MultiIndex or repeated indices") - - # Test copy.union(copy) - first = indices.copy().set_names(fname) - second = indices.copy().set_names(sname) - union = first.union(second) - expected = indices.copy().set_names(expected_name) - tm.assert_index_equal(union, expected) - - # Test copy.union(empty) - first = indices.copy().set_names(fname) - second = indices.drop(indices).set_names(sname) - union = first.union(second) - expected = indices.copy().set_names(expected_name) - tm.assert_index_equal(union, expected) - - # Test empty.union(copy) - first = indices.drop(indices).set_names(fname) - second = indices.copy().set_names(sname) - union = first.union(second) - expected = indices.copy().set_names(expected_name) - tm.assert_index_equal(union, expected) - - # Test empty.union(empty) - first = indices.drop(indices).set_names(fname) - second = indices.drop(indices).set_names(sname) - union = first.union(second) - expected = indices.drop(indices).set_names(expected_name) - tm.assert_index_equal(union, expected) - def test_chained_union(self): # Chained unions handles names correctly i1 = Index([1, 2], name='i1') @@ -2292,14 +2197,6 @@ def test_tab_complete_warning(self, ip): with provisionalcompleter('ignore'): list(ip.Completer.completions('idx.', 4)) - def test_to_flat_index(self, indices): - # 22866 - if isinstance(indices, MultiIndex): - pytest.skip("Separate expectation for MultiIndex") - - result = indices.to_flat_index() - tm.assert_index_equal(result, indices) - class TestMixedIntIndex(Base): # Mostly the tests from common.py for which the results differ @@ -2422,6 +2319,12 @@ def test_union_different_type_base(self, klass): assert tm.equalContents(result, index) + def test_unique_na(self): + idx = pd.Index([2, np.nan, 2, 1], name='my_index') + expected = pd.Index([2, np.nan, 1], name='my_index') + result = idx.unique() + tm.assert_index_equal(result, expected) + def test_intersection_base(self): # (same results for py2 and py3 but sortedness not tested elsewhere) index = self.create_index() diff --git a/pandas/tests/indexes/test_common.py b/pandas/tests/indexes/test_common.py new file mode 100644 index 0000000000000..fd356202a8ce5 --- /dev/null +++ b/pandas/tests/indexes/test_common.py @@ -0,0 +1,343 @@ +""" +Collection of tests asserting things that should be true for +any index subclass. Makes use of the `indices` fixture defined +in pandas/tests/indexes/conftest.py. +""" +import numpy as np +import pytest + +from pandas._libs.tslibs import iNaT + +from pandas.core.dtypes.common import needs_i8_conversion + +import pandas as pd +from pandas import CategoricalIndex, MultiIndex, RangeIndex, compat +import pandas.util.testing as tm + + +class TestCommon(object): + + def test_droplevel(self, indices): + # GH 21115 + if isinstance(indices, MultiIndex): + # Tested separately in test_multi.py + return + + assert indices.droplevel([]).equals(indices) + + for level in indices.name, [indices.name]: + if isinstance(indices.name, tuple) and level is indices.name: + # GH 21121 : droplevel with tuple name + continue + with pytest.raises(ValueError): + indices.droplevel(level) + + for level in 'wrong', ['wrong']: + with pytest.raises(KeyError): + indices.droplevel(level) + + def test_constructor_non_hashable_name(self, indices): + # GH 20527 + + if isinstance(indices, MultiIndex): + pytest.skip("multiindex handled in test_multi.py") + + message = "Index.name must be a hashable type" + renamed = [['1']] + + # With .rename() + with pytest.raises(TypeError, match=message): + indices.rename(name=renamed) + + # With .set_names() + with pytest.raises(TypeError, match=message): + indices.set_names(names=renamed) + + def test_constructor_unwraps_index(self, indices): + if isinstance(indices, pd.MultiIndex): + raise pytest.skip("MultiIndex has no ._data") + a = indices + b = type(a)(a) + tm.assert_equal(a._data, b._data) + + @pytest.mark.parametrize("itm", [101, 'no_int']) + # FutureWarning from non-tuple sequence of nd indexing + @pytest.mark.filterwarnings("ignore::FutureWarning") + def test_getitem_error(self, indices, itm): + with pytest.raises(IndexError): + indices[itm] + + @pytest.mark.parametrize( + 'fname, sname, expected_name', + [ + ('A', 'A', 'A'), + ('A', 'B', None), + ('A', None, None), + (None, 'B', None), + (None, None, None), + ]) + def test_corner_union(self, indices, fname, sname, expected_name): + # GH 9943 9862 + # Test unions with various name combinations + # Do not test MultiIndex or repeats + + if isinstance(indices, MultiIndex) or not indices.is_unique: + pytest.skip("Not for MultiIndex or repeated indices") + + # Test copy.union(copy) + first = indices.copy().set_names(fname) + second = indices.copy().set_names(sname) + union = first.union(second) + expected = indices.copy().set_names(expected_name) + tm.assert_index_equal(union, expected) + + # Test copy.union(empty) + first = indices.copy().set_names(fname) + second = indices.drop(indices).set_names(sname) + union = first.union(second) + expected = indices.copy().set_names(expected_name) + tm.assert_index_equal(union, expected) + + # Test empty.union(copy) + first = indices.drop(indices).set_names(fname) + second = indices.copy().set_names(sname) + union = first.union(second) + expected = indices.copy().set_names(expected_name) + tm.assert_index_equal(union, expected) + + # Test empty.union(empty) + first = indices.drop(indices).set_names(fname) + second = indices.drop(indices).set_names(sname) + union = first.union(second) + expected = indices.drop(indices).set_names(expected_name) + tm.assert_index_equal(union, expected) + + def test_to_flat_index(self, indices): + # 22866 + if isinstance(indices, MultiIndex): + pytest.skip("Separate expectation for MultiIndex") + + result = indices.to_flat_index() + tm.assert_index_equal(result, indices) + + def test_wrong_number_names(self, indices): + with pytest.raises(ValueError, match="^Length"): + indices.names = ["apple", "banana", "carrot"] + + def test_set_name_methods(self, indices): + new_name = "This is the new name for this index" + + # don't tests a MultiIndex here (as its tested separated) + if isinstance(indices, MultiIndex): + pytest.skip('Skip check for MultiIndex') + original_name = indices.name + new_ind = indices.set_names([new_name]) + assert new_ind.name == new_name + assert indices.name == original_name + res = indices.rename(new_name, inplace=True) + + # should return None + assert res is None + assert indices.name == new_name + assert indices.names == [new_name] + # with pytest.raises(TypeError, match="list-like"): + # # should still fail even if it would be the right length + # ind.set_names("a") + with pytest.raises(ValueError, match="Level must be None"): + indices.set_names("a", level=0) + + # rename in place just leaves tuples and other containers alone + name = ('A', 'B') + indices.rename(name, inplace=True) + assert indices.name == name + assert indices.names == [name] + + def test_dtype_str(self, indices): + dtype = indices.dtype_str + assert isinstance(dtype, compat.string_types) + assert dtype == str(indices.dtype) + + def test_hash_error(self, indices): + index = indices + with pytest.raises(TypeError, match=("unhashable type: %r" % + type(index).__name__)): + hash(indices) + + def test_copy_and_deepcopy(self, indices): + from copy import copy, deepcopy + + if isinstance(indices, MultiIndex): + pytest.skip('Skip check for MultiIndex') + + for func in (copy, deepcopy): + idx_copy = func(indices) + assert idx_copy is not indices + assert idx_copy.equals(indices) + + new_copy = indices.copy(deep=True, name="banana") + assert new_copy.name == "banana" + + def test_unique(self, indices): + # don't test a MultiIndex here (as its tested separated) + # don't test a CategoricalIndex because categories change (GH 18291) + if isinstance(indices, (MultiIndex, CategoricalIndex)): + pytest.skip('Skip check for MultiIndex/CategoricalIndex') + + # GH 17896 + expected = indices.drop_duplicates() + for level in 0, indices.name, None: + result = indices.unique(level=level) + tm.assert_index_equal(result, expected) + + for level in 3, 'wrong': + pytest.raises((IndexError, KeyError), indices.unique, level=level) + + def test_get_unique_index(self, indices): + # MultiIndex tested separately + if not len(indices) or isinstance(indices, MultiIndex): + pytest.skip('Skip check for empty Index and MultiIndex') + + idx = indices[[0] * 5] + idx_unique = indices[[0]] + + # We test against `idx_unique`, so first we make sure it's unique + # and doesn't contain nans. + assert idx_unique.is_unique is True + try: + assert idx_unique.hasnans is False + except NotImplementedError: + pass + + for dropna in [False, True]: + result = idx._get_unique_index(dropna=dropna) + tm.assert_index_equal(result, idx_unique) + + # nans: + if not indices._can_hold_na: + pytest.skip('Skip na-check if index cannot hold na') + + if needs_i8_conversion(indices): + vals = indices.asi8[[0] * 5] + vals[0] = iNaT + else: + vals = indices.values[[0] * 5] + vals[0] = np.nan + + vals_unique = vals[:2] + idx_nan = indices._shallow_copy(vals) + idx_unique_nan = indices._shallow_copy(vals_unique) + assert idx_unique_nan.is_unique is True + + assert idx_nan.dtype == indices.dtype + assert idx_unique_nan.dtype == indices.dtype + + for dropna, expected in zip([False, True], + [idx_unique_nan, + idx_unique]): + for i in [idx_nan, idx_unique_nan]: + result = i._get_unique_index(dropna=dropna) + tm.assert_index_equal(result, expected) + + def test_sort(self, indices): + pytest.raises(TypeError, indices.sort) + + def test_mutability(self, indices): + if not len(indices): + pytest.skip('Skip check for empty Index') + pytest.raises(TypeError, indices.__setitem__, 0, indices[0]) + + def test_view(self, indices): + assert indices.view().name == indices.name + + def test_compat(self, indices): + assert indices.tolist() == list(indices) + + def test_searchsorted_monotonic(self, indices): + # GH17271 + # not implemented for tuple searches in MultiIndex + # or Intervals searches in IntervalIndex + if isinstance(indices, (MultiIndex, pd.IntervalIndex)): + pytest.skip('Skip check for MultiIndex/IntervalIndex') + + # nothing to test if the index is empty + if indices.empty: + pytest.skip('Skip check for empty Index') + value = indices[0] + + # determine the expected results (handle dupes for 'right') + expected_left, expected_right = 0, (indices == value).argmin() + if expected_right == 0: + # all values are the same, expected_right should be length + expected_right = len(indices) + + # test _searchsorted_monotonic in all cases + # test searchsorted only for increasing + if indices.is_monotonic_increasing: + ssm_left = indices._searchsorted_monotonic(value, side='left') + assert expected_left == ssm_left + + ssm_right = indices._searchsorted_monotonic(value, side='right') + assert expected_right == ssm_right + + ss_left = indices.searchsorted(value, side='left') + assert expected_left == ss_left + + ss_right = indices.searchsorted(value, side='right') + assert expected_right == ss_right + + elif indices.is_monotonic_decreasing: + ssm_left = indices._searchsorted_monotonic(value, side='left') + assert expected_left == ssm_left + + ssm_right = indices._searchsorted_monotonic(value, side='right') + assert expected_right == ssm_right + else: + # non-monotonic should raise. + with pytest.raises(ValueError): + indices._searchsorted_monotonic(value, side='left') + + def test_pickle(self, indices): + original_name, indices.name = indices.name, 'foo' + unpickled = tm.round_trip_pickle(indices) + assert indices.equals(unpickled) + indices.name = original_name + + @pytest.mark.parametrize('keep', ['first', 'last', False]) + def test_duplicated(self, indices, keep): + if not len(indices) or isinstance(indices, (MultiIndex, RangeIndex)): + # MultiIndex tested separately in: + # tests/indexes/multi/test_unique_and_duplicates + pytest.skip('Skip check for empty Index, MultiIndex, RangeIndex') + + holder = type(indices) + + idx = holder(indices) + if idx.has_duplicates: + # We are testing the duplicated-method here, so we need to know + # exactly which indices are duplicate and how (for the result). + # This is not possible if "idx" has duplicates already, which we + # therefore remove. This is seemingly circular, as drop_duplicates + # invokes duplicated, but in the end, it all works out because we + # cross-check with Series.duplicated, which is tested separately. + idx = idx.drop_duplicates() + + n, k = len(idx), 10 + duplicated_selection = np.random.choice(n, k * n) + expected = pd.Series(duplicated_selection).duplicated(keep=keep).values + idx = holder(idx.values[duplicated_selection]) + + result = idx.duplicated(keep=keep) + tm.assert_numpy_array_equal(result, expected) + + def test_has_duplicates(self, indices): + holder = type(indices) + if not len(indices) or isinstance(indices, (MultiIndex, RangeIndex)): + # MultiIndex tested separately in: + # tests/indexes/multi/test_unique_and_duplicates. + # RangeIndex is unique by definition. + pytest.skip('Skip check for empty Index, MultiIndex, ' + 'and RangeIndex') + + idx = holder([indices[0]] * 5) + assert idx.is_unique is False + assert idx.has_duplicates is True diff --git a/pandas/tests/indexes/test_numeric.py b/pandas/tests/indexes/test_numeric.py index 273e1d6ac30a6..854e294bd9906 100644 --- a/pandas/tests/indexes/test_numeric.py +++ b/pandas/tests/indexes/test_numeric.py @@ -398,9 +398,7 @@ def test_take_fill_value(self): class NumericInt(Numeric): - def test_view(self, indices): - super(NumericInt, self).test_view(indices) - + def test_view(self): i = self._holder([], name='Foo') i_view = i.view() assert i_view.name == 'Foo' diff --git a/pandas/tests/indexes/test_range.py b/pandas/tests/indexes/test_range.py index d0f8768456bc5..90aa7602c2b62 100644 --- a/pandas/tests/indexes/test_range.py +++ b/pandas/tests/indexes/test_range.py @@ -336,9 +336,7 @@ def test_delete(self): # either depending on numpy version result = idx.delete(len(idx)) - def test_view(self, indices): - super(TestRangeIndex, self).test_view(indices) - + def test_view(self): i = RangeIndex(0, name='Foo') i_view = i.view() assert i_view.name == 'Foo'