Fallback Chains for Optional Dependency Probing in book-to-skill

The book-to-skill library uses a declarative DEPENDENCY_GROUPS table to probe optional dependencies, implementing multi-layered fallback chains that gracefully degrade from high-quality extractors to stdlib-based parsers when external packages are unavailable.

Understanding how open-source tools handle missing dependencies is critical for building resilient data pipelines. The book-to-skill project—available at virgiliojr94/book-to-skill—implements an elegant probing system that prioritizes user experience through intelligent fallback chains. This article examines the complete mechanism, from dependency declaration to runtime satisfaction logic.

The DEPENDENCY_GROUPS Declaration Table

All fallback behavior originates in book_to_skill/dependencies.py (lines 13‑70). The DEPENDENCY_GROUPS list defines every supported format with structured metadata that drives the probing engine.

Each dependency group contains these key fields:

  • modules — Python packages that can handle the format
  • any_of_modules — When True, only one module needs to be present; when False, all are required
  • any_tool_suffices — When True, either a Python module OR a system command satisfies the requirement
  • system — External binaries as tuples of (command, pretty-name, install-hint)
  • required — If set, the format has no fallback and extraction aborts
  • note — Human-readable description of the fallback chain

Complete Fallback Chain Reference

The following table maps each format to its probing behavior and degradation path:

Format Primary Dependencies Fallback When Missing
PDF (text-heavy) pdftotext or pypdf or pdfminer Any installed Python PDF parser; extraction fails if none present
PDF (technical) docling Falls back to PDF text-heavy chain
EPUB ebooklib and bs4 zipfile + html.parser from stdlib
DOCX docx zipfile + xml.etree.ElementTree from stdlib
HTML trafilatura or bs4 or html.parser Always degrades to stdlib html.parser
RTF striprtf Basic regex-based cleanup
MOBI/AZW/AZW3 ebook-convert (Calibre) No fallback — mandatory external tool

These chains are encoded in the note fields at lines 24, 30, 37‑45, 51‑58, and 68‑69 of book_to_skill/dependencies.py.

Source Code Structure: How Probing Works

Step 1: Availability Checking

The run_dependency_check function (lines 73‑115) iterates through DEPENDENCY_GROUPS and probes each dependency:

from book_to_skill.dependencies import run_dependency_check

# Returns a structured report of ready/missing/fallback-available formats

status = run_dependency_check()

Two helper functions perform the actual probing:

  • python_module_available(module_name) (lines 73‑75) — tests Python importability
  • shutil.which(command) — locates system binaries on PATH

Step 2: Satisfaction Determination

The decision block at lines 80‑94 evaluates each group against the declared flags:


# Simplified logic from lines 81-94

if required and not satisfied:
    status = "missing-required"  # Hard failure

elif any_tool_suffices and has_any_module_or_system:
    status = "ready"
elif any_of_modules and has_any_module:
    status = "ready"
elif not any_of_modules and has_all_modules:
    status = "ready"
else:
    status = "fallback-available"  # Degrade gracefully

Step 3: Runtime Fallback Handling

The prepare_dependencies function (lines 94‑136) orchestrates the actual fallback during extraction:

from book_to_skill.dependencies import prepare_dependencies

# Example: HTML extraction with automatic fallback

prepare_dependencies(ext=".html", extraction_mode="default", install_mode="ask")

Typical console output when falling back:


HTML extraction uses beautifulsoup4, if installed, otherwise a stdlib HTML parser.
Non-interactive mode or install disabled; using fallback.
Using fallback: a stdlib HTML parser.

Practical Code Examples

Running the Full Dependency Audit

Execute the built-in checker to see your system's status across all formats:

python -m book_to_skill --check

This invokes run_dependency_check and prints a formatted table with installation suggestions (lines 111‑115).

Programmatic Dependency Probing

Check a specific format before extraction:

from book_to_skill.dependencies import (
    DEPENDENCY_GROUPS,
    python_module_available
)
import shutil

