Skip to content

Commit d975544

Browse files
otiscuileisjrl
andauthored
fix: preserve metadata key named "meta" in Document.from_dict() (#11952)
Co-authored-by: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com>
1 parent d79762b commit d975544

3 files changed

Lines changed: 25 additions & 0 deletions

File tree

haystack/dataclasses/document.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ def from_dict(cls, data: dict[str, Any]) -> "Document":
155155
# a document field is a metadata key. We treat legacy fields as document fields, so that
156156
# `_RemoveLegacyFields` drops them instead of them ending up in `meta`.
157157
flatten_meta = {}
158+
# A non-mapping value under the "meta" key can't be the `meta` parameter (which must be a
159+
# dictionary). It can only be a flattened metadata key literally named "meta", produced by
160+
# to_dict(flatten=True) for a document whose metadata contains a "meta" key.
161+
if not isinstance(meta, dict):
162+
flatten_meta["meta"] = meta
163+
meta = {}
158164
document_fields = _LEGACY_FIELDS + [f.name for f in fields(cls)]
159165
for key in list(data.keys()):
160166
if key not in document_fields:
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
fixes:
3+
- |
4+
Fixed ``Document.from_dict()`` raising ``TypeError: 'str' object is not a mapping`` when
5+
deserializing a document whose metadata contained a non-mapping key named ``meta``
6+
(for example ``Document(content="hi", meta={"meta": "value"})``). Such a document is now
7+
correctly reconstructed from the default flattened ``to_dict()`` output, so the
8+
``to_dict()``/``from_dict()`` round-trip no longer crashes.

test/dataclasses/test_document.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,17 @@ def test_from_dict_with_flat_meta():
346346
)
347347

348348

349+
def test_to_dict_from_dict_roundtrip_with_meta_key_named_meta():
350+
"""
351+
A metadata key literally named "meta" must survive the default
352+
to_dict(flatten=True)/from_dict() round-trip.
353+
"""
354+
doc = Document(content="hi", meta={"meta": "value"})
355+
356+
assert Document.from_dict(doc.to_dict()) == doc
357+
assert Document.from_dict(doc.to_dict()).meta == {"meta": "value"}
358+
359+
349360
def test_from_dict_with_flat_and_non_flat_meta():
350361
with pytest.raises(ValueError, match="Pass either the 'meta' parameter or flattened metadata keys"):
351362
Document.from_dict(

0 commit comments

Comments
 (0)