langchain-pdf-inspector
A LangChain DocumentLoader integration that wraps the Rust-backed pdf-inspector library to load PDFs as plain text, markdown, positional text, or region-cropped text. It is designed as a langchain_community-style document loader integration.
Introduction
langchain-pdf-inspector gives you a standard LangChain document loader for PDF files, backed by the Rust-powered pdf-inspector package. It returns langchain_core.documents.Document objects that plug straight into LangChain chains, retrievers, and vector stores.
Features
langchain-pdf-inspector is built on two small classes. PdfInspectorParser (a BaseBlobParser) parses a single Blob into Documents across four extraction paths — plain text, markdown (headings, lists, and tables preserved), positional text (text items with bounding boxes), and region-cropped text (cropped to [x0, y0, x1, y1] rectangles) — each in one of two modes: mode="single" (one Document for the whole PDF, the default) or mode="page" (one Document per page). PdfInspectorLoader (a BasePDFLoader) wraps the parser, resolves local, web (HTTP/HTTPS), and S3 paths, downloads remote files to a temporary file, and merges caller-supplied metadata on top of every Document. Because the heavy lifting is done by the Rust-backed pdf-inspector package, extraction is fast and accurate for both text-based and scanned PDFs.
[!NOTE]
langchain-pdf-inspectoris a standalone package (version0.1.1) published on PyPI. It imports from its ownlangchain_pdf_inspectornamespace, so usefrom langchain_pdf_inspector import PdfInspectorLoaderrather than alangchain_communityimport.
Requirements
- Python 3.12 or higher
- langchain-core 1.5.3 or higher
- pdf-inspector 0.2.6 or higher
Installation
Install langchain-pdf-inspector from PyPI:
pip install langchain-pdf-inspector
# or with uv
uv add langchain-pdf-inspector
Installing langchain-pdf-inspector also installs its pinned runtime dependencies, langchain-core and pdf-inspector. pdf-inspector is a required dependency; if it is missing, constructing the loader or parser raises a friendly ImportError telling you to run pip install pdf-inspector.
To install from source instead, clone the repository and run pip install . (or uv add .) from the repo root.
Usage
Create a loader from a local file, a web URL, or an S3 path:
from langchain_pdf_inspector import PdfInspectorLoader
# Local file
loader = PdfInspectorLoader("path/to/report.pdf")
# Web URL
loader = PdfInspectorLoader("https://example.com/report.pdf")
# With optional caller metadata
loader = PdfInspectorLoader(
"report.pdf",
metadata={"tenant": "acme", "document_id": "R-42"},
)
Call load() to get a list of Document objects:
loader = PdfInspectorLoader("path/to/report.pdf")
for doc in loader.load():
print(doc.page_content)
print(doc.metadata)
Use lazy_load() to stream documents:
loader = PdfInspectorLoader("report.pdf", mode="page", pages=[0, 1, 2])
for doc in loader.lazy_load():
print(doc.metadata["page"], doc.page_content[:80])
Every Document carries source and a 1-indexed page; pdf_type and total_pages are attached whenever page detection succeeds. Caller-supplied metadata is merged on top of these keys, and wins on conflicts.
One document per page
mode="page" splits the PDF into one Document per page and requires pages, a non-empty list of 0-indexed pages. In page mode the content branches on output: output="markdown" yields per-page markdown with layout flags (needs_ocr, has_tables, has_multicolumn_layout); output="text" yields per-page positional or region-cropped text and requires extract_positions or extract_regions:
loader = PdfInspectorLoader(
"report.pdf", mode="page", pages=[0, 1, 2], output="markdown"
)
for doc in loader.load():
print(doc.metadata["page"], doc.metadata.get("has_tables"))
Markdown
Use output="markdown" in single mode to get the whole file as one Document of markdown, preserving headings, lists, and tables:
loader = PdfInspectorLoader("report.pdf", mode="single", output="markdown")
doc = loader.load()[0]
print(doc.page_content)
Positional text
Set extract_positions=True to extract text items with their positional data. In single mode all pages collapse into one joined Document (pages joined with page_delimiter); in page mode you get one Document per page:
loader = PdfInspectorLoader(
"report.pdf", mode="page", pages=[0, 1, 2], extract_positions=True
)
for doc in loader.load():
print(doc.metadata["page"], doc.page_content)
Region extraction
Set extract_regions=True and pass page_regions to crop text to [x0, y0, x1, y1] rectangles. extract_regions requires page_regions and is mutually exclusive with extract_positions:
# Single mode: one joined Document cropped to the given regions
loader = PdfInspectorLoader(
"report.pdf",
extract_regions=True,
page_regions=[(0, [[10.0, 10.0, 200.0, 200.0]])],
)
for doc in loader.load():
print(doc.metadata["page"], doc.page_content)
# Page mode: one region-cropped Document per page
loader = PdfInspectorLoader(
"report.pdf",
mode="page",
pages=[0, 1, 2],
extract_regions=True,
page_regions=[(0, [[10.0, 10.0, 200.0, 200.0]])],
)
for doc in loader.load():
print(doc.metadata["page"], doc.page_content)
Using the parser directly
PdfInspectorParser parses a Blob directly when you do not need path resolution or metadata merging:
from langchain_core.document_loaders.blob_loaders import Blob
from langchain_pdf_inspector import PdfInspectorParser
parser = PdfInspectorParser(mode="page", pages=[0, 1, 2], extract_positions=True)
blob = Blob.from_path("report.pdf")
docs = list(parser.lazy_parse(blob)) # or parser.parse(blob) for a list
Async loading
aload() and alazy_load() are inherited from BaseLoader and run the synchronous parsing work in a thread executor:
loader = PdfInspectorLoader("report.pdf")
docs = await loader.aload()
async for doc in loader.alazy_load():
print(doc.page_content)
API reference
PdfInspectorLoader(src/langchain_pdf_inspector/pdf_inspector_loader.py) — aBasePDFLoadersubclass that resolves local, web, and S3 paths, forwards extraction options to the parser, and merges caller metadata on top of everyDocument. Implementslazy_load();load(),aload(), andalazy_load()come fromBaseLoader.PdfInspectorParser(src/langchain_pdf_inspector/pdf_inspector_parser.py) — aBaseBlobParsersubclass that parses aBlobintoDocuments across four extraction paths and two modes. Implementslazy_parse()andparse().
Development
Install the development group with uv:
uv sync --group dev
The repo ships a dev container (VS Code, Python 3.12, uv, and TeX Live) that runs uv sync --group dev automatically on create.
- Type checking —
uv run mypy src - Linting —
uv run ruff check . - Tests —
uv run pytest
Creating Test Documents
Test fixtures are PDFs compiled from LaTeX sources under tests/fixtures/tex/ by tests/fixtures/build_fixtures.py. Six fixtures are staged for incremental complexity — plain_text, headings, lists, two_column, tables, and complex_layout. The .tex sources are tracked; the built PDFs are gitignored build artifacts.
Build them with:
uv run python tests/fixtures/build_fixtures.py
The script requires pdflatex (pdfTeX) on PATH. On macOS, brew install --cask mactex-no-gui (or basictex) provides it; otherwise add its bin directory to PATH, for example export PATH="/Library/TeX/texbin:$PATH".
Licensing
- Open source — the
langchain-pdf-inspectorintegration code is licensed under the MIT License. - Third-party — the wrapped
pdf-inspectorpackage is distributed under its own license; see that package for details.
Contributing
Contributions are welcome. Report bugs, request features, or open a pull request on the repository.
⭐ Support this project
If you find this useful, please consider giving it a star — it helps others discover it!
Release files for langchain-pdf-inspector 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| langchain_pdf_inspector-0.1.1.tar.gz | 27.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| langchain_pdf_inspector-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.6 kB
Release files / langchain_pdf_inspector-0.1.1.tar.gz
| Download URL | langchain_pdf_inspector-0.1.1.tar.gz |
|---|---|
| Size | 27.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8c2927ef46628a50570353df5a59fb47039dff6e8b8df5251878616d0cbd717b
|
|
BLAKE2b-256 checksum How to use checksums |
5596985967b264baf2a6696b5083ff5574a178ba4005e8d8a0b49ae824b59464
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.31 {"installer":{"name":"uv","version":"0.11.31","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / langchain_pdf_inspector-0.1.1-py3-none-any.whl
| Download URL | langchain_pdf_inspector-0.1.1-py3-none-any.whl |
|---|---|
| Size | 13.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
50a57c1ced78a302a573f90e27b14fd72b497b5e445a7cdb068a65f450c8ebdf
|
|
BLAKE2b-256 checksum How to use checksums |
8a77bfddbaedf361179c5332bc4c9fe30c992e525958c7da68fdb6833c5f5620
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.31 {"installer":{"name":"uv","version":"0.11.31","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|