diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index 8d84bef91bb03..fa01fd5e4379c 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -3147,7 +3147,9 @@ def write_multi_index(self, key: str, index: MultiIndex) -> None: zip(index.levels, index.codes, index.names, strict=True) ): # write the level - if isinstance(lev.dtype, ExtensionDtype): + if isinstance(lev.dtype, ExtensionDtype) and not isinstance( + lev.dtype, StringDtype + ): raise NotImplementedError( "Saving a MultiIndex with an extension dtype is not supported." ) diff --git a/pandas/tests/io/pytables/test_put.py b/pandas/tests/io/pytables/test_put.py index 0cfa24e889e6f..a195b32fa1a15 100644 --- a/pandas/tests/io/pytables/test_put.py +++ b/pandas/tests/io/pytables/test_put.py @@ -314,12 +314,6 @@ def test_column_multiindex(tmp_path, setup_path, using_infer_string): path = tmp_path / setup_path with HDFStore(path) as store: - if using_infer_string: - # TODO(infer_string) make this work for string dtype - msg = "Saving a MultiIndex with an extension dtype is not supported." - with pytest.raises(NotImplementedError, match=msg): - store.put("df", df) - return store.put("df", df) tm.assert_frame_equal( store["df"], expected, check_index_type=True, check_column_type=True diff --git a/pandas/tests/io/pytables/test_read.py b/pandas/tests/io/pytables/test_read.py index 70696a502a111..75a0cb0fe3be5 100644 --- a/pandas/tests/io/pytables/test_read.py +++ b/pandas/tests/io/pytables/test_read.py @@ -181,12 +181,6 @@ def test_read_hdf_open_store(tmp_path, setup_path, using_infer_string): df = df.set_index(keys="E", append=True) path = tmp_path / setup_path - if using_infer_string: - # TODO(infer_string) make this work for string dtype - msg = "Saving a MultiIndex with an extension dtype is not supported." - with pytest.raises(NotImplementedError, match=msg): - df.to_hdf(path, key="df", mode="w") - return df.to_hdf(path, key="df", mode="w") direct = read_hdf(path, "df") with HDFStore(path, mode="r") as store: diff --git a/pandas/tests/io/pytables/test_round_trip.py b/pandas/tests/io/pytables/test_round_trip.py index aacdfb1f82f6d..7d4303722534e 100644 --- a/pandas/tests/io/pytables/test_round_trip.py +++ b/pandas/tests/io/pytables/test_round_trip.py @@ -434,12 +434,6 @@ def test_store_hierarchical( ): frame = multiindex_dataframe_random_data - if using_infer_string: - # TODO(infer_string) make this work for string dtype - msg = "Saving a MultiIndex with an extension dtype is not supported." - with pytest.raises(NotImplementedError, match=msg): - _check_roundtrip(frame, tm.assert_frame_equal, path=temp_file) - return _check_roundtrip(frame, tm.assert_frame_equal, path=temp_file) _check_roundtrip(frame.T, tm.assert_frame_equal, path=temp_file) _check_roundtrip(frame["A"], tm.assert_series_equal, path=temp_file) diff --git a/pandas/tests/io/pytables/test_store.py b/pandas/tests/io/pytables/test_store.py index d11495902f76c..74055582dc89c 100644 --- a/pandas/tests/io/pytables/test_store.py +++ b/pandas/tests/io/pytables/test_store.py @@ -1129,3 +1129,13 @@ def test_select_categorical_string_columns(tmp_path, model): result = store.select("df", "modelId == model") expected = df[df["modelId"] == model] tm.assert_frame_equal(result, expected) + + +def test_to_hdf_multiindex_string_dtype_crash(tmp_path): + # GH#63412 + path = tmp_path / "test.h5" + index = MultiIndex.from_tuples([("a", "x"), ("b", "y")], names=["level1", "level2"]) + df = DataFrame({"value": [1, 2]}, index=index) + df.to_hdf(path, key="test") + result = read_hdf(path, key="test") + tm.assert_frame_equal(df, result, check_dtype=False)