Skip to content

fix(converters): preserve literal NA strings in XLSXToDocument (#12945) - #13044

Open
HarshitR2004 wants to merge 8 commits into
deepset-ai:mainfrom
HarshitR2004:fix-xlsx-drops-literal-na-values
Open

HarshitR2004 wants to merge 8 commits into
deepset-ai:mainfrom
HarshitR2004:fix-xlsx-drops-literal-na-values

Conversation

@HarshitR2004

@HarshitR2004 HarshitR2004 commented Sep 30, 2026 •

Copy link
Copy Markdown

Related Issues

Proposed Changes

XLSXToDocument preserves literal NA strings when callers have not configured NA parsing, while retaining pandas' existing behavior for explicit NA settings.

  • Apply keep_default_na=False and na_values=[""] only when neither option is present in read_excel_kwargs. This keeps literal "NA", "N/A", "NULL", and "None" while still recognizing empty cells as missing.
  • When either key is supplied, pass the caller's NA settings through unchanged. Custom na_values alone supplement pandas' built-in defaults; explicit keep_default_na=False keeps its existing empty-cell and numeric-formatting behavior.
  • Cover lists, empty lists, tuples, sets, strings, column-specific dictionaries, and None in CSV and Markdown. Test explicit overrides, na_filter=False, unrelated read options, numeric columns with gaps, and unchanged caller configuration.
  • Keep the shared CSV/Markdown assertion, clarify the docstring and current documentation, and document the upgrade path. Restore the archived 3.3 page to match upstream.

How did you test it?

Validation used a workspace-local Hatch environment with Python 3.12.10, pandas 3.0.6, openpyxl 3.1.5, and tabulate 0.10.0.

  • Before the compatibility fix, the expanded compatibility tests had 22 failures and 8 passes. Those cases now pass.
  • hatch -e review run pytest test/components/converters/test_xlsx_to_document.py -q --tb=short: 66 passed, 1 failed, including all 38 NA-parsing cases passing.
  • The remaining failure is the existing test_run_markdown_escapes_cell_content[windows-line-break] case: two spaces are produced instead of one. It was reproduced using the upstream converter from current base c41c45de0648e279efbd6d988eae638d1b85f7df in the same environment.
  • Ruff lint/format checks and repository pre-commit checks passed for the changed files.
  • mypy --follow-imports=silent haystack/components/converters/xlsx.py test/components/converters/test_xlsx_to_document.py: passed.
  • Verified that the archived version 3.3 documentation page has no diff against the upstream base.

Notes for the reviewer

The review follow-up was implemented with AI assistance. The local results above distinguish the passing NA-parsing coverage from the reproduced upstream line-ending failure.

Checklist

  • I have read the contributors guidelines and code of conduct.
  • I have added unit tests and updated the docstrings.
  • The PR title follows the conventional commit format.
  • I have documented the changed behavior.
  • I have added a release note, including an upgrade section.
  • I have run the relevant local checks and reported their results above.

@HarshitR2004
HarshitR2004 requested a review from a team as a code owner September 30, 2026 17:50
@HarshitR2004
HarshitR2004 requested review from bogdankostic and removed request for a team September 30, 2026 17:50
@vercel

vercel Bot commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

@HarshitR2004 is attempting to deploy a commit to the deepset Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant

CLAassistant commented Sep 30, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@github-actions

Copy link
Copy Markdown
Contributor

Hi @HarshitR2004, thanks for your interest in contributing to Haystack! 🙏

⚠️ Issue #12945 is already being addressed by open pull request(s) #12951. Before opening a PR for an issue, please check whether a PR is already linked to it, and consider contributing to the existing PR instead. We may close duplicate PRs to keep the review queue manageable.

This is an automated message to help us keep the review queue healthy.

@github-actions github-actions Bot added the P3 Low priority, leave it in the backlog label Oct 8, 2026

@bogdankostic bogdankostic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this @HarshitR2004!

Defaulting to keep_default_na=False fixes #12945, but it breaks empty-cell handling for users who pass their own na_values. On main, these are added to pandas' default list, which includes "". With this PR, they replace the [""] default, so empty cells are no longer treated as missing:

# sheet with an empty cell in column B and "foo" in column A
converter = XLSXToDocument(
    read_excel_kwargs={"na_values": ["foo"]},
    table_format_kwargs={"na_rep": "<missing>"},
)
# main:
# 2,x,<missing>
# 3,<missing>,y
# this PR:
# 2,x,
# 3,<missing>,y

Same for missingval with table_format="markdown". For lists, adding "" to the user-provided na_values fixes this.

Apart from this, let's add the upgrade note and the test for passing na_values.

Comment thread haystack/components/converters/xlsx.py Outdated
Comment on lines +66 to +67
By default, `keep_default_na` is set to False and `na_values` to `[""]` so literal text
values like "NA" and "N/A" are preserved while empty cells remain empty.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also mention what happens when na_values is passed. Right now this reads as if it's added to the [""] default, but it replaces it (see my comment on _extract_tables).

@@ -0,0 +1,7 @@
---
fixes:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the output for everyone using the default settings, e.g. cells containing "NULL" or "None" now end up in the content instead of being emptied. Let's add an upgrade section explaining how to get the old behavior back.

Comment on lines +278 to +293
if table_format == "csv":
rows = [row[1:] for row in list(csv.reader(io.StringIO(content)))[1:]]
assert rows == [
["Code", "Status", "Blank"],
["NA", "OK", ""],
["N/A", "pending", ""],
["North America", "active", ""],
]
else:
rows = [[cell.strip() for cell in row.split("|")[2:-1]] for row in content.splitlines()[2:]]
assert rows == [
["Code", "Status", "Blank"],
["NA", "OK", ""],
["N/A", "pending", ""],
["North America", "active", ""],
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the expected rows are the same for both formats, so let's assert once after parsing:

Suggested change
if table_format == "csv":
rows = [row[1:] for row in list(csv.reader(io.StringIO(content)))[1:]]
assert rows == [
["Code", "Status", "Blank"],
["NA", "OK", ""],
["N/A", "pending", ""],
["North America", "active", ""],
]
else:
rows = [[cell.strip() for cell in row.split("|")[2:-1]] for row in content.splitlines()[2:]]
assert rows == [
["Code", "Status", "Blank"],
["NA", "OK", ""],
["N/A", "pending", ""],
["North America", "active", ""],
]
if table_format == "csv":
rows = [row[1:] for row in list(csv.reader(io.StringIO(content)))[1:]]
else:
rows = [[cell.strip() for cell in row.split("|")[2:-1]] for row in content.splitlines()[2:]]
assert rows == [
["Code", "Status", "Blank"],
["NA", "OK", ""],
["N/A", "pending", ""],
["North America", "active", ""],
]

["North America", "active", ""],
]

def test_run_keep_default_na_override(self, tmp_path: Path) -> None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also add a test that passes na_values via read_excel_kwargs and checks that empty cells still get na_rep/missingval. That covers the case from my comment on _extract_tables.

@HarshitR2004

Copy link
Copy Markdown
Author

@bogdankostic Thanks for the review! I’ve fixed empty-cell handling with custom na_values, added regression tests, updated the docs and upgrade note, and simplified the assertion as suggested. All new tests and quality checks pass. One existing line-ending test still fails on the unchanged code, which I’ve noted in the PR.

@github-actions github-actions Bot added the type:documentation Improvements on the docs label Oct 22, 2026
@davidsbatista

Copy link
Copy Markdown
Contributor

Thanks for the updates @HarshitR2004!

The list case works now, but other forms of na_values still break empty cells, and the docs need to be moved to the right version

Comment thread haystack/components/converters/xlsx.py Outdated
"""
file_bytes = io.BytesIO(bytestream.data)
resolved_read_excel_kwargs = {
"keep_default_na": False,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two behaviour changes the upgrade note should mention (the suggestion above avoids the second one):

  • read_excel_kwargs={"na_values": [...]} used to add to pandas' default NA strings. Now it replaces them, so NA/NULL text stays in the output.
  • read_excel_kwargs={"keep_default_na": False}: we now also add na_values=[""], so empty cells become NaN and numeric columns with gaps turn into floats.

Comment thread haystack/components/converters/xlsx.py Outdated
"engine": "openpyxl", # Use openpyxl as the engine to read the Excel file
}
na_values = resolved_read_excel_kwargs["na_values"]
if isinstance(na_values, list) and "" not in na_values:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"" only gets added when na_values is a list. If someone passes a tuple, set, string, dict or None, empty cells come through as "" strings and na_rep/missingval won't apply to them.

XLSXToDocument(read_excel_kwargs={"na_values": ("foo",)})  # blank cells no longer rendered as missing

A simpler way to handle every case: only set our defaults when the user passes neither key, and otherwise leave their kwargs untouched.

if "keep_default_na" not in self.read_excel_kwargs and "na_values" not in self.read_excel_kwargs:
      resolved_read_excel_kwargs.update(keep_default_na=False, na_values=[""])

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  haystack/components/converters
  xlsx.py
Project Total  

This report was generated by python-coverage-comment-action

["North America", "active", ""],
]

@pytest.mark.parametrize("table_format", ["csv", "markdown"])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you parametrize this test over a tuple, a dict and None for na_values as well? Those are the cases that break right now.


To see the additional parameters that you can specify with the component initialization, check out the [API Reference](/reference/converters-api#xlsxtodocument).

### Missing values

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this file. The change ships in 3.5, so 3.3 users would read about behaviour they don't have. Updating docs-website/docs/ is enough.

@HaystackBot

Copy link
Copy Markdown
Contributor

Hi @HarshitR2004, thanks a lot for your contribution! 🙏

We noticed that the Contributor License Agreement (CLA) check (license/cla) hasn't passed yet, so we've temporarily moved this PR to draft and paused the review assignment.

To get your PR reviewed, please sign the CLA via the link in the license/cla check below (or in the CLA bot comment). As soon as the check turns green, this PR will automatically be marked ready for review again and a reviewer will be re-assigned.

@HaystackBot HaystackBot added the cla-pending PR is in draft until the contributor signs the CLA label Oct 22, 2026
@HaystackBot
HaystackBot marked this pull request as draft October 22, 2026 10:30
@HaystackBot

Copy link
Copy Markdown
Contributor

Hi @HarshitR2004, just a friendly reminder: this PR is still in draft because the Contributor License Agreement (CLA) hasn't been signed yet. We'd love to review your contribution! Please sign the CLA via the link in the license/cla check, and this PR will automatically be marked ready for review.

@davidsbatista davidsbatista removed the cla-pending PR is in draft until the contributor signs the CLA label Oct 22, 2026
@davidsbatista
davidsbatista marked this pull request as ready for review October 22, 2026 11:03
@HaystackBot HaystackBot added the cla-pending PR is in draft until the contributor signs the CLA label Oct 22, 2026
@HaystackBot
HaystackBot marked this pull request as draft October 22, 2026 11:29
@HaystackBot
HaystackBot marked this pull request as ready for review October 22, 2026 11:59
@HaystackBot HaystackBot removed the cla-pending PR is in draft until the contributor signs the CLA label Oct 22, 2026
@HaystackBot

Copy link
Copy Markdown
Contributor

Thanks for signing the CLA, @HarshitR2004! 🎉 This PR is now ready for review again and the reviewer has been re-assigned.

@HarshitR2004

Copy link
Copy Markdown
Author

@davidsbatista Thanks for the feedback! I’ve applied the suggested conditional defaults, preserving pandas behavior whenever either NA option is supplied. Added tests for all supported input forms, explicit overrides, and numeric formatting; updated the docstring and upgrade note and reverted the 3.3 docs change.

Comment thread docs-website/docs/pipeline-components/converters/xlsxtodocument.mdx Outdated
@vercel

vercel Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
haystack-docs Ready Ready Preview Oct 22, 2026 1:24pm UTC

Request Review

@davidsbatista davidsbatista left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the contribution!

@davidsbatista

Copy link
Copy Markdown
Contributor

@bogdankostic have a look when you have the time

This branch was successfully deployed

1 active deployment
Preview — 7ad32c7a Deployed Oct 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low priority, leave it in the backlog topic:tests type:documentation Improvements on the docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XLSXToDocument drops literal NA and N/A cell values

5 participants