Skip to content

Commit a99c463

Browse files
jschendeljreback
authored andcommitted
BUG: Fix Index constructor with mixed closed Intervals (pandas-dev#27173)
1 parent e145443 commit a99c463

File tree

4 files changed

+32
-3
lines changed

4 files changed

+32
-3
lines changed

doc/source/whatsnew/v0.25.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ Interval
764764

765765
- Construction of :class:`Interval` is restricted to numeric, :class:`Timestamp` and :class:`Timedelta` endpoints (:issue:`23013`)
766766
- Fixed bug in :class:`Series`/:class:`DataFrame` not displaying ``NaN`` in :class:`IntervalIndex` with missing values (:issue:`25984`)
767-
-
767+
- Bug in :class:`Index` constructor where passing mixed closed :class:`Interval` objects would result in a ``ValueError`` instead of an ``object`` dtype ``Index`` (:issue:`27172`)
768768

769769
Indexing
770770
^^^^^^^^

pandas/core/indexes/base.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,11 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None,
421421
return Float64Index(subarr, copy=copy, name=name)
422422
elif inferred == 'interval':
423423
from .interval import IntervalIndex
424-
return IntervalIndex(subarr, name=name, copy=copy)
424+
try:
425+
return IntervalIndex(subarr, name=name, copy=copy)
426+
except ValueError:
427+
# GH27172: mixed closed Intervals --> object dtype
428+
pass
425429
elif inferred == 'boolean':
426430
# don't support boolean explicitly ATM
427431
pass

pandas/tests/indexes/interval/test_construction.py

+14
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,16 @@ def test_index_object_dtype(self, values_constructor):
364364
assert type(result) is Index
365365
tm.assert_numpy_array_equal(result.values, np.array(values))
366366

367+
def test_index_mixed_closed(self):
368+
# GH27172
369+
intervals = [Interval(0, 1, closed='left'),
370+
Interval(1, 2, closed='right'),
371+
Interval(2, 3, closed='neither'),
372+
Interval(3, 4, closed='both')]
373+
result = Index(intervals)
374+
expected = Index(intervals, dtype=object)
375+
tm.assert_index_equal(result, expected)
376+
367377

368378
class TestFromIntervals(TestClassConstructors):
369379
"""
@@ -388,3 +398,7 @@ def test_deprecated(self):
388398
@pytest.mark.skip(reason='parent class test that is not applicable')
389399
def test_index_object_dtype(self):
390400
pass
401+
402+
@pytest.mark.skip(reason='parent class test that is not applicable')
403+
def test_index_mixed_closed(self):
404+
pass

pandas/tests/indexes/test_base.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
CategoricalIndex, DataFrame, DatetimeIndex, Float64Index, Int64Index,
2323
PeriodIndex, RangeIndex, Series, TimedeltaIndex, UInt64Index, date_range,
2424
isna, period_range)
25-
from pandas.core.index import _get_combined_index, ensure_index_from_sequences
25+
from pandas.core.index import (
26+
_get_combined_index, ensure_index, ensure_index_from_sequences)
2627
from pandas.core.indexes.api import Index, MultiIndex
2728
from pandas.core.sorting import safe_sort
2829
from pandas.tests.indexes.common import Base
@@ -2432,6 +2433,16 @@ def test_ensure_index_from_sequences(self, data, names, expected):
24322433
result = ensure_index_from_sequences(data, names)
24332434
tm.assert_index_equal(result, expected)
24342435

2436+
def test_ensure_index_mixed_closed_intervals(self):
2437+
# GH27172
2438+
intervals = [pd.Interval(0, 1, closed='left'),
2439+
pd.Interval(1, 2, closed='right'),
2440+
pd.Interval(2, 3, closed='neither'),
2441+
pd.Interval(3, 4, closed='both')]
2442+
result = ensure_index(intervals)
2443+
expected = Index(intervals, dtype=object)
2444+
tm.assert_index_equal(result, expected)
2445+
24352446

24362447
@pytest.mark.parametrize('opname', ['eq', 'ne', 'le', 'lt', 'ge', 'gt',
24372448
'add', 'radd', 'sub', 'rsub',

0 commit comments

Comments
 (0)