diff --git a/tabulate/__init__.py b/tabulate/__init__.py index 12a2950..cd12475 100644 --- a/tabulate/__init__.py +++ b/tabulate/__init__.py @@ -1483,11 +1483,20 @@ def _normalize_tabular_data(tabular_data, headers, showindex="default"): elif hasattr(tabular_data, "index"): # values is a property, has .index => it's likely a pandas.DataFrame (pandas 0.11.0) keys = list(tabular_data) - if showindex in ["default", "always", True] and tabular_data.index.name is not None: - if isinstance(tabular_data.index.name, list): - keys[:0] = tabular_data.index.name - else: - keys[:0] = [tabular_data.index.name] + if showindex in ["default", "always", True]: + # Pandas prints columns.name in the index header when the + # index itself has no name. Keep an explicit index.name. + index_header = tabular_data.index.name + if index_header is None: + columns = getattr(tabular_data, "columns", None) + column_axis_name = getattr(columns, "name", None) + if column_axis_name is not None: + index_header = column_axis_name + if index_header is not None: + if isinstance(index_header, list): + keys[:0] = index_header + else: + keys[:0] = [index_header] vals = tabular_data.values # values matrix doesn't need to be transposed # for DataFrames add an index per default index = list(tabular_data.index) diff --git a/test/test_input.py b/test/test_input.py index 3cc3237..7c551ab 100644 --- a/test/test_input.py +++ b/test/test_input.py @@ -292,6 +292,33 @@ def test_pandas_keys(): skip("test_pandas_keys is skipped") +def test_pandas_columns_name_shown_when_index_unnamed(): + "DataFrame columns.name fills the index header when index.name is unset." + try: + import pandas + + df = pandas.DataFrame([[1, 2], [3, 4]], columns=["a", "b"]) + df.columns.name = "some_name" + expected = """\ +| some_name | a | b | +|------------:|----:|----:| +| 0 | 1 | 2 | +| 1 | 3 | 4 |""" + result = tabulate(df, tablefmt="pipe", headers="keys", showindex=True) + assert_equal(expected, result) + + df.index.name = "row_id" + named_index = tabulate(df, tablefmt="pipe", headers="keys", showindex=True) + assert_in("row_id", named_index.splitlines()[0]) + assert "some_name" not in named_index.splitlines()[0] + + hidden = tabulate(df, tablefmt="pipe", headers="keys", showindex=False) + assert "some_name" not in hidden + assert "row_id" not in hidden + except ImportError: + skip("test_pandas_columns_name_shown_when_index_unnamed is skipped") + + def test_sqlite3(): "Input: an sqlite3 cursor" try: