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!
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langchain_pdf_inspector-0.1.1.tar.gz.
File metadata
- Download URL: langchain_pdf_inspector-0.1.1.tar.gz
- Upload date:
- Size: 27.4 kB
- Tags: Source
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c2927ef46628a50570353df5a59fb47039dff6e8b8df5251878616d0cbd717b
|
|
| MD5 |
4209faa2e5076905cf082e973d611e0d
|
|
| BLAKE2b-256 |
5596985967b264baf2a6696b5083ff5574a178ba4005e8d8a0b49ae824b59464
|
File details
Details for the file langchain_pdf_inspector-0.1.1-py3-none-any.whl.
File metadata
- Download URL: langchain_pdf_inspector-0.1.1-py3-none-any.whl
- Upload date:
- Size: 13.2 kB
- Tags: Python 3
- Uploaded using 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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
50a57c1ced78a302a573f90e27b14fd72b497b5e445a7cdb068a65f450c8ebdf
|
|
| MD5 |
6e2c59f53c8bd3eacd59429c6ed9f75d
|
|
| BLAKE2b-256 |
8a77bfddbaedf361179c5332bc4c9fe30c992e525958c7da68fdb6833c5f5620
|