Skip to content

Commit f12567f

Browse files
jschendeljreback
authored andcommitted
BUG: Fix Series(List[Interval]) to infer interval dtype (#28399)
1 parent b187a0d commit f12567f

File tree

3 files changed

+35
-22
lines changed

3 files changed

+35
-22
lines changed

doc/source/whatsnew/v1.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,7 @@ Interval
885885

886886
- Bug in :meth:`IntervalIndex.get_indexer` where a :class:`Categorical` or :class:`CategoricalIndex` ``target`` would incorrectly raise a ``TypeError`` (:issue:`30063`)
887887
- Bug in ``pandas.core.dtypes.cast.infer_dtype_from_scalar`` where passing ``pandas_dtype=True`` did not infer :class:`IntervalDtype` (:issue:`30337`)
888+
- Bug in :class:`Series` constructor where constructing a ``Series`` from a ``list`` of :class:`Interval` objects resulted in ``object`` dtype instead of :class:`IntervalDtype` (:issue:`23563`)
888889
- Bug in :class:`IntervalDtype` where the ``kind`` attribute was incorrectly set as ``None`` instead of ``"O"`` (:issue:`30568`)
889890
- Bug in :class:`IntervalIndex`, :class:`~arrays.IntervalArray`, and :class:`Series` with interval data where equality comparisons were incorrect (:issue:`24112`)
890891

pandas/core/construction.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -497,13 +497,8 @@ def sanitize_array(
497497

498498
if is_object_dtype(subarr.dtype) and not is_object_dtype(dtype):
499499
inferred = lib.infer_dtype(subarr, skipna=False)
500-
if inferred == "period":
501-
from pandas.core.arrays import period_array
502-
503-
try:
504-
subarr = period_array(subarr)
505-
except IncompatibleFrequency:
506-
pass
500+
if inferred in {"interval", "period"}:
501+
subarr = array(subarr)
507502

508503
return subarr
509504

pandas/tests/series/test_constructors.py

+32-15
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
timedelta_range,
2828
)
2929
import pandas._testing as tm
30-
from pandas.core.arrays import period_array
30+
from pandas.core.arrays import IntervalArray, period_array
3131

3232

3333
class TestSeriesConstructors:
@@ -967,16 +967,34 @@ def test_constructor_with_naive_string_and_datetimetz_dtype(self, arg):
967967
expected = Series(pd.Timestamp(arg)).dt.tz_localize("CET")
968968
tm.assert_series_equal(result, expected)
969969

970-
def test_construction_interval(self):
970+
@pytest.mark.parametrize("interval_constructor", [IntervalIndex, IntervalArray])
971+
def test_construction_interval(self, interval_constructor):
971972
# construction from interval & array of intervals
972-
index = IntervalIndex.from_breaks(np.arange(3), closed="right")
973-
result = Series(index)
974-
repr(result)
975-
str(result)
976-
tm.assert_index_equal(Index(result.values), index)
973+
intervals = interval_constructor.from_breaks(np.arange(3), closed="right")
974+
result = Series(intervals)
975+
assert result.dtype == "interval[int64]"
976+
tm.assert_index_equal(Index(result.values), Index(intervals))
977977

978-
result = Series(index.values)
979-
tm.assert_index_equal(Index(result.values), index)
978+
@pytest.mark.parametrize(
979+
"data_constructor", [list, np.array], ids=["list", "ndarray[object]"]
980+
)
981+
def test_constructor_infer_interval(self, data_constructor):
982+
# GH 23563: consistent closed results in interval dtype
983+
data = [pd.Interval(0, 1), pd.Interval(0, 2), None]
984+
result = pd.Series(data_constructor(data))
985+
expected = pd.Series(IntervalArray(data))
986+
assert result.dtype == "interval[float64]"
987+
tm.assert_series_equal(result, expected)
988+
989+
@pytest.mark.parametrize(
990+
"data_constructor", [list, np.array], ids=["list", "ndarray[object]"]
991+
)
992+
def test_constructor_interval_mixed_closed(self, data_constructor):
993+
# GH 23563: mixed closed results in object dtype (not interval dtype)
994+
data = [pd.Interval(0, 1, closed="both"), pd.Interval(0, 2, closed="neither")]
995+
result = Series(data_constructor(data))
996+
assert result.dtype == object
997+
assert result.tolist() == data
980998

981999
def test_construction_consistency(self):
9821000

@@ -993,17 +1011,16 @@ def test_construction_consistency(self):
9931011
result = Series(s.values, dtype=s.dtype)
9941012
tm.assert_series_equal(result, s)
9951013

996-
def test_constructor_infer_period(self):
1014+
@pytest.mark.parametrize(
1015+
"data_constructor", [list, np.array], ids=["list", "ndarray[object]"]
1016+
)
1017+
def test_constructor_infer_period(self, data_constructor):
9971018
data = [pd.Period("2000", "D"), pd.Period("2001", "D"), None]
998-
result = pd.Series(data)
1019+
result = pd.Series(data_constructor(data))
9991020
expected = pd.Series(period_array(data))
10001021
tm.assert_series_equal(result, expected)
10011022
assert result.dtype == "Period[D]"
10021023

1003-
data = np.asarray(data, dtype=object)
1004-
tm.assert_series_equal(result, expected)
1005-
assert result.dtype == "Period[D]"
1006-
10071024
def test_constructor_period_incompatible_frequency(self):
10081025
data = [pd.Period("2000", "D"), pd.Period("2001", "A")]
10091026
result = pd.Series(data)

0 commit comments

Comments
 (0)