Repository navigation
Conversation
…as text S3Loader, GCSLoader and AzureBlobLoader decoded every object with the text encoding, so a PDF raised UnicodeDecodeError and stopped the load. PDFs are now parsed with the same logic as PyPDFLoader, moved into a shared stream_pdf function that reads a path or bytes, and split by a new pdf_breakdown_strategy option. pypdf is imported only when a PDF is met. Any other object that is not valid text is skipped with a warning. Closes #1690
…oding behaviour - Move the duplicated `__init__` validation and `astream` loop of S3Loader, GCSLoader and AzureBlobLoader into an `ObjectStoreLoader` base; each provider now only lists, downloads and names its objects. - Check for `pypdf` once, before any object is downloaded, when a listed key is a PDF, so a missing extra no longer leaves a half-ingested store. Missing-module detection uses `find_spec`, so other import errors surface unchanged. - Raise a `ValueError` for a `.txt`/`.md`/`.csv`/`.json`/`.jsonl` object that does not decode (a wrong `encoding`); other undecodable objects are still skipped with a warning. - Decode text and extract `document`-strategy pages in worker threads instead of on the event loop. - Simplify `stream_pdf` around one document builder, and reuse `validate_breakdown_strategy` (now taking `allowed`) in PyPDFOCRLoader and GLMOCRLoader. - Docs: case-insensitive `.pdf` matching, PDF metadata keys in the field tables, and the `[pdf]` note on the cloud extras.
Pooria90
left a comment
There was a problem hiding this comment.
Thanks Guan. I just have two blocking comments on the pdf_loader. They are carried over from previous code; I appreciate you fixing them.
…loaders Adds cloud-loader cases for an uppercase `.PDF` key and a corrupt PDF (raises today; containment is #1654), and makes the missing-pypdf tests also evict the cached `pdf_loader` module so they run the real import path.
3fe7970 to
f4e67f2
Compare
|
@Pooria90 For the record, following our chat: the page-id fix is out of this PR. It's #1648's bug, and #1687 already fixes it by putting the page into Your other two points are in: the Thanks for the sharp eyes! (๑•̀ㅂ•́)و✧ |
Summary
Closes #1690.
S3Loader,GCSLoaderandAzureBlobLoaderdecoded every object with the text encoding, including objects they had already taggedDocumentType.PDF. A real PDF raisedUnicodeDecodeErrorand stopped the whole load, and any other binary file (an image, a.docx) did the same.PyPDFLoader._stream_filemoves into a module-levelstream_pdf()inpdf_loader.py, which reads either a path or bytes.PyPDFLoaderand the cloud loaders both call it, so a PDF in a bucket produces the same documents and metadata as the same file on disk, plus the provider metadata (bucket,key, ...). Matching on.pdfignores case.pdf_breakdown_strategyoption on the three cloud loaders, with the same values and default ("page") asPyPDFLoader.breakdown_strategy.pypdfstays optional. Text-only loads don't need thepdfextra. If any listed key is a PDF andpypdfis missing, the load raises anImportErrorwith the install hint before any object is downloaded, so a store is never left half-ingested..txt,.md,.markdown,.csv,.jsonor.jsonlobject that is not valid text inencodingraises aValueErrornaming the object andencoding=, since that means the encoding is wrong. Anything else that is not valid text (images, Office files, extension-less binaries) is skipped with a warning.ObjectStoreLoaderincloud/_common.py, which owns option validation,astream, and the parse-or-decode step. Each provider only lists keys, downloads bytes, and names itssourceand metadata.documentstrategy's page extraction now run in worker threads, like the other strategies.validate_breakdown_strategyin_pdf_options.py(nopypdfimport) now takes the allowed values, andPyPDFOCRLoaderandGLMOCRLoaderuse it too.module_packages.mdnotes that the cloud extras need[pdf]to parse PDFs.Type of change
Checklist
ruff check . && ruff format .)pytest tests)Notes
Depends on #1687 for page ids. Every page or paragraph of one PDF still shares a
source, so it shares aDocument.id, and the runtime keeps only the last one. That bug is #1648, already onmainforPyPDFLoader, and #1687 fixes it by putting the page intosource(path#page=N). The plan is to merge #1687 first, then rebase this PR onto it sostream_pdfcarries that scheme and cloud PDFs get it too.Tests:
test_binary_objects.pyruns every case against all three loaders: page,paragraphanddocumentsplitting of a real PDF, empty pages skipped, metadata merged, an uppercase.PDFkey, a corrupt PDF (raises), an invalid strategy rejected, PDF and text objects kept in order, a PNG skipped with a warning, a.txtin the wrong encoding raising, a customencoding=, andpypdfunavailable (text still loads; a PDF raises before anything is yielded). The PDFs come from a smallmake_pdf()builder in the cloudconftest.py, so the tests run the realpypdfpath. All 631 retrieval unit tests pass, andmkdocs build --strictpasses.Behaviour changes:
Documentper non-empty page by default, where it used to raise. Passpdf_breakdown_strategy="document"for oneDocumentper object.UnicodeDecodeErroris now skipped with a warning, unless it has a known text extension, which raises aValueErrorinstead.breakdown_strategyerrors from the PDF and OCR loaders now read... must be one of 'page', 'paragraph', 'document', got ....Left out:
pypdfand stops the load, as it does inPyPDFLoader. Containing one document's failure is [09] [Bug] [Retrieval] One bad document aborts the whole ingest run #1654.