def check_pdf_readiness():
    """Probe PDF extraction capabilities with full fallback chain."""
    pdf_group = next(g for g in DEPENDENCY_GROUPS if "PDF (text-heavy)" in g["label"])
    
    # Check Python modules

    modules_ok = any(
        python_module_available(m) 
        for m in pdf_group["modules"]
    )
    
    # Check system tools

    system_ok = any(
        shutil.which(cmd) for cmd, _, _ in pdf_group["system"]
    )
    
    return {
        "ready": modules_ok or system_ok,
        "has_pypdf": python_module_available("pypdf"),
        "has_pdfminer": python_module_available("pdfminer"),
        "has_pdftotext": shutil.which("pdftotext") is not None
    }

Handling Isolated Tool Installations

For tools installed via pipx or similar isolation mechanisms:

from book_to_skill.dependencies import isolated_install_hint

print(isolated_install_hint("docling"))

# → a `docling` command exists at /home/user/.local/pipx/venvs/docling/bin/docling,

#   so it is installed in an isolated environment ...

Optional Dependency Installation Flow

When install_mode is set to "ask" or "auto", the offer_dependency_install function (invoked from prepare_dependencies) can resolve missing Python packages:

from book_to_skill.dependencies import install_python_packages

# Automatic resolution (lines 111-127)

install_python_packages(["pypdf", "beautifulsoup4"], mode="auto")

The installation respects the mapping in book_to_skill/config.py (PYTHON_DEPENDENCIES), which translates import names to pip package identifiers.

Key Implementation Files

File Responsibility
book_to_skill/dependencies.py Core probing logic, DEPENDENCY_GROUPS definition, satisfaction evaluation (lines 13‑70, 73‑95, 94‑136)
book_to_skill/config.py Module-to-package name mapping (PYTHON_DEPENDENCIES) for installation
scripts/extract.py CLI entry point, --check reporter invocation
book_to_skill/cli.py Argument parsing for --install-missing and related flags
tests/test_book_to_skill.py Verified fallback behavior across all format chains

Summary

  • DEPENDENCY_GROUPS in book_to_skill/dependencies.py (lines 13‑70) provides the single source of truth for all optional dependency probing and fallback chains.
  • Three-tier satisfaction logic (ready / fallback-available / missing-required) enables graceful degradation without hard failures for most formats.
  • MOBI/AZW/AZW3 is the sole exception with no fallback—it requires Calibre's ebook-convert as a mandatory external dependency.
  • Automatic installation can resolve missing Python packages when configured, while system tools always require manual installation.
  • Stdlib fallbacks for EPUB, DOCX, and HTML ensure basic functionality even in minimal environments.

Frequently Asked Questions

How does book-to-skill handle missing PDF libraries?

The PDF text-heavy format accepts any one of pdftotext (system), pypdf, or pdfminer. Probing occurs via shutil.which for system tools and python_module_available for Python packages. If none are found, extraction fails with a diagnostic message. Technical PDFs using docling automatically fall back to the text-heavy chain.

Can I force book-to-skill to use stdlib parsers only?

Not directly through a global flag, but you can uninstall or exclude the optional packages. For HTML specifically, the tool always prefers trafilatura, then beautifulsoup4, then html.parser—so absence of the first two forces stdlib usage. For EPUB and DOCX, removing ebooklib/docx triggers zipfile-based extraction.

What happens if ebook-convert is not installed for MOBI files?

The MOBI/AZW/AZW3 group has required=True, meaning no fallback exists. The prepare_dependencies function returns a hard failure status, and extraction aborts with instructions to install Calibre. This is the only format in DEPENDENCY_GROUPS with mandatory external dependencies.

How do I check my system's dependency status before running extraction?

Run python -m book_to_skill --check or programmatically call run_dependency_check(). This prints a formatted table showing ready formats, available fallbacks, and missing required tools—with specific installation commands for your platform.

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 →