diff --git a/haystack/components/preprocessors/python_code_splitter.py b/haystack/components/preprocessors/python_code_splitter.py index fe663ba2db0..92169c7fe0b 100644 --- a/haystack/components/preprocessors/python_code_splitter.py +++ b/haystack/components/preprocessors/python_code_splitter.py @@ -556,7 +556,9 @@ def _secondary_split(self, unit: _CodeUnit, parent_doc: Document) -> list[Docume meta["secondary_split"] = True meta["secondary_split_index"] = idx meta["secondary_split_total"] = len(intermediate) + meta["qualified_name"] = qualified_name results.append(Document(content=piece.content or "", meta=meta)) + return results @component.output_types(documents=list[Document]) diff --git a/releasenotes/notes/python-code-splitter-secondary-split-context-8449dc47dcce0928.yaml b/releasenotes/notes/python-code-splitter-secondary-split-context-8449dc47dcce0928.yaml new file mode 100644 index 00000000000..8f0d2084abd --- /dev/null +++ b/releasenotes/notes/python-code-splitter-secondary-split-context-8449dc47dcce0928.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed ``PythonCodeSplitter`` losing identifying context for oversized + functions, methods, or classes. When a unit is too large and falls back + to line-based secondary splitting, only the first resulting piece + naturally retains the source ``def``/``class`` line; every piece now + includes a ``qualified_name`` field in ``meta`` identifying the function, + method, or class it came from. diff --git a/test/components/preprocessors/test_python_code_splitter.py b/test/components/preprocessors/test_python_code_splitter.py index 37922a7ae48..267cb7d82cc 100644 --- a/test/components/preprocessors/test_python_code_splitter.py +++ b/test/components/preprocessors/test_python_code_splitter.py @@ -836,6 +836,12 @@ def longer(): assert chunks_with_short and chunks_with_long assert chunks_with_short[0] is not chunks_with_long[0] + def test_qualified_name_in_meta_for_all_pieces(self, oversized_function_source): + splitter = PythonCodeSplitter(min_effective_lines=2, max_effective_lines=5, oversized_factor=3) + result = splitter.run(documents=[Document(content=oversized_function_source)]) + for piece in result["documents"]: + assert piece.meta.get("qualified_name") == "giant" + class TestEdgeCases: def test_module_with_only_docstring(self):