Skip to content

Commit 7b48a75

Browse files
jschendelMarco Gorelli
authored and
Marco Gorelli
committed
REGR: Fix to_csv with IntervalIndex (pandas-dev#28229)
* REGR: Fix to_csv with IntervalIndex
1 parent 09d96cc commit 7b48a75

File tree

5 files changed

+71
-7
lines changed

5 files changed

+71
-7
lines changed

doc/source/whatsnew/v0.25.2.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Missing
6262
I/O
6363
^^^
6464

65-
-
65+
- Regression in :meth:`~DataFrame.to_csv` where writing a :class:`Series` or :class:`DataFrame` indexed by an :class:`IntervalIndex` would incorrectly raise a ``TypeError`` (:issue:`28210`)
6666
-
6767
-
6868

pandas/core/indexes/interval.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -1096,12 +1096,8 @@ def _format_with_header(self, header, **kwargs):
10961096
return header + list(self._format_native_types(**kwargs))
10971097

10981098
def _format_native_types(self, na_rep="NaN", quoting=None, **kwargs):
1099-
""" actually format my specific types """
1100-
from pandas.io.formats.format import ExtensionArrayFormatter
1101-
1102-
return ExtensionArrayFormatter(
1103-
values=self, na_rep=na_rep, justify="all", leading_space=False
1104-
).get_result()
1099+
# GH 28210: use base method but with different default na_rep
1100+
return super()._format_native_types(na_rep=na_rep, quoting=quoting, **kwargs)
11051101

11061102
def _format_data(self, name=None):
11071103

pandas/tests/frame/test_to_csv.py

+14
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,20 @@ def _make_frame(names=None):
695695
tm.assert_index_equal(recons.columns, exp.columns)
696696
assert len(recons) == 0
697697

698+
def test_to_csv_interval_index(self):
699+
# GH 28210
700+
df = DataFrame({"A": list("abc"), "B": range(3)}, index=pd.interval_range(0, 3))
701+
702+
with ensure_clean("__tmp_to_csv_interval_index__.csv") as path:
703+
df.to_csv(path)
704+
result = self.read_csv(path, index_col=0)
705+
706+
# can't roundtrip intervalindex via read_csv so check string repr (GH 23595)
707+
expected = df.copy()
708+
expected.index = expected.index.astype(str)
709+
710+
assert_frame_equal(result, expected)
711+
698712
def test_to_csv_float32_nanrep(self):
699713
df = DataFrame(np.random.randn(1, 4).astype(np.float32))
700714
df[1] = np.nan

pandas/tests/indexes/interval/test_interval.py

+40
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,46 @@ def test_repr_missing(self, constructor, expected):
417417
result = repr(obj)
418418
assert result == expected
419419

420+
@pytest.mark.parametrize(
421+
"tuples, closed, expected_data",
422+
[
423+
([(0, 1), (1, 2), (2, 3)], "left", ["[0, 1)", "[1, 2)", "[2, 3)"]),
424+
(
425+
[(0.5, 1.0), np.nan, (2.0, 3.0)],
426+
"right",
427+
["(0.5, 1.0]", "NaN", "(2.0, 3.0]"],
428+
),
429+
(
430+
[
431+
(Timestamp("20180101"), Timestamp("20180102")),
432+
np.nan,
433+
((Timestamp("20180102"), Timestamp("20180103"))),
434+
],
435+
"both",
436+
["[2018-01-01, 2018-01-02]", "NaN", "[2018-01-02, 2018-01-03]"],
437+
),
438+
(
439+
[
440+
(Timedelta("0 days"), Timedelta("1 days")),
441+
(Timedelta("1 days"), Timedelta("2 days")),
442+
np.nan,
443+
],
444+
"neither",
445+
[
446+
"(0 days 00:00:00, 1 days 00:00:00)",
447+
"(1 days 00:00:00, 2 days 00:00:00)",
448+
"NaN",
449+
],
450+
),
451+
],
452+
)
453+
def test_to_native_types(self, tuples, closed, expected_data):
454+
# GH 28210
455+
index = IntervalIndex.from_tuples(tuples, closed=closed)
456+
result = index.to_native_types()
457+
expected = np.array(expected_data)
458+
tm.assert_numpy_array_equal(result, expected)
459+
420460
def test_get_item(self, closed):
421461
i = IntervalIndex.from_arrays((0, 1, np.nan), (1, 2, np.nan), closed=closed)
422462
assert i[0] == Interval(0.0, 1.0, closed=closed)

pandas/tests/series/test_io.py

+14
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,20 @@ def test_to_csv_compression(self, s, encoding, compression):
191191
s, pd.read_csv(fh, index_col=0, squeeze=True, encoding=encoding)
192192
)
193193

194+
def test_to_csv_interval_index(self):
195+
# GH 28210
196+
s = Series(["foo", "bar", "baz"], index=pd.interval_range(0, 3))
197+
198+
with ensure_clean("__tmp_to_csv_interval_index__.csv") as path:
199+
s.to_csv(path, header=False)
200+
result = self.read_csv(path, index_col=0, squeeze=True)
201+
202+
# can't roundtrip intervalindex via read_csv so check string repr (GH 23595)
203+
expected = s.copy()
204+
expected.index = expected.index.astype(str)
205+
206+
assert_series_equal(result, expected)
207+
194208

195209
class TestSeriesIO:
196210
def test_to_frame(self, datetime_series):

0 commit comments

Comments
 (0)