How Book-to-Skill Probes for Optional Dependencies: Detection Logic Explained

Book-to-Skill detects optional dependencies by verifying Python module importability with importlib.util.find_spec and system binary availability via shutil.which, orchestrated through functions in book_to_skill/dependencies.py to enable graceful degradation when extraction enhancers are absent.

Unlike monolithic tools that fail on missing requirements, Book-to-Skill treats most third-party packages and external utilities as optional—they improve extraction fidelity but are not hard requirements (with the sole exception of Calibre for MOBI/AZW processing). The repository implements a two-stage probing system that defines dependency groups per format and validates them at runtime.

Defining Dependency Groups in dependencies.py

The probing logic centers on a declarative data structure defined at the top of [book_to_skill/dependencies.py](https://github.com/virgiliojr94/book-to-skill/blob/master/book_to_skill/dependencies.py) (lines 13‑70). Each supported format declares its Python modules, system commands, and fallback rules using dictionaries that specify whether any or all dependencies must be present.

For PDF text extraction, the configuration looks like this:

{
    "label": "PDF (text‑heavy)",
    "modules": ["pypdf", "pdfminer"],
    "any_of_modules": True,
    "any_tool_suffices": True,
    "system": [("pdftotext", "poppler‑utils",
                "sudo apt install poppler-utils")],
    "note": "any one of pdftotext / pypdf / pdfminer is enough",
}

This structure maps file extensions to their optimal and fallback parsers, storing installation hints for both PyPI packages and system-level tools.

Runtime Probing Mechanism

When the extractor initializes, it invokes either prepare_dependencies() (for per-format checks during extraction) or run_dependency_check() (when users run extract.py --check). Both functions rely on a shared set of utility helpers to probe the environment without importing heavy libraries upfront.

Python Module Detection

The function python_module_available(module_name) checks if a package is installed using importlib.util.find_spec, which locates the module specification without executing import side effects:

present_modules = [m for m in group["modules"] if python_module_available(m)]

This approach avoids the performance penalty of actually importing libraries like pypdf or pdfminer.six just to verify their existence.

System Binary Detection

For external tools such as pdftotext (from poppler-utils), the system uses shutil.which(cmd) to verify the binary exists on the system PATH:

system_present = [c for c, _, _ in group["system"] if shutil.which(c)]

The Core Probing Loop

The run_dependency_check() function iterates over DEPENDENCY_GROUPS and aggregates status reports. It prints a ✓/✗ status for each component and compiles missing items into installation commands. According to the source code, if all optional dependencies are satisfied, the probe outputs:


All optional dependencies are installed. You're ready for every format.

Installation Handling and Graceful Fallbacks

When dependencies are missing, Book-to-Skill does not halt execution. Instead, offer_dependency_install() evaluates the install_mode parameter (set via the --install-missing CLI flag or the BOOK_SKILL_INSTALL_MISSING environment variable) to decide whether to prompt the user, auto-install packages, or proceed with fallbacks.

For automatic remediation, install_python_packages() executes pip install for missing Python modules:

if ext == ".pdf" and not shutil.which("pdftotext"):
    offer_dependency_install(
        feature="PDF text extraction",
        module_names=["pypdf", "pdfminer"],
        fallback="any installed Python PDF parser; extraction fails if none are available",
        install_mode=install_mode,
    )

The per-format probe (prepare_dependencies()) limits its scope to the file extension being processed, ensuring extraction proceeds with the best available tool while degrading to fallback parsers if the optimal ones are absent.

Checking Dependencies via CLI

Users can audit their environment without processing a book by running the standalone dependency check:

python -m book_to_skill extract.py --check

This produces a formatted report listing each format, the status of its Python modules (e.g., pypdf, pdfminer.six), and system utilities (e.g., pdftotext), along with exact installation commands for missing components.

To enable automatic installation during extraction:

python -m book_to_skill extract.py mybook.pdf --install-missing yes

This triggers the detection flow: identifying missing modules and binaries, installing Python packages via pip, and continuing extraction using the newly available or fallback parsers.

For programmatic integration, developers can invoke the probe directly:

from book_to_skill.dependencies import prepare_dependencies, normalize_install_mode

install_mode = normalize_install_mode(["--install-missing", "yes"])
prepare_dependencies(ext=".pdf", extraction_mode="technical", install_mode=install_mode)

Summary

  • Centralized definitions: All optional dependencies are declared in book_to_skill/dependencies.py (lines 13‑70) with fallback rules and installation hints.
  • Non-invasive detection: The system uses importlib.util.find_spec for Python packages and shutil.which for binaries, avoiding heavy imports during checks.
  • Flexible installation: The offer_dependency_install() function respects user preferences via CLI flags (--install-missing) or environment variables (BOOK_SKILL_INSTALL_MISSING).
  • Graceful degradation: Extraction proceeds using available fallbacks when optional enhancers are missing, with only format-specific hard requirements (like Calibre for MOBI) causing failure.

Frequently Asked Questions

How does Book-to-Skill verify if a Python package is installed without importing it?

According to the source code in book_to_skill/dependencies.py, the python_module_available() function uses importlib.util.find_spec(module_name) to locate the module specification without executing the import statement. This lightweight check avoids the memory and startup overhead of loading heavy libraries like pdfminer.six or pypdf just for verification purposes.

What happens if an optional system tool like pdftotext is missing?

The probing logic in run_dependency_check() marks the tool as missing (✗) and checks if any Python-based fallback modules are available. If any_tool_suffices is set to True in the dependency group definition, the extractor proceeds using alternative parsers like pypdf or pdfminer, though potentially with reduced extraction quality for complex layouts.

Can Book-to-Skill automatically install missing dependencies?

Yes, when invoked with --install-missing yes or when the BOOK_SKILL_INSTALL_MISSING environment variable is set, the offer_dependency_install() function triggers install_python_packages() to run pip install for missing Python modules. System tools must still be installed manually, but the dependency check outputs the exact command (e.g., sudo apt install poppler-utils) required.

Which dependency is mandatory rather than optional?

While Book-to-Skill treats most third-party packages as optional, Calibre is a hard requirement specifically for processing MOBI and AZW ebook formats. All other dependencies—including PDF parsers, OCR engines, and text extraction libraries—operate on a fallback system where the tool degrades gracefully if the optimal extractor is unavailable.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →