diff --git a/python/cudf/cudf/core/multiindex.py b/python/cudf/cudf/core/multiindex.py index 5be6335601cd..1e1656d8a004 100644 --- a/python/cudf/cudf/core/multiindex.py +++ b/python/cudf/cudf/core/multiindex.py @@ -550,6 +550,7 @@ def copy( @_performance_tracking def __repr__(self) -> str: max_seq_items = pd.get_option("display.max_seq_items") or len(self) + self._maybe_materialize_codes_and_levels() if len(self) > max_seq_items: n = int(max_seq_items / 2) + 1 @@ -560,20 +561,30 @@ def __repr__(self) -> str: indices = indices.append( ColumnBase.from_range(range(len(self) - n, len(self), 1)) ) - preprocess = self.take(indices) + preprocess = self[indices] else: preprocess = self arrays = [] - for name, col in zip(self.names, preprocess._columns, strict=True): + # Unused level values also determine pandas' formatting, such as + # whether datetime values include a time component. + for level in self.levels: try: - pd_idx = col.to_pandas(nullable=True) + pd_idx = level.to_pandas(nullable=True) except NotImplementedError: - pd_idx = col.to_pandas(nullable=False) - pd_idx.name = name + pd_idx = level.to_pandas(nullable=False) arrays.append(pd_idx) - preprocess_pd = pd.MultiIndex.from_arrays(arrays) + pd_codes = ( + code.find_and_replace( + as_column(np.iinfo(SIZE_TYPE_DTYPE).min, length=1), + as_column(-1, length=1), + ).to_numpy() + for code in preprocess._codes + ) + preprocess_pd = pd.MultiIndex( + levels=arrays, codes=list(pd_codes), names=self.names + ) output = repr(preprocess_pd) output_prefix = self.__class__.__name__ + "(" diff --git a/python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py b/python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py index dbbb83bdbeff..b8a80bf500dc 100644 --- a/python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py +++ b/python/cudf/cudf/pandas/scripts/pandas-testing-plugin.py @@ -2091,8 +2091,6 @@ def pytest_unconfigure(config): "tests/indexes/multi/test_equivalence.py::test_equals_op": "TODO: Add a reason for failure", "tests/indexes/multi/test_equivalence.py::test_is_": "TODO: Add a reason for failure", "tests/indexes/multi/test_equivalence.py::test_multiindex_compare": "TODO: Add a reason for failure", - "tests/indexes/multi/test_formats.py::TestRepr::test_rjust": "assert \"MultiIndex([... 'b', 'dti'])\" == \"MultiIndex([... 'b', 'dti'])\"", - "tests/indexes/multi/test_formats.py::TestRepr::test_tuple_width": "assert \"MultiIndex([...2', 'dti_3'])\" == \"MultiIndex([...2', 'dti_3'])\"", "tests/indexes/multi/test_get_set.py::test_set_levels_categorical[False]": "TODO: Add a reason for failure", "tests/indexes/multi/test_get_set.py::test_set_levels_categorical[True]": "TODO: Add a reason for failure", "tests/indexes/multi/test_get_set.py::test_set_name_methods": "TODO: Add a reason for failure", @@ -5321,7 +5319,6 @@ def pytest_unconfigure(config): "tests/indexes/interval/test_interval.py::TestIntervalIndex::test_maybe_convert_i8_errors[Index-datetime64[us, US/Eastern]-datetime64[us]]": "Skipped: failing in pandas-tests sharded CI (PR #22992, run 28204832469)", "tests/indexes/interval/test_interval.py::TestIntervalIndex::test_maybe_convert_i8_errors[scalar-datetime64[us, US/Eastern]-datetime64[us]]": "Skipped: failing in pandas-tests sharded CI (PR #22992, run 28204832469)", "tests/indexes/interval/test_interval.py::TestIntervalIndex::test_maybe_convert_i8_errors[scalar-datetime64[us, US/Eastern]-timedelta64[us]]": "Skipped: failing in pandas-tests sharded CI (PR #22992, run 28204832469)", - "tests/indexes/multi/test_formats.py::TestRepr::test_tuple_width": "Skipped: failing in pandas-tests sharded CI (PR #22992, run 28204832469)", "tests/plotting/frame/test_frame.py::TestDataFramePlots::test_memory_leak[area]": "Skipped: failing in pandas-tests sharded CI (PR #22992, run 28204832469)", "tests/plotting/frame/test_frame.py::TestDataFramePlots::test_memory_leak[line]": "Skipped: failing in pandas-tests sharded CI (PR #22992, run 28204832469)", "tests/plotting/frame/test_frame.py::TestDataFramePlots::test_plot_period_index_makes_no_right_shift[120min]": "Skipped: failing in pandas-tests sharded CI (PR #22992, run 28204832469)", diff --git a/python/cudf/cudf/tests/indexes/multiindex/test_repr.py b/python/cudf/cudf/tests/indexes/multiindex/test_repr.py index 0eb86b530dd6..a42d36520a92 100644 --- a/python/cudf/cudf/tests/indexes/multiindex/test_repr.py +++ b/python/cudf/cudf/tests/indexes/multiindex/test_repr.py @@ -39,6 +39,25 @@ def test_multiindex_repr(pmi, max_seq_items): assert repr(gmi) == repr(pmi) +@pytest.mark.parametrize("unit", ["s", "ms", "us", "ns"]) +@pytest.mark.parametrize("tz", [None, "US/Eastern"]) +@pytest.mark.parametrize("max_seq_items", [None, 2, 10]) +@pytest.mark.parametrize("selection", [slice(None), slice(0, 1), slice(0, 0)]) +def test_multiindex_repr_unused_datetime_levels( + unit, tz, max_seq_items, selection +): + times = pd.date_range("2025-01-01", periods=20, freq="s", tz=tz, unit=unit) + expected = pd.MultiIndex.from_arrays( + [pd.CategoricalIndex(["a"] * 10 + ["long label"] * 10), times], + names=["label", "time"], + ) + result = cudf.from_pandas(expected)[selection] + expected = expected[selection] + + with pd.option_context("display.max_seq_items", max_seq_items): + assert repr(result) == repr(expected) + + @pytest.mark.parametrize( "gdi, expected_repr", [