Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TST: trim fixture to avoid xfails/skips #39502

Merged
merged 7 commits into from
Feb 2, 2021
Merged
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
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