Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/pymupdf/pymupdf4llm-mcp/llms.txt

Use this file to discover all available pages before exploring further.

The project uses pytest for testing, with inline-snapshot for golden-file style assertions and pytest-cov for coverage reporting. Tests are deterministic and run against a bundled minimal PDF fixture so no external files are required.

Running Tests

Run the full test suite with a single Make target:
make test
# equivalent to:
uv run python -m pytest --inline-snapshot=report --cov --cov-config=pyproject.toml --cov-report=xml
This collects all tests under tests/, checks inline snapshots for drift, measures branch coverage, and writes a coverage.xml report.
To iterate quickly on a single file during development, run pytest directly against it:
uv run pytest tests/test_tool.py -v

Test Structure

Tests live in the tests/ directory alongside a small PDF fixture:
PathPurpose
tests/test_tool.pyTests for the convert_pdf_to_markdown function
tests/dummy.pdfMinimal single-page PDF used as a test fixture

test_tool.py

The test file exercises both code paths exposed by convert_pdf_to_markdown — inline conversion and file-save conversion — and pins their output with snapshot assertions:
import tempfile
from pathlib import Path

from inline_snapshot import snapshot

from pymupdf4llm_mcp.app import convert_pdf_to_markdown

_HERE = Path(__file__).parent
dummy_pdf_path = _HERE / "dummy.pdf"


def test_convert_pdf_to_markdown():
    result = convert_pdf_to_markdown(dummy_pdf_path.as_posix())
    assert result["success"] is True
    assert "markdown_content" in result
    assert result["markdown_content"] == snapshot("""\
# **Dummy PDF file**


-----

""")

    # temporary file to write the markdown content
    with tempfile.NamedTemporaryFile(suffix=".md", delete=False) as temp_file:
        temp_file_path = Path(temp_file.name)
        result = convert_pdf_to_markdown(dummy_pdf_path.as_posix(), save_path=temp_file_path.as_posix())
        assert result["success"] is True
        assert "markdown_path" in result
        assert result["markdown_path"] == temp_file_path.expanduser().resolve().absolute().as_posix()
        with open(temp_file_path, encoding="utf-8") as f:
            content = f.read()
            assert content == snapshot("""\
# **Dummy PDF file**


-----

""")
The test covers two scenarios:
  • Inline conversion — calls convert_pdf_to_markdown without a save_path and asserts the result contains a markdown_content key with the expected Markdown string
  • File-save conversion — calls convert_pdf_to_markdown with a save_path pointing to a temporary file, asserts the result contains a markdown_path key with the resolved absolute path, then reads the file and checks its contents against a snapshot
Both paths share the same snapshot value because the same PDF produces the same Markdown regardless of how the output is delivered.

Snapshot Testing

Snapshots are stored inline in the test source using the inline-snapshot library. When a test runs with --inline-snapshot=report (the default via make test), any drift between actual output and the stored snapshot causes the test to fail without modifying the file. To update snapshots after an intentional change to the Markdown output:
make snapshot
# equivalent to:
uv run python -m pytest --inline-snapshot=fix --cov --cov-config=pyproject.toml --cov-report=xml
The --inline-snapshot=fix flag rewrites the snapshot strings in-place to match the current output.
Always review snapshot updates carefully before committing. An unintended change to the Markdown output will pass make snapshot silently, replacing the correct expected value with a broken one. Diff the file after running make snapshot to confirm only expected lines changed.

Coverage

Coverage is configured in pyproject.toml under [tool.coverage]:
[tool.coverage.report]
skip_empty = true

[tool.coverage.run]
branch = true
source = ["pymupdf4llm_mcp"]
omit = ["tests/*", "pymupdf4llm_mcp/cli.py"]
Key points:
  • Source: only the pymupdf4llm_mcp package is measured — test files themselves are excluded
  • Branch coverage: enabled, so both sides of every conditional are tracked
  • cli.py excluded: the CLI entry point is thin glue code that wires up Typer and is not exercised by the unit tests
  • Output: coverage is written to coverage.xml in the project root, which CI picks up for reporting

Cross-Version Testing with tox

The project officially supports Python 3.10, 3.11, 3.12, and 3.13. To verify compatibility across all supported interpreters, run tox:
tox
tox creates an isolated environment for each Python version and runs the full pytest suite inside each one. This requires all target versions to be installed locally. If they are not, you can skip this step — CI runs tox automatically on every pull request and will catch cross-version regressions for you.

Build docs developers (and LLMs) love