diff --git a/bigframes/core/blocks.py b/bigframes/core/blocks.py index 6e22baabec..2a6a5d4a81 100644 --- a/bigframes/core/blocks.py +++ b/bigframes/core/blocks.py @@ -252,6 +252,10 @@ def from_local( pass return block + @property + def has_index(self) -> bool: + return len(self._index_columns) > 0 + @property def index(self) -> BlockIndexProperties: """Row identities for values in the Block.""" diff --git a/bigframes/dataframe.py b/bigframes/dataframe.py index 371f69e713..f4d968a336 100644 --- a/bigframes/dataframe.py +++ b/bigframes/dataframe.py @@ -489,7 +489,6 @@ def memory_usage(self, index: bool = True): column_sizes = pandas.concat([index_size, column_sizes]) return column_sizes - @validations.requires_index def info( self, verbose: Optional[bool] = None, @@ -512,12 +511,17 @@ def info( obuf.write(f"{type(self)}\n") - index_type = "MultiIndex" if self.index.nlevels > 1 else "Index" + if self._block.has_index: + index_type = "MultiIndex" if self.index.nlevels > 1 else "Index" - # These accessses are kind of expensive, maybe should try to skip? - first_indice = self.index[0] - last_indice = self.index[-1] - obuf.write(f"{index_type}: {n_rows} entries, {first_indice} to {last_indice}\n") + # These accessses are kind of expensive, maybe should try to skip? + first_indice = self.index[0] + last_indice = self.index[-1] + obuf.write( + f"{index_type}: {n_rows} entries, {first_indice} to {last_indice}\n" + ) + else: + obuf.write("NullIndex\n") dtype_strings = self.dtypes.astype("string") if show_all_columns: diff --git a/tests/system/small/test_null_index.py b/tests/system/small/test_null_index.py index a1c7c0f1a3..4aa7ba8c77 100644 --- a/tests/system/small/test_null_index.py +++ b/tests/system/small/test_null_index.py @@ -13,6 +13,8 @@ # limitations under the License. +import io + import pandas as pd import pytest @@ -44,6 +46,38 @@ def test_null_index_materialize(scalars_df_null_index, scalars_pandas_df_default ) +def test_null_index_info(scalars_df_null_index): + expected = ( + "\n" + "NullIndex\n" + "Data columns (total 14 columns):\n" + " # Column Non-Null Count Dtype\n" + "--- ------------- ---------------- ------------------------------\n" + " 0 bool_col 8 non-null boolean\n" + " 1 bytes_col 6 non-null binary[pyarrow]\n" + " 2 date_col 7 non-null date32[day][pyarrow]\n" + " 3 datetime_col 6 non-null timestamp[us][pyarrow]\n" + " 4 geography_col 4 non-null geometry\n" + " 5 int64_col 8 non-null Int64\n" + " 6 int64_too 9 non-null Int64\n" + " 7 numeric_col 6 non-null decimal128(38, 9)[pyarrow]\n" + " 8 float64_col 7 non-null Float64\n" + " 9 rowindex_2 9 non-null Int64\n" + " 10 string_col 8 non-null string\n" + " 11 time_col 6 non-null time64[us][pyarrow]\n" + " 12 timestamp_col 6 non-null timestamp[us, tz=UTC][pyarrow]\n" + " 13 duration_col 7 non-null duration[us][pyarrow]\n" + "dtypes: Float64(1), Int64(3), binary[pyarrow](1), boolean(1), date32[day][pyarrow](1), decimal128(38, 9)[pyarrow](1), duration[us][pyarrow](1), geometry(1), string(1), time64[us][pyarrow](1), timestamp[us, tz=UTC][pyarrow](1), timestamp[us][pyarrow](1)\n" + "memory usage: 1269 bytes\n" + ) + + bf_result = io.StringIO() + + scalars_df_null_index.drop(columns="rowindex").info(buf=bf_result) + + assert expected == bf_result.getvalue() + + def test_null_index_series_repr(scalars_df_null_index, scalars_pandas_df_default_index): bf_result = scalars_df_null_index["int64_too"].head(5).__repr__() pd_result = (