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 formatany_of_modules— WhenTrue, only one module needs to be present; whenFalse, all are requiredany_tool_suffices— WhenTrue, either a Python module OR a system command satisfies the requirementsystem— External binaries as tuples of(command, pretty-name, install-hint)required— If set, the format has no fallback and extraction abortsnote— 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 importabilityshutil.which(command)— locates system binaries onPATH
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_GROUPSinbook_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-convertas 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →