Skip to content

Commit

Permalink
TST: trim fixture to avoid xfails/skips (#39502)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored Feb 2, 2021
1 parent 48f73d8 commit 787d6f3
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 86 deletions.
36 changes: 32 additions & 4 deletions pandas/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,13 +480,41 @@ def index(request):
index_fixture2 = index


@pytest.fixture(params=indices_dict.keys())
@pytest.fixture(
params=[
key for key in indices_dict if not isinstance(indices_dict[key], MultiIndex)
]
)
def index_flat(request):
"""
index fixture, but excluding MultiIndex cases.
"""
key = request.param
return indices_dict[key].copy()


# Alias so we can test with cartesian product of index_flat
index_flat2 = index_flat


@pytest.fixture(
params=[
key
for key in indices_dict
if key not in ["int", "uint", "range", "empty", "repeats"]
and not isinstance(indices_dict[key], MultiIndex)
]
)
def index_with_missing(request):
"""
Fixture for indices with missing values
Fixture for indices with missing values.
Integer-dtype and empty cases are excluded because they cannot hold missing
values.
MultiIndex is excluded because isna() is not defined for MultiIndex.
"""
if request.param in ["int", "uint", "range", "empty", "repeats"]:
pytest.skip("missing values not supported")

# GH 35538. Use deep copy to avoid illusive bug on np-dev
# Azure pipeline that writes into indices_dict despite copy
ind = indices_dict[request.param].copy(deep=True)
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/indexes/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ def test_map(self):
def test_map_dictlike(self, mapper):

index = self.create_index()
if isinstance(index, (pd.CategoricalIndex, pd.IntervalIndex)):
if isinstance(index, pd.CategoricalIndex):
pytest.skip(f"skipping tests for {type(index)}")

identity = mapper(index.values, index)
Expand Down
5 changes: 1 addition & 4 deletions pandas/tests/indexes/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -878,14 +878,11 @@ def test_difference_name_preservation(self, index, second_name, expected, sort):
assert result.name == expected

def test_difference_empty_arg(self, index, sort):
if isinstance(index, MultiIndex):
pytest.skip("Not applicable")
first = index[5:20]
first.name = "name"
result = first.difference([], sort)

assert tm.equalContents(result, first)
assert result.name == first.name
tm.assert_index_equal(result, first)

@pytest.mark.parametrize("index", ["string"], indirect=True)
def test_difference_identity(self, index, sort):
Expand Down
84 changes: 35 additions & 49 deletions pandas/tests/indexes/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,9 @@ def test_droplevel(self, index):
):
index.droplevel(level)

def test_constructor_non_hashable_name(self, index):
def test_constructor_non_hashable_name(self, index_flat):
# GH 20527

if isinstance(index, MultiIndex):
pytest.skip("multiindex handled in test_multi.py")
index = index_flat

message = "Index.name must be a hashable type"
renamed = [["1"]]
Expand All @@ -69,27 +67,23 @@ def test_constructor_non_hashable_name(self, index):
with pytest.raises(TypeError, match=message):
index.set_names(names=renamed)

def test_constructor_unwraps_index(self, index):
if isinstance(index, pd.MultiIndex):
raise pytest.skip("MultiIndex has no ._data")
a = index
def test_constructor_unwraps_index(self, index_flat):
a = index_flat
b = type(a)(a)
tm.assert_equal(a._data, b._data)

def test_to_flat_index(self, index):
def test_to_flat_index(self, index_flat):
# 22866
if isinstance(index, MultiIndex):
pytest.skip("Separate expectation for MultiIndex")
index = index_flat

result = index.to_flat_index()
tm.assert_index_equal(result, index)

def test_set_name_methods(self, index):
def test_set_name_methods(self, index_flat):
# MultiIndex tested separately
index = index_flat
new_name = "This is the new name for this index"

# don't tests a MultiIndex here (as its tested separated)
if isinstance(index, MultiIndex):
pytest.skip("Skip check for MultiIndex")
original_name = index.name
new_ind = index.set_names([new_name])
assert new_ind.name == new_name
Expand All @@ -113,11 +107,10 @@ def test_set_name_methods(self, index):
assert index.name == name
assert index.names == [name]

def test_copy_and_deepcopy(self, index):
def test_copy_and_deepcopy(self, index_flat):
from copy import copy, deepcopy

if isinstance(index, MultiIndex):
pytest.skip("Skip check for MultiIndex")
index = index_flat

for func in (copy, deepcopy):
idx_copy = func(index)
Expand All @@ -127,10 +120,9 @@ def test_copy_and_deepcopy(self, index):
new_copy = index.copy(deep=True, name="banana")
assert new_copy.name == "banana"

def test_unique(self, index):
def test_unique(self, index_flat):
# don't test a MultiIndex here (as its tested separated)
if isinstance(index, MultiIndex):
pytest.skip("Skip check for MultiIndex")
index = index_flat

# GH 17896
expected = index.drop_duplicates()
Expand All @@ -149,9 +141,10 @@ def test_unique(self, index):
with pytest.raises(KeyError, match=msg):
index.unique(level="wrong")

def test_get_unique_index(self, index):
def test_get_unique_index(self, index_flat):
# MultiIndex tested separately
if not len(index) or isinstance(index, MultiIndex):
index = index_flat
if not len(index):
pytest.skip("Skip check for empty Index and MultiIndex")

idx = index[[0] * 5]
Expand Down Expand Up @@ -200,11 +193,12 @@ def test_get_unique_index(self, index):
result = i._get_unique_index(dropna=dropna)
tm.assert_index_equal(result, expected)

def test_searchsorted_monotonic(self, index):
def test_searchsorted_monotonic(self, index_flat):
# GH17271
index = index_flat
# not implemented for tuple searches in MultiIndex
# or Intervals searches in IntervalIndex
if isinstance(index, (MultiIndex, pd.IntervalIndex)):
if isinstance(index, pd.IntervalIndex):
pytest.skip("Skip check for MultiIndex/IntervalIndex")

# nothing to test if the index is empty
Expand Down Expand Up @@ -245,9 +239,9 @@ def test_searchsorted_monotonic(self, index):
with pytest.raises(ValueError, match=msg):
index._searchsorted_monotonic(value, side="left")

def test_drop_duplicates(self, index, keep):
if isinstance(index, MultiIndex):
pytest.skip("MultiIndex is tested separately")
def test_drop_duplicates(self, index_flat, keep):
# MultiIndex is tested separately
index = index_flat
if isinstance(index, RangeIndex):
pytest.skip(
"RangeIndex is tested in test_drop_duplicates_no_duplicates "
Expand Down Expand Up @@ -279,9 +273,9 @@ def test_drop_duplicates(self, index, keep):
expected_dropped = holder(pd.Series(idx).drop_duplicates(keep=keep))
tm.assert_index_equal(idx.drop_duplicates(keep=keep), expected_dropped)

def test_drop_duplicates_no_duplicates(self, index):
if isinstance(index, MultiIndex):
pytest.skip("MultiIndex is tested separately")
def test_drop_duplicates_no_duplicates(self, index_flat):
# MultiIndex is tested separately
index = index_flat

# make unique index
if isinstance(index, RangeIndex):
Expand All @@ -305,9 +299,12 @@ def test_drop_duplicates_inplace(self, index):
with pytest.raises(TypeError, match=msg):
index.drop_duplicates(inplace=True)

def test_has_duplicates(self, index):
def test_has_duplicates(self, index_flat):
# MultiIndex tested separately in:
# tests/indexes/multi/test_unique_and_duplicates.
index = index_flat
holder = type(index)
if not len(index) or isinstance(index, (MultiIndex, RangeIndex)):
if not len(index) or isinstance(index, RangeIndex):
# MultiIndex tested separately in:
# tests/indexes/multi/test_unique_and_duplicates.
# RangeIndex is unique by definition.
Expand Down Expand Up @@ -363,29 +360,18 @@ def test_asi8_deprecation(self, index):


@pytest.mark.parametrize("na_position", [None, "middle"])
def test_sort_values_invalid_na_position(request, index_with_missing, na_position):
if isinstance(index_with_missing, MultiIndex):
request.node.add_marker(
pytest.mark.xfail(
reason="missing value sorting order not defined for index type"
)
)
def test_sort_values_invalid_na_position(index_with_missing, na_position):

if na_position not in ["first", "last"]:
with pytest.raises(ValueError, match=f"invalid na_position: {na_position}"):
index_with_missing.sort_values(na_position=na_position)
with pytest.raises(ValueError, match=f"invalid na_position: {na_position}"):
index_with_missing.sort_values(na_position=na_position)


@pytest.mark.parametrize("na_position", ["first", "last"])
def test_sort_values_with_missing(request, index_with_missing, na_position):
def test_sort_values_with_missing(index_with_missing, na_position):
# GH 35584. Test that sort_values works with missing values,
# sort non-missing and place missing according to na_position

if isinstance(index_with_missing, MultiIndex):
request.node.add_marker(
pytest.mark.xfail(reason="missing value sorting order not implemented")
)
elif isinstance(index_with_missing, CategoricalIndex):
if isinstance(index_with_missing, CategoricalIndex):
pytest.skip("missing value sorting order not well-defined")

missing_count = np.sum(index_with_missing.isna())
Expand Down
64 changes: 36 additions & 28 deletions pandas/tests/indexes/test_setops.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,39 @@ def test_union_same_types(index):
assert idx1.union(idx2).dtype == idx1.dtype


def test_union_different_types(request, index, index_fixture2):
def test_union_different_types(index_flat, index_flat2):
# This test only considers combinations of indices
# GH 23525
idx1, idx2 = index, index_fixture2
type_pair = tuple(sorted([type(idx1), type(idx2)], key=lambda x: str(x)))
if type_pair in COMPATIBLE_INCONSISTENT_PAIRS:
request.node.add_marker(
pytest.mark.xfail(reason="This test only considers non compatible indexes.")
)

if any(isinstance(idx, pd.MultiIndex) for idx in (idx1, idx2)):
pytest.skip("This test doesn't consider multiindixes.")
idx1 = index_flat
idx2 = index_flat2

if is_dtype_equal(idx1.dtype, idx2.dtype):
pytest.skip("This test only considers non matching dtypes.")

# A union with a CategoricalIndex (even as dtype('O')) and a
# non-CategoricalIndex can only be made if both indices are monotonic.
# This is true before this PR as well.
type_pair = tuple(sorted([type(idx1), type(idx2)], key=lambda x: str(x)))

# Union with a non-unique, non-monotonic index raises error
# This applies to the boolean index
idx1 = idx1.sort_values()
idx2 = idx2.sort_values()

assert idx1.union(idx2).dtype == np.dtype("O")
assert idx2.union(idx1).dtype == np.dtype("O")
res1 = idx1.union(idx2)
res2 = idx2.union(idx1)

if is_dtype_equal(idx1.dtype, idx2.dtype):
assert res1.dtype == idx1.dtype
assert res2.dtype == idx1.dtype

elif type_pair not in COMPATIBLE_INCONSISTENT_PAIRS:
# A union with a CategoricalIndex (even as dtype('O')) and a
# non-CategoricalIndex can only be made if both indices are monotonic.
# This is true before this PR as well.
assert res1.dtype == np.dtype("O")
assert res2.dtype == np.dtype("O")

elif idx1.dtype.kind in ["f", "i", "u"] and idx2.dtype.kind in ["f", "i", "u"]:
assert res1.dtype == np.dtype("f8")
assert res2.dtype == np.dtype("f8")

else:
raise NotImplementedError


@pytest.mark.parametrize("idx_fact1,idx_fact2", COMPATIBLE_INCONSISTENT_PAIRS.values())
Expand Down Expand Up @@ -275,12 +281,12 @@ def test_symmetric_difference(self, index):
(None, None, None),
],
)
def test_corner_union(self, index, fname, sname, expected_name):
def test_corner_union(self, index_flat, fname, sname, expected_name):
# GH#9943, GH#9862
# Test unions with various name combinations
# Do not test MultiIndex or repeats

if isinstance(index, MultiIndex) or not index.is_unique:
index = index_flat
if not index.is_unique:
pytest.skip("Not for MultiIndex or repeated indices")

# Test copy.union(copy)
Expand Down Expand Up @@ -321,8 +327,9 @@ def test_corner_union(self, index, fname, sname, expected_name):
(None, None, None),
],
)
def test_union_unequal(self, index, fname, sname, expected_name):
if isinstance(index, MultiIndex) or not index.is_unique:
def test_union_unequal(self, index_flat, fname, sname, expected_name):
index = index_flat
if not index.is_unique:
pytest.skip("Not for MultiIndex or repeated indices")

# test copy.union(subset) - need sort for unicode and string
Expand All @@ -342,11 +349,11 @@ def test_union_unequal(self, index, fname, sname, expected_name):
(None, None, None),
],
)
def test_corner_intersect(self, index, fname, sname, expected_name):
def test_corner_intersect(self, index_flat, fname, sname, expected_name):
# GH#35847
# Test intersections with various name combinations

if isinstance(index, MultiIndex) or not index.is_unique:
index = index_flat
if not index.is_unique:
pytest.skip("Not for MultiIndex or repeated indices")

# Test copy.intersection(copy)
Expand Down Expand Up @@ -387,8 +394,9 @@ def test_corner_intersect(self, index, fname, sname, expected_name):
(None, None, None),
],
)
def test_intersect_unequal(self, index, fname, sname, expected_name):
if isinstance(index, MultiIndex) or not index.is_unique:
def test_intersect_unequal(self, index_flat, fname, sname, expected_name):
index = index_flat
if not index.is_unique:
pytest.skip("Not for MultiIndex or repeated indices")

# test copy.intersection(subset) - need sort for unicode and string
Expand Down

0 comments on commit 787d6f3

Please sign in to comment.