Skip to content

Commit 4cfd4f7

Browse files
fix(python_code_splitter): ensure secondary-split pieces retain qualified name in metadata
1 parent d2de764 commit 4cfd4f7

3 files changed

Lines changed: 14 additions & 32 deletions

File tree

haystack/components/preprocessors/python_code_splitter.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -556,11 +556,9 @@ def _secondary_split(self, unit: _CodeUnit, parent_doc: Document) -> list[Docume
556556
meta["secondary_split"] = True
557557
meta["secondary_split_index"] = idx
558558
meta["secondary_split_total"] = len(intermediate)
559+
meta["qualified_name"] = qualified_name
560+
results.append(Document(content=piece.content or "", meta=meta))
559561

560-
# Prepend the unit's qualified name as a comment to non-first pieces,
561-
# since only the first piece naturally retains the def/class signature line.
562-
content = piece.content or "" if idx == 0 else f"# {qualified_name}\n{piece.content or ''}"
563-
results.append(Document(content=content, meta=meta))
564562
return results
565563

566564
@component.output_types(documents=list[Document])
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
---
22
fixes:
33
- |
4-
Fixed ``PythonCodeSplitter`` secondary-split pieces losing all identifying
5-
context after the first piece when a function, method, or class body is
6-
oversized and falls back to line-based splitting. Every piece after the
7-
first is now prefixed with the unit's qualified name (e.g. ``# ClassName.method_name``)
8-
so that retrieval can still associate the chunk with its source function.
4+
Fixed ``PythonCodeSplitter`` losing identifying context for oversized
5+
functions, methods, or classes. When a unit is too large and falls back
6+
to line-based secondary splitting, only the first resulting piece
7+
naturally retains the source ``def``/``class`` line; every piece now
8+
includes a ``qualified_name`` field in ``meta`` identifying the function,
9+
method, or class it came from.

test/components/preprocessors/test_python_code_splitter.py

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,12 @@ def longer():
836836
assert chunks_with_short and chunks_with_long
837837
assert chunks_with_short[0] is not chunks_with_long[0]
838838

839+
def test_qualified_name_in_meta_for_all_pieces(self, oversized_function_source):
840+
splitter = PythonCodeSplitter(min_effective_lines=2, max_effective_lines=5, oversized_factor=3)
841+
result = splitter.run(documents=[Document(content=oversized_function_source)])
842+
for piece in result["documents"]:
843+
assert piece.meta.get("qualified_name") == "giant"
844+
839845

840846
class TestEdgeCases:
841847
def test_module_with_only_docstring(self):
@@ -872,26 +878,3 @@ def test_invalid_syntax_raises_syntax_error(self):
872878
doc = Document(content="class Broken(\n pass\n")
873879
with pytest.raises(SyntaxError):
874880
splitter.run(documents=[doc])
875-
876-
877-
class TestSecondarySplitQualifiedName:
878-
def test_first_piece_has_no_prefix(self, oversized_function_source):
879-
splitter = PythonCodeSplitter(min_effective_lines=2, max_effective_lines=5, oversized_factor=3)
880-
result = splitter.run(documents=[Document(content=oversized_function_source)])
881-
secondary = sorted(
882-
(c for c in result["documents"] if c.meta.get("secondary_split")),
883-
key=lambda c: c.meta["secondary_split_index"],
884-
)
885-
assert secondary
886-
assert not (secondary[0].content or "").startswith("# giant")
887-
888-
def test_non_first_pieces_are_prefixed_with_qualified_name(self, oversized_function_source):
889-
splitter = PythonCodeSplitter(min_effective_lines=2, max_effective_lines=5, oversized_factor=3)
890-
result = splitter.run(documents=[Document(content=oversized_function_source)])
891-
secondary = sorted(
892-
(c for c in result["documents"] if c.meta.get("secondary_split")),
893-
key=lambda c: c.meta["secondary_split_index"],
894-
)
895-
assert len(secondary) >= 2
896-
for piece in secondary[1:]:
897-
assert (piece.content or "").startswith("# giant")

0 commit comments

Comments
 (0)