Fix Camelot Import Error on Linux

Importing camelot on a fresh Linux environment raises one of three errors. The exact message depends on which system dependency is missing:

ImportError: No module named 'camelot'
ModuleNotFoundError: No module named 'cv2'
OSError: ghostscript not found on PATH

All three errors come from the same root cause: camelot's lattice mode requires two system-level binaries — Ghostscript and OpenCV — that are not installed by a plain pip install camelot-py.

Root Cause

camelot-py is published in two variants on PyPI:

PackageWhat it includesWhen it fails
camelot-pyCore library onlyLattice mode crashes — no OpenCV
camelot-py[cv]Core + OpenCV bindingsWorks if Ghostscript binary is also installed

The cv2 (OpenCV) module handles image processing for lattice-mode table detection. Ghostscript is called as a subprocess to convert PDFs to intermediate images before processing. Neither ships inside a wheel — they are system-level dependencies.

Minimal Diagnostic

Run this before attempting any fix to confirm which component is missing:

# No pip install needed — this only tests imports
def diagnose_camelot() -> dict:
    """Check which camelot dependencies are present."""
    status = {}

    try:
        import camelot
        status["camelot"] = camelot.__version__
    except ImportError as e:
        status["camelot"] = f"MISSING: {e}"

    try:
        import cv2
        status["cv2"] = cv2.__version__
    except ImportError as e:
        status["cv2"] = f"MISSING: {e}"

    import shutil
    gs = shutil.which("ghostscript") or shutil.which("gs")
    status["ghostscript_binary"] = gs or "NOT FOUND"

    return status

if __name__ == "__main__":
    import pprint
    pprint.pprint(diagnose_camelot())

Expected healthy output:

{'camelot': '0.11.0',
 'cv2': '4.9.0',
 'ghostscript_binary': '/usr/bin/ghostscript'}

Any MISSING or NOT FOUND value maps directly to the fix below.

Fix: Install Ghostscript and camelot-pycv

Run the following in order. Do not skip steps — Ghostscript must be present before the Python install or camelot's post-install check will fail.

# Step 1: Install Ghostscript system binary
sudo apt-get update && sudo apt-get install -y ghostscript

# Step 2: Verify the binary is accessible
gs --version
# Expected: 9.x or 10.x

# Step 3: Install camelot with the cv extra (includes OpenCV)
pip install "camelot-py[cv]"

# Step 4: Confirm no import errors
python -c "import camelot; print(camelot.__version__)"

The [cv] extra installs opencv-python-headless as a dependency. This is the headless variant — it has no GUI dependencies, which is correct for server environments.

Variant Fix 1: ModuleNotFoundError: No module named 'cv2'

This error means camelot is installed but the [cv] extra was not included. The package was installed as bare camelot-py:

# Check what is installed
pip show camelot-py | grep -i requires

If cv2 is not in the requirements list, reinstall with the extra:

pip uninstall camelot-py -y
pip install "camelot-py[cv]"

If you are in a virtualenv where opencv-python is already installed (not the headless variant), the cv2 import may still fail due to missing GUI libraries (libGL.so.1):

# Install the headless variant to avoid X11 / display dependencies
pip uninstall opencv-python -y
pip install opencv-python-headless

# Or install the missing system lib directly:
sudo apt-get install -y libgl1

Variant Fix 2: OSError: ghostscript not found at Runtime

This error appears after a successful import camelot — it surfaces when camelot.read_pdf() is first called:

OSError: ghostscript not found on PATH. Please install ghostscript.

The binary is either not installed or not on the PATH seen by the Python process:

# Confirm the binary name — Debian/Ubuntu uses 'ghostscript', others use 'gs'
which ghostscript || which gs

# If missing:
sudo apt-get install -y ghostscript

# If present but not on PATH (e.g., in a restricted shell):
export PATH="$PATH:/usr/bin"
python -c "import camelot; camelot.read_pdf('test.pdf', pages='1', flavor='lattice')"

If running inside a Docker container or CI environment without apt access, use the ghostscript Python binding as a fallback — but note this is slower than the system binary:

pip install ghostscript

Then verify camelot can find it:

# pip install ghostscript camelot-py[cv]
import ghostscript   # exercises the binding
import camelot
print("All dependencies resolved:", camelot.__version__)

Variant Fix 3: ImportError for tkinter on Headless Servers

Some older camelot-py versions imported tkinter at module load time. On headless servers (no display), this raises:

_tkinter.TclError: no display name and no $DISPLAY environment variable

Fix: upgrade camelot to 0.10.1 or later, which dropped the hard tkinter dependency:

pip install --upgrade "camelot-py[cv]"
python -c "import camelot; print(camelot.__version__)"

If upgrading is not possible, set a dummy display before importing:

# Temporary workaround only — upgrade is the proper fix
DISPLAY=:99 python your_script.py

Variant Fix 4: Ghostscript Version Conflict

Camelot calls Ghostscript via the command-line API using version-specific flag sets. If you have a very new Ghostscript (11.x) installed and a pinned older camelot, the subprocess call may fail with:

subprocess.CalledProcessError: Command '['gs', ...]' returned non-zero exit status 1

Check the installed version and whether camelot supports it:

gs --version
pip show camelot-py | grep Version

If Ghostscript is 11.x and camelot is below 0.11, upgrade camelot first:

pip install --upgrade "camelot-py[cv]"

If you cannot upgrade camelot (pinned by another dependency), install an older Ghostscript alongside the current one using the Ghostscript release tarballs at ghostscript.com, then point camelot at it by setting the GS_PROG environment variable:

export GS_PROG=/usr/local/bin/gs-9.56
python your_script.py

Environment-Specific Notes

Docker

Minimal Docker images (Alpine, python:3.x-slim) do not include Ghostscript. Add the following to your Dockerfile before the pip install step:

# Debian-based image
RUN apt-get update && apt-get install -y --no-install-recommends \
    ghostscript \
    libsm6 \
    libxext6 \
    && rm -rf /var/lib/apt/lists/*

RUN pip install "camelot-py[cv]"

libsm6 and libxext6 are required by OpenCV on Debian even in headless mode.

GitHub Actions

Add the system install step before the Python setup action:

- name: Install system dependencies
  run: sudo apt-get update && sudo apt-get install -y ghostscript libsm6 libxext6

- name: Install Python dependencies
  run: pip install "camelot-py[cv]" pandas

Red Hat / CentOS / Fedora

Replace apt-get with dnf:

sudo dnf install -y ghostscript opencv
pip install "camelot-py[cv]"

Note that opencv on dnf installs the C++ library but not the Python binding — the [cv] extra still handles the Python side.

Troubleshooting Table

A quick reference for matching the exact error text to the right fix:

Error messageComponent missingFix command
ImportError: No module named 'camelot'camelot not installedpip install "camelot-py[cv]"
ModuleNotFoundError: No module named 'cv2'OpenCV not installedpip install opencv-python-headless
OSError: ghostscript not found on PATHGhostscript binary missingsudo apt-get install ghostscript
OSError: ghostscript not found on PATHBinary not on Python's PATHexport PATH="$PATH:/usr/bin"
_tkinter.TclError: no display nameOld camelot with tkinter deppip install --upgrade "camelot-py[cv]"
libGL.so.1: cannot open shared object fileNon-headless OpenCV on serverpip install opencv-python-headless
subprocess.CalledProcessError on gs callGhostscript version mismatchpip install --upgrade "camelot-py[cv]"

Confirming the Correct camelot Package Is Installed

There are three similarly named packages on PyPI: camelot-py, camelot (an unrelated project), and camelot-py[cv]. Installing the wrong one is a common mistake:

# Confirm camelot-py is installed, not the unrelated 'camelot' package
pip show camelot-py

# The output should include:
# Name: camelot-py
# ...
# Requires: chardet, click, numpy, openpyxl, pandas, pdfminer.six, pypdf2, tabulate
# (plus opencv-python-headless when installed with [cv])

# If you see 'Name: camelot' without 'py', you have the wrong package:
pip uninstall camelot -y
pip install "camelot-py[cv]"

After a correct install, the import path is always import camelot — both packages use the same name, which is why the error message alone is not enough to distinguish them.

Verification

After applying all fixes, run the full smoke test:

# pip install "camelot-py[cv]" pandas
from pathlib import Path
import camelot
import pandas as pd

def smoke_test(pdf_path: Path) -> None:
    """Verify camelot can open a PDF and return at least one table."""
    if not pdf_path.exists():
        raise FileNotFoundError(f"Test PDF not found: {pdf_path}")
    try:
        tables = camelot.read_pdf(
            str(pdf_path),
            pages="1",
            flavor="lattice",
        )
    except Exception as e:
        raise RuntimeError(f"camelot.read_pdf failed: {e}") from e

    assert tables.n >= 0, "camelot.read_pdf ran without error"
    print(f"camelot {camelot.__version__} OK — found {tables.n} table(s) on page 1")

if __name__ == "__main__":
    # Use any single-page PDF with a bordered table, or any PDF to test import
    smoke_test(Path("data/sample.pdf"))

A clean run with no ImportError, no OSError, and a printed version confirms all dependencies are wired correctly. For the full extraction workflow once camelot is working, continue with Extracting Tables from PDFs.

Part of Extracting Tables from PDFs.