diff --git a/haystack/components/converters/xlsx.py b/haystack/components/converters/xlsx.py index 370e1615f7..5b0aff95bb 100644 --- a/haystack/components/converters/xlsx.py +++ b/haystack/components/converters/xlsx.py @@ -227,10 +227,15 @@ def _extract_tables(self, bytestream: ByteStream) -> tuple[list[str], list[dict] "index": True, "headers": value.columns, "tablefmt": "pipe", + "missingval": "", **self.table_format_kwargs, } - # to_markdown uses tabulate - tables.append(value.to_markdown(**resolved_kwargs)) + # to_markdown uses tabulate, whose missingval only covers None: a NaN + # reaches the formatter as a number and is written out as "nan". Replace + # the empty cells with None so an empty cell reads as empty, the way + # to_csv already writes it, and so missingval keeps working. + filled = value.astype(object).where(value.notna(), None) + tables.append(filled.to_markdown(**resolved_kwargs)) # add sheet_name to metadata metadata.append({"xlsx": {"sheet_name": key}}) return tables, metadata diff --git a/releasenotes/notes/xlsx-markdown-missing-value-3f0c1de84b6a29c7.yaml b/releasenotes/notes/xlsx-markdown-missing-value-3f0c1de84b6a29c7.yaml new file mode 100644 index 0000000000..fbf5b9629b --- /dev/null +++ b/releasenotes/notes/xlsx-markdown-missing-value-3f0c1de84b6a29c7.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixed `XLSXToDocument` writing the string `nan` into an empty cell when + `table_format="markdown"`. The same cell is written as an empty field by + `table_format="csv"`, so an empty cell now reads as empty in both formats. + A different placeholder can be set with + `table_format_kwargs={"missingval": "N/A"}`. diff --git a/test/components/converters/test_xlsx_to_document.py b/test/components/converters/test_xlsx_to_document.py index 3e75a77a52..a55623aeaf 100644 --- a/test/components/converters/test_xlsx_to_document.py +++ b/test/components/converters/test_xlsx_to_document.py @@ -86,7 +86,8 @@ def test_run_markdown(self, test_files_path: Path) -> None: } assert ( documents[1].content - == "| | A | B |\n|---:|:------|:------|\n| 1 | col_c | col_d |\n| 2 | True | nan |" + # The empty cell reads as empty, the way the CSV format already writes it. + == "| | A | B |\n|---:|:------|:------|\n| 1 | col_c | col_d |\n| 2 | True | |" ) assert documents[1].meta == { "date_added": "2022-01-01T00:00:00", @@ -94,6 +95,16 @@ def test_run_markdown(self, test_files_path: Path) -> None: "xlsx": {"sheet_name": "Table Missing Value"}, } + def test_run_markdown_missing_value(self, test_files_path: Path) -> None: + """table_format_kwargs["missingval"] reaches tabulate for an empty cell.""" + converter = XLSXToDocument(table_format="markdown", table_format_kwargs={"missingval": "N/A"}) + paths: list[str | Path | ByteStream] = [test_files_path / "xlsx" / "basic_tables_two_sheets.xlsx"] + results = converter.run(sources=paths) + assert ( + results["documents"][1].content + == "| | A | B |\n|---:|:------|:------|\n| 1 | col_c | col_d |\n| 2 | True | N/A |" + ) + @pytest.mark.parametrize( "sheet_name, expected_sheet_name, expected_content", [