Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions pandas/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ def _create_mi_with_dt64tz_level():
),
"mi-with-dt64tz-level": _create_mi_with_dt64tz_level(),
"multi": _create_multiindex(),
"mixed-int-string": Index([0, "a", 1, "b", 2, "c"]),
"repeats": Index([0, 0, 1, 1, 2, 2]),
"nullable_int": Index(np.arange(10), dtype="Int64"),
"nullable_uint": Index(np.arange(10), dtype="UInt16"),
Expand Down Expand Up @@ -745,6 +746,14 @@ def index(request):
return indices_dict[request.param].copy(deep=False)


@pytest.fixture(params=[key for key in indices_dict if key != "mixed-int-string"])
def index_sortable(request):
"""
index fixture, but excluding types that are not orderable.
"""
return indices_dict[request.param].copy(deep=False)


@pytest.fixture(
params=[
key for key, value in indices_dict.items() if not isinstance(value, MultiIndex)
Expand All @@ -758,6 +767,20 @@ def index_flat(request):
return indices_dict[key].copy(deep=False)


@pytest.fixture(
params=[
key
for key, value in indices_dict.items()
if not isinstance(value, MultiIndex) and key != "mixed-int-string"
]
)
def index_flat_sortable(request):
"""
index_flat fixture, but excluding types that are not orderable.
"""
return indices_dict[request.param].copy(deep=False)


@pytest.fixture(
params=[
key
Expand Down Expand Up @@ -792,6 +815,28 @@ def index_with_missing(request):
return type(ind)(vals, copy=False)


@pytest.fixture(
params=[
key
for key, value in indices_dict.items()
if not (
key.startswith(("int", "uint", "float"))
or key in ["range", "empty", "repeats", "bool-dtype", "mixed-int-string"]
)
and not isinstance(value, MultiIndex)
]
)
def index_with_missing_sortable(request):
"""
index_with_missing fixture, but excluding types that are not orderable.
"""
ind = indices_dict[request.param]
vals = ind.values.copy()
vals[0] = None
vals[-1] = None
return type(ind)(vals, copy=False)


# ----------------------------------------------------------------
# Series'
# ----------------------------------------------------------------
Expand Down Expand Up @@ -870,6 +915,21 @@ def index_or_series_obj(request):
return _index_or_series_objs[request.param].copy(deep=False)


_index_or_series_objs_orderable = {
key: value
for key, value in _index_or_series_objs.items()
if "mixed-int-string" not in key
}


@pytest.fixture(params=_index_or_series_objs_orderable.keys())
def index_or_series_obj_orderable(request):
"""
index_or_series_obj fixture, but excluding types that are not orderable.
"""
return _index_or_series_objs_orderable[request.param].copy(deep=False)


_typ_objects_series = {
f"{dtype.__name__}-series": Series(dtype) for dtype in tm.PYTHON_DATA_TYPES
}
Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/base/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ def test_memory_usage_components_narrow_series(any_real_numpy_dtype):
assert total_usage == non_index_usage + index_usage


def test_searchsorted(request, index_or_series_obj):
def test_searchsorted(request, index_or_series_obj_orderable):
# numpy.searchsorted calls obj.searchsorted under the hood.
# See gh-12238
obj = index_or_series_obj
obj = index_or_series_obj_orderable

if isinstance(obj, pd.MultiIndex):
# See gh-14833
Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/base/test_value_counts.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ def test_value_counts(index_or_series_obj):

@pytest.mark.parametrize("null_obj", [np.nan, None])
@pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning")
def test_value_counts_null(null_obj, index_or_series_obj):
orig = index_or_series_obj
def test_value_counts_null(null_obj, index_or_series_obj_orderable):
orig = index_or_series_obj_orderable

if not allow_na_ops(orig):
pytest.skip("type doesn't allow for NA operations")
Expand Down
3 changes: 2 additions & 1 deletion pandas/tests/indexes/multi/test_setops.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,9 @@ def test_union_with_duplicates_keep_ea_dtype(dupe_val, any_numeric_ea_dtype):


@pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning")
def test_union_duplicates(index, request):
def test_union_duplicates(index_sortable, request):
# GH#38977
index = index_sortable
if index.empty or isinstance(index, (IntervalIndex, CategoricalIndex)):
pytest.skip(f"No duplicates in an empty {type(index).__name__}")

Expand Down
8 changes: 5 additions & 3 deletions pandas/tests/indexes/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,17 +436,19 @@ def test_hasnans_isnans(self, index_flat):

@pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning")
@pytest.mark.parametrize("na_position", [None, "middle"])
def test_sort_values_invalid_na_position(index_with_missing, na_position):
def test_sort_values_invalid_na_position(index_with_missing_sortable, na_position):
with pytest.raises(ValueError, match=f"invalid na_position: {na_position}"):
index_with_missing.sort_values(na_position=na_position)
index_with_missing_sortable.sort_values(na_position=na_position)


@pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning")
@pytest.mark.parametrize("na_position", ["first", "last"])
def test_sort_values_with_missing(index_with_missing, na_position):
def test_sort_values_with_missing(index_with_missing_sortable, na_position):
# GH 35584. Test that sort_values works with missing values,
# sort non-missing and place missing according to na_position

index_with_missing = index_with_missing_sortable

missing_count = np.sum(index_with_missing.isna())
not_na_vals = index_with_missing[index_with_missing.notna()].values
sorted_values = np.sort(not_na_vals)
Expand Down
7 changes: 4 additions & 3 deletions pandas/tests/indexes/test_numpy_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,18 @@ def test_numpy_ufuncs_other(index, func):


@pytest.mark.parametrize("func", [np.maximum, np.minimum])
def test_numpy_ufuncs_reductions(index, func):
def test_numpy_ufuncs_reductions(index_sortable, func):
# TODO: overlap with tests.series.test_ufunc.test_reductions
index = index_sortable
if len(index) == 0:
pytest.skip("Test doesn't make sense for empty index.")

if isinstance(index, CategoricalIndex) and index.dtype.ordered is False:
with pytest.raises(TypeError, match="is not ordered for"):
func.reduce(index)
return
else:
result = func.reduce(index)

result = func.reduce(index)

if func is np.maximum:
expected = index.max(skipna=False)
Expand Down
6 changes: 4 additions & 2 deletions pandas/tests/indexes/test_old_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,15 +355,17 @@ def test_memory_usage_doesnt_trigger_engine(self, index):
assert res_without_engine > 0
assert res_with_engine > 0

def test_argsort(self, index):
def test_argsort(self, index_sortable):
index = index_sortable
if isinstance(index, CategoricalIndex):
pytest.skip(f"{type(self).__name__} separately tested")

result = index.argsort()
expected = np.array(index).argsort()
tm.assert_numpy_array_equal(result, expected)

def test_numpy_argsort(self, index):
def test_numpy_argsort(self, index_sortable):
index = index_sortable
result = np.argsort(index)
expected = index.argsort()
tm.assert_numpy_array_equal(result, expected)
Expand Down
40 changes: 23 additions & 17 deletions pandas/tests/indexes/test_setops.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,24 @@ def index_flat2(index_flat):
return index_flat


def test_union_same_types(index):
@pytest.fixture
def index_flat2_sortable(index_flat_sortable):
return index_flat_sortable


def test_union_same_types(index_sortable):
# Union with a non-unique, non-monotonic index raises error
# Only needed for bool index factory
idx1 = index.sort_values()
idx2 = index.sort_values()
idx1 = index_sortable.sort_values()
idx2 = index_sortable.sort_values()
assert idx1.union(idx2).dtype == idx1.dtype


def test_union_different_types(index_flat, index_flat2):
def test_union_different_types(index_flat_sortable, index_flat2_sortable):
# This test only considers combinations of indices
# GH 23525
idx1 = index_flat
idx2 = index_flat2
idx1 = index_flat_sortable
idx2 = index_flat2_sortable

common_dtype = find_common_type([idx1.dtype, idx2.dtype])

Expand Down Expand Up @@ -220,8 +225,8 @@ def test_intersection_base(self, index):
first.intersection([1, 2, 3])

@pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning")
def test_union_base(self, index):
index = index.unique()
def test_union_base(self, index_sortable):
index = index_sortable.unique()
first = index[3:]
second = index[:5]
everything = index
Expand Down Expand Up @@ -272,7 +277,8 @@ def test_difference_base(self, sort, index):
first.difference([1, 2, 3], sort)

@pytest.mark.filterwarnings(r"ignore:PeriodDtype\[B\] is deprecated:FutureWarning")
def test_symmetric_difference(self, index, using_infer_string, request):
def test_symmetric_difference(self, index_sortable, using_infer_string, request):
index = index_sortable
if (
using_infer_string
and index.dtype == "object"
Expand Down Expand Up @@ -362,11 +368,11 @@ def test_corner_union(self, index_flat, fname, sname, expected_name):
(None, None, None),
],
)
def test_union_unequal(self, index_flat, fname, sname, expected_name):
if not index_flat.is_unique:
index = index_flat.unique()
def test_union_unequal(self, index_flat_sortable, fname, sname, expected_name):
if not index_flat_sortable.is_unique:
index = index_flat_sortable.unique()
else:
index = index_flat
index = index_flat_sortable

# test copy.union(subset) - need sort for unicode and string
first = index.copy().set_names(fname)
Expand Down Expand Up @@ -431,11 +437,11 @@ def test_corner_intersect(self, index_flat, fname, sname, expected_name):
(None, None, None),
],
)
def test_intersect_unequal(self, index_flat, fname, sname, expected_name):
if not index_flat.is_unique:
index = index_flat.unique()
def test_intersect_unequal(self, index_flat_sortable, fname, sname, expected_name):
if not index_flat_sortable.is_unique:
index = index_flat_sortable.unique()
else:
index = index_flat
index = index_flat_sortable

# test copy.intersection(subset) - need sort for unicode and string
first = index.copy().set_names(fname)
Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/test_algos.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ def test_factorize_complex(self):
expected_uniques = np.array([(1 + 0j), (2 + 0j), (2 + 1j)], dtype=complex)
tm.assert_numpy_array_equal(uniques, expected_uniques)

def test_factorize(self, index_or_series_obj, sort):
obj = index_or_series_obj
def test_factorize(self, index_or_series_obj_orderable, sort):
obj = index_or_series_obj_orderable
result_codes, result_uniques = obj.factorize(sort=sort)

constructor = Index
Expand Down
Loading