Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions openkb/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from pathlib import Path

import pymupdf
from markitdown import MarkItDown

from openkb.config import load_config
from openkb.images import convert_pdf_with_images, copy_relative_images, extract_base64_images
Expand Down Expand Up @@ -230,7 +229,15 @@ def convert_document(
# Use pymupdf dict-mode for PDFs: text + images inline at correct positions
markdown = convert_pdf_with_images(src, doc_name, images_dir)
else:
# Non-PDF, non-MD: use markitdown (docx, pptx, html, etc.)
# Non-PDF, non-MD: use markitdown (docx, pptx, html, etc.).
# Imported lazily: markitdown pulls in magika → onnxruntime (tens
# of MB, slow to import) that only this branch needs. Keeping it
# out of module import makes `import openkb` cheap and lets a
# packaged build drop those deps when Office-format ingest isn't
# required. markitdown appends warning filters on import but leaves
# the CLI's front "ignore" filter in place, so no re-suppress here.
from markitdown import MarkItDown

mid = MarkItDown()
result = mid.convert(str(src), keep_data_uris=True)
markdown = result.text_content
Expand Down
34 changes: 33 additions & 1 deletion tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

import subprocess
import sys
from unittest.mock import MagicMock, patch

from openkb.converter import convert_document, get_pdf_page_count
Expand Down Expand Up @@ -145,7 +147,7 @@ def test_docx_conversion_enables_keep_data_uris(self, kb_dir, tmp_path):
mock_result.text_content = "![](data:image/png;base64,abc123)"

with (
patch("openkb.converter.MarkItDown") as mock_markitdown,
patch("markitdown.MarkItDown") as mock_markitdown,
patch(
"openkb.converter.extract_base64_images",
return_value="converted markdown",
Expand All @@ -164,6 +166,36 @@ def test_docx_conversion_enables_keep_data_uris(self, kb_dir, tmp_path):
assert result.source_path.read_text(encoding="utf-8") == "converted markdown"


# ---------------------------------------------------------------------------
# Lazy markitdown import (guards the deferred-import optimization)
# ---------------------------------------------------------------------------


class TestLazyMarkItDownImport:
def test_importing_converter_does_not_load_markitdown(self):
"""`import openkb.converter` must not pull in markitdown/magika/onnxruntime.

markitdown is imported lazily inside convert_document's Office-format
branch so `import openkb` stays cheap and a packaged build can drop
magika/onnxruntime. This runs in a fresh interpreter (a clean
sys.modules) so the assertion is deterministic regardless of what other
tests in this process already imported.
"""
heavy = ("markitdown", "magika", "onnxruntime")
code = (
"import sys, openkb.converter; "
f"print(','.join(m for m in {heavy!r} if m in sys.modules))"
)
proc = subprocess.run(
[sys.executable, "-c", code],
capture_output=True,
text=True,
)
assert proc.returncode == 0, proc.stderr
loaded = proc.stdout.strip()
assert loaded == "", f"import openkb.converter eagerly loaded: {loaded}"


# ---------------------------------------------------------------------------
# _registry_path
# ---------------------------------------------------------------------------
Expand Down
Loading