diff --git a/haystack/components/readers/extractive.py b/haystack/components/readers/extractive.py index 43f46165f1..f11accb1aa 100644 --- a/haystack/components/readers/extractive.py +++ b/haystack/components/readers/extractive.py @@ -323,7 +323,7 @@ def _postprocess( def _add_answer_page_number(self, answer: ExtractedAnswer) -> ExtractedAnswer: if answer.meta is None: - answer.meta = {} + answer = replace(answer, meta={}) if answer.document_offset is None: return answer diff --git a/releasenotes/notes/fix-extractive-reader-inplace-mutation-53436ea625324943.yaml b/releasenotes/notes/fix-extractive-reader-inplace-mutation-53436ea625324943.yaml new file mode 100644 index 0000000000..2b9724c267 --- /dev/null +++ b/releasenotes/notes/fix-extractive-reader-inplace-mutation-53436ea625324943.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixed in-place mutation of ``ExtractedAnswer.meta`` in + ``ExtractiveReader._add_answer_page_number`` when the answer's ``meta`` + was ``None``. Now uses ``dataclasses.replace`` to avoid triggering the + dataclass mutation warning. diff --git a/test/components/readers/test_extractive.py b/test/components/readers/test_extractive.py index 03cf696b8d..7a8a311ab7 100644 --- a/test/components/readers/test_extractive.py +++ b/test/components/readers/test_extractive.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 import logging +import warnings from math import ceil, exp from unittest.mock import Mock, patch @@ -486,6 +487,25 @@ def test_add_answer_page_number_returns_same_answer(mock_reader: ExtractiveReade assert "page_number must be int" in caplog.text +def test_add_answer_page_number_with_none_meta(mock_reader: ExtractiveReader): + # when answer.meta is None, it should be initialized to {} without triggering a mutation warning + document = Document(content="I thought a lot about this. The answer is 42.", meta={"page_number": 5}) + answer = ExtractedAnswer( + data="42", + query="What is the answer?", + document=document, + score=1.0, + document_offset=ExtractedAnswer.Span(42, 44), + meta=None, + ) + + with warnings.catch_warnings(): + warnings.simplefilter("error") + result = mock_reader._add_answer_page_number(answer=answer) + assert result.meta is not None + assert "answer_page_number" in result.meta + + def test_add_answer_page_number_with_form_feed(mock_reader: ExtractiveReader): document = Document( content="I thought a lot about this. \f And this document is long. \f The answer is 42.",