Skip to content

Commit dffab1f

Browse files
authored
BUG: name attr in RangeIndex.intersection (#38197)
1 parent 02caf7d commit dffab1f

File tree

5 files changed

+45
-26
lines changed

5 files changed

+45
-26
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,7 @@ Other
817817
- Fixed metadata propagation in the :class:`Series.dt`, :class:`Series.str` accessors, :class:`DataFrame.duplicated`, :class:`DataFrame.stack`, :class:`DataFrame.unstack`, :class:`DataFrame.pivot`, :class:`DataFrame.append`, :class:`DataFrame.diff`, :class:`DataFrame.applymap` and :class:`DataFrame.update` methods (:issue:`28283`, :issue:`37381`)
818818
- Fixed metadata propagation when selecting columns with ``DataFrame.__getitem__`` (:issue:`28283`)
819819
- Bug in :meth:`Index.intersection` with non-:class:`Index` failing to set the correct name on the returned :class:`Index` (:issue:`38111`)
820+
- Bug in :meth:`RangeIndex.intersection` failing to set the correct name on the returned :class:`Index` in some corner cases (:issue:`38197`)
820821
- Bug in :meth:`Index.union` behaving differently depending on whether operand is an :class:`Index` or other list-like (:issue:`36384`)
821822
- Bug in :meth:`Index.intersection` with non-matching numeric dtypes casting to ``object`` dtype instead of minimal common dtype (:issue:`38122`)
822823
- Passing an array with 2 or more dimensions to the :class:`Series` constructor now raises the more specific ``ValueError`` rather than a bare ``Exception`` (:issue:`35744`)

pandas/conftest.py

+14
Original file line numberDiff line numberDiff line change
@@ -1432,3 +1432,17 @@ def __init__(self, **kwargs):
14321432
registry.pop("testmem", None)
14331433
TestMemoryFS.test[0] = None
14341434
TestMemoryFS.store.clear()
1435+
1436+
1437+
@pytest.fixture(
1438+
params=[
1439+
("foo", None, None),
1440+
("Egon", "Venkman", None),
1441+
("NCC1701D", "NCC1701D", "NCC1701D"),
1442+
]
1443+
)
1444+
def names(request):
1445+
"""
1446+
A 3-tuple of names, the first two for operands, the last for a result.
1447+
"""
1448+
return request.param

pandas/core/indexes/range.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -508,19 +508,22 @@ def intersection(self, other, sort=False):
508508
self._assert_can_do_setop(other)
509509
other, _ = self._convert_can_do_setop(other)
510510

511-
if self.equals(other):
511+
if self.equals(other) and not self.has_duplicates:
512+
# has_duplicates check is unnecessary for RangeIndex, but
513+
# used to match other subclasses.
512514
return self._get_reconciled_name_object(other)
513515

514-
return self._intersection(other, sort=sort)
516+
if not is_dtype_equal(self.dtype, other.dtype):
517+
return super().intersection(other, sort=sort)
518+
519+
result = self._intersection(other, sort=sort)
520+
return self._wrap_setop_result(other, result)
515521

516522
def _intersection(self, other, sort=False):
517523

518524
if not isinstance(other, RangeIndex):
519-
if is_dtype_equal(other.dtype, self.dtype):
520-
# Int64Index
521-
result = super()._intersection(other, sort=sort)
522-
return self._wrap_setop_result(other, result)
523-
return super().intersection(other, sort=sort)
525+
# Int64Index
526+
return super()._intersection(other, sort=sort)
524527

525528
if not len(self) or not len(other):
526529
return self._simple_new(_empty_range)
@@ -562,7 +565,7 @@ def _intersection(self, other, sort=False):
562565
if sort is None:
563566
new_index = new_index.sort_values()
564567

565-
return self._wrap_setop_result(other, new_index)
568+
return new_index
566569

567570
def _min_fitting_element(self, lower_limit: int) -> int:
568571
"""Returns the smallest element greater than or equal to the limit"""

pandas/tests/arithmetic/conftest.py

-12
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,6 @@ def id_func(x):
1818

1919

2020
# ------------------------------------------------------------------
21-
@pytest.fixture(
22-
params=[
23-
("foo", None, None),
24-
("Egon", "Venkman", None),
25-
("NCC1701D", "NCC1701D", "NCC1701D"),
26-
]
27-
)
28-
def names(request):
29-
"""
30-
A 3-tuple of names, the first two for operands, the last for a result.
31-
"""
32-
return request.param
3321

3422

3523
@pytest.fixture(params=[1, np.array(1, dtype=np.int64)])

pandas/tests/indexes/ranges/test_setops.py

+19-6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ def test_intersection_mismatched_dtype(self, klass):
3737
result = flt[:0].intersection(index)
3838
tm.assert_index_equal(result, flt[:0], exact=True)
3939

40+
def test_intersection_empty(self, sort, names):
41+
# name retention on empty intersections
42+
index = RangeIndex(start=0, stop=20, step=2, name=names[0])
43+
44+
# empty other
45+
result = index.intersection(index[:0].rename(names[1]), sort=sort)
46+
tm.assert_index_equal(result, index[:0].rename(names[2]), exact=True)
47+
48+
# empty self
49+
result = index[:0].intersection(index.rename(names[1]), sort=sort)
50+
tm.assert_index_equal(result, index[:0].rename(names[2]), exact=True)
51+
4052
def test_intersection(self, sort):
4153
# intersect with Int64Index
4254
index = RangeIndex(start=0, stop=20, step=2)
@@ -78,12 +90,12 @@ def test_intersection(self, sort):
7890
result = other.intersection(first, sort=sort).astype(int)
7991
tm.assert_index_equal(result, expected)
8092

81-
index = RangeIndex(5)
93+
index = RangeIndex(5, name="foo")
8294

8395
# intersect of non-overlapping indices
84-
other = RangeIndex(5, 10, 1)
96+
other = RangeIndex(5, 10, 1, name="foo")
8597
result = index.intersection(other, sort=sort)
86-
expected = RangeIndex(0, 0, 1)
98+
expected = RangeIndex(0, 0, 1, name="foo")
8799
tm.assert_index_equal(result, expected)
88100

89101
other = RangeIndex(-1, -5, -1)
@@ -100,11 +112,12 @@ def test_intersection(self, sort):
100112
result = other.intersection(index, sort=sort)
101113
tm.assert_index_equal(result, expected)
102114

115+
def test_intersection_non_overlapping_gcd(self, sort, names):
103116
# intersection of non-overlapping values based on start value and gcd
104-
index = RangeIndex(1, 10, 2)
105-
other = RangeIndex(0, 10, 4)
117+
index = RangeIndex(1, 10, 2, name=names[0])
118+
other = RangeIndex(0, 10, 4, name=names[1])
106119
result = index.intersection(other, sort=sort)
107-
expected = RangeIndex(0, 0, 1)
120+
expected = RangeIndex(0, 0, 1, name=names[2])
108121
tm.assert_index_equal(result, expected)
109122

110123
def test_union_noncomparable(self, sort):

0 commit comments

Comments
 (0)