ebook-convert
Command-line ebook converter carved out of the Calibre project. It is only the conversion pipeline: no GUI, no library management, no Qt, no C extensions, no device drivers.
No installation needed. With uv on your machine, this is the whole thing:
$ uvx ebook-convert book.epub book.mobi
uvx fetches the package into a cache the first time and runs it straight away; later runs start instantly. Swap the extensions to convert between any of the formats listed below, for example uvx ebook-convert novel.docx novel.epub or uvx ebook-convert story.fb2 story.txt.
The package is pure Python and every dependency ships binary wheels, so it runs anywhere with a stock Python 3.12+ and no compiler.
This is the 5.x line of the project: a fresh extraction of current Calibre (9.18.0, git 0ccdcb283f, November 2026) produced by a script, so that it can be re-synchronised with Calibre cheaply. The 4.x line was a hand-pruned copy of Calibre 4.13 from 2020 (gryf’s ebook-converter, later maintained as ebook-convert 4.x); it served as the reference for what this version has to look like and do, and its test-suite is the acceptance suite here. All credit for the conversion code goes to Kovid Goyal and the Calibre contributors; credit for showing that Calibre’s converter can live without Qt goes to gryf.
Installation
The recommended way is not to install at all and run it through uvx as shown above. uv itself is a single binary; see its install page.
If you would rather have a permanent ebook-convert command on your $PATH:
$ uv tool install ebook-convert # with uv
$ pipx install ebook-convert # with pipx
$ pip install ebook-convert # into the current environment
Single-file executables for Linux (x86_64, aarch64) and macOS (arm64, x86_64) that need no Python at all are attached to each GitHub release.
Optional pieces:
pdftohtml, pdfinfo and pdftoppm from poppler are needed in $PATH for conversion from PDF.
pip install 'ebook-convert[markdown]' enables Markdown input (.md); [japanese] adds Japanese transliteration for --asciiize.
optipng, jpegtran/cjpeg and cwebp are used to optimise images when present; Pillow is used otherwise.
Usage
$ ebook-convert INPUT OUTPUT [options]
The command line is Calibre’s own ebook-convert command, unchanged: the output format is taken from the extension of OUTPUT (.EXT alone derives the name from the input, no extension writes an OEB folder), and all of Calibre’s conversion options work, from --authors and --cover to --base-font-size, --chapter, --level1-toc, --extra-css, --embed-font-family, --search-replace and the heuristic processing switches. ebook-convert in.epub out.mobi -h lists the options that apply to that pair of formats. The Calibre conversion manual applies verbatim.
Diagnostics go to stderr; -v makes them more verbose, --debug-pipeline DIR dumps the intermediate stages.
Supported formats
Every entry below is exercised by tools/survey.py with a real conversion (output: EPUB fixture to the format; input: that result back to EPUB, text checked to survive).
Input: azw, azw3, azw4, docx, docm, epub, fb2, fbz, htm, html, xhtml, shtml, htmlz, lrf, md/markdown (needs the markdown extra), mobi, prc, pobi, odt, opf, pdb, updb, pdf (needs poppler), pml, pmlz, rb, rtf, snb, tcr, txt, text, textile, txtz, zip (of HTML), kepub (also as .kepub.epub; the Kobo markup is stripped).
Output: azw3, docx, epub, fb2, htmlz, kepub (or .kepub.epub, Kobo’s own naming), lrf, mobi, oeb (a folder), pdb, pmlz, rb, rtf, snb, tcr, txt, txtz, zip (Calibre’s “HTML output”: a zip of HTML files with an index).
Compared with the 4.x line this adds HTML/zip, PDB, PMLZ, RB, RTF, SNB and TCR output, KEPUB input and output, and PML, RB, SNB, TCR and AZW4 input, plus everything Calibre changed in the converters between 2020 and 2026 (EPUB 3 navigation, KF8 fixes, DOCX tables and footnotes, the new CSS parser, …).
Not included, and why:
PDF output: rendered by Calibre with Qt WebEngine and PoDoFo (C++).
LIT input/output: needs the lzx/msdes C extensions.
CHM and DjVu input: need the chm and bzzdec C extensions.
Comic (CBZ/CBR) input: image processing with Qt, unrar.
News download (recipes): needs Calibre’s web framework.
RAR archives anywhere: need unrardll.
Metadata download, library, devices, viewer, editor, server, AI features: not conversion.
Differences from Calibre
A handful of Calibre’s building blocks are C/C++ or Qt and have been replaced by pure-Python equivalents. These are the places where behaviour can differ from running ebook-convert inside a Calibre install:
Sentence splitting (calibre.spell.break_iterator): the Kobo <span> per sentence in KEPUB output is placed by ICU’s sentence iterator in Calibre. Here it follows kepubify’s rule instead (a sentence ends at ., ! or ?, an optional closing quote or ellipsis, and whitespace), which is what Kobo’s own tooling produces.
ICU (calibre.utils.icu): sorting, case changes and case-insensitive searches are done with Unicode normalisation and case folding from the standard library. Results are locale independent (no Swedish v/w merging, no Turkish i rules, no language specific contractions), and bidi reordering of PDF text (visual_to_logical) is an identity transform. Sorting is only used for things like index pages and manifest ordering; for conversion output the difference is cosmetic.
Images (calibre.utils.img): re-implemented on Pillow. Covers, image rescaling, grayscale/dither for e-ink profiles, GIF/PNG/JPEG/WebP conversion all work; the quality of resampling and JPEG encoding is Pillow’s rather than Qt’s. JPEG-XR needs the external JxrDecApp.
SVG rasterisation: rendered by resvg (resvg_py wheel) instead of QSvgRenderer. resvg is a complete SVG 1.1 renderer; SVG fonts and CSS @font-face inside SVG are not supported.
Generated covers (the “default cover” EPUB output adds when a book has none): a plain title/series/author cover drawn with Pillow, instead of Calibre’s themed, template-driven Qt painter.
HTML parsing: html5lib instead of the html5-parser C extension. Same HTML5 algorithm, slower, and element line numbers are not recorded.
Encoding detection: chardet instead of uchardet.
PalmDOC compression (MOBI/PDB): the Python implementation; slower on very large books.
Translations: none, _() is the identity. All messages are English.
Fonts: no FreeType/fontconfig; the system font scanner reads font files directly (--embed-font-family works with fonts from ~/.fonts, /usr/share/fonts etc.). Liberation fonts are not bundled, so LRF output and font embedding fall back to whatever the system has.
Configuration lives in ~/.config/ebook-convert (XDG), not in Calibre’s directory; Calibre tweaks can be put in a tweaks.json there. Set EBOOK_CONVERT_CONFIG_DIRECTORY to move it.
Workers: jobs Calibre runs in a helper process (pdfinfo metadata, exploding AZW3 files) run in-process.
Reading PDF metadata works (pdfinfo); writing PDF metadata does not (PoDoFo).
How this package is built
ebook_convert/ is generated; do not edit it by hand. Everything that turns a Calibre checkout into this package lives in tools/:
- tools/vendor.py (standard library only)
python tools/vendor.py /path/to/calibre rebuilds ebook_convert/ from scratch, deterministically:
copies an explicit include list (src/calibre/ebooks, customize, the needed utils modules, polyglot, tinycss, css_selectors and the resource files under resources/ into ebook_convert/data/);
deletes an explicit exclude list (LIT/CHM/DjVu/comic/PDF-output/recipe plugins, editor-only oeb/polish modules, metadata download sources, C sources, tests) and every non-Python file outside data/;
rewrites imports: calibre to ebook_convert, polyglot, tinycss, css_selectors, html5_parser and calibre_extensions to the copies/stand-ins inside ebook_convert;
makes Calibre’s Python 3.14 code run on 3.12 and 3.13 (except A, B: to except (A, B):, from compression import zlib to import zlib, type parameter defaults dropped, from __future__ import annotations added for the deferred annotations Calibre relies on);
applies the ordered patch rules in tools/patches/ (small exact text replacements; a rule that no longer matches makes the run fail, which is the point: after a Calibre upgrade you fix or drop the rule);
copies the hand-written modules in tools/overlay/ over the tree;
writes ebook_convert/_vendored.py with the Calibre commit.
python tools/vendor.py --check lists imports of calibre, qt, PyQt or calibre_extensions still present; module-level ones fail the check, indented (lazy) ones are listed for information.
- tools/patches/
One file per patch, applied in name order:
010_localization_iso639: build the ISO-639 language tables from the bundled iso_639-3.json instead of Calibre’s build-time msgpack file.
020_customize_builtins: keep only the archive, metadata and conversion plugins and the profiles; register the verified plugin set.
030_customize_ui: placeholder classes for device drivers and metadata sources in the plugin registry.
040_formatter_functions: inline two constants from calibre.db.
050_conversion_cli: no recipe listing; log to stderr; usage text.
060_docx_paper_sizes: inline the paper size table from the PDF renderer.
070_lrf_device_stub: inline DevicePlugin.THUMBNAIL_HEIGHT.
080_metadata_pdf_podofo: PDF metadata writing raises instead of importing PoDoFo.
090_txt_input_txtz_metadata: read TXTZ metadata from the archive, not from the inner .txt (fixes lost title/author).
100_markdown_series: inline the “Series [index]” parser from calibre.db.
- tools/overlay/
Replacements and additions, kept small and documented in each file:
constants.py, startup.py, utils/resources.py: trimmed constants, process initialisation (_, P(), I() builtins, mimetypes, temp dir) and resource lookup inside ebook_convert/data.
utils/icu.py: the pure-Python ICU replacement described above.
utils/img.py: Pillow image utilities (from the 4.x line, plus WebP and alt-text helpers from current Calibre).
utils/html5.py, html5_parser/: html5lib-based html5_parser.
calibre_extensions/: Python stand-ins for the C extensions speedup, fast_html_entities, cPalmdoc, uchardet, translator and tokenizer (CSS Color 4 parser); any other extension raises ImportError so Calibre’s own fallbacks kick in.
utils/ipc/simple_worker.py, utils/safe_atexit.py: in-process replacements for Calibre’s worker processes.
ebooks/oeb/transforms/rasterize.py: resvg rasteriser.
ebooks/covers.py: Pillow cover generator.
ebooks/metadata/sources/identify.py: urls_from_identifiers only.
main.py: the console entry point.
data/iso_639-3.json: language codes (from the iso-codes project).
- tools/check_imports.py
Imports every module under ebook_convert/ and lists failures.
- tools/survey.py
Runs a real conversion through every registered input and output plugin and prints a table.
Re-syncing with a newer Calibre
$ git clone --depth 1 https://github.com/kovidgoyal/calibre.git /tmp/calibre
$ ./make.sh vendor /tmp/calibre # vendor + --check + import check
$ ./make.sh test
$ ./make.sh survey
If a patch rule no longer matches, vendor.py stops and names it: look at the new Calibre code, update the rule (or remove it if Calibre no longer needs it) and run again. New calibre_extensions names or Qt imports show up in --check and check_imports.py; add a stand-in to the overlay or an entry to the exclude list. Commit the regenerated tree together with the tooling change.
Development
$ ./make.sh install # uv venv with all extras
$ ./make.sh test # pytest (the 4.x acceptance suite + tree checks)
$ ./make.sh check # vendor --check + import every module
$ ./make.sh survey # convert through every plugin
$ ./make.sh build # sdist + wheel + twine check
$ ./make.sh binary # PyInstaller single-file executable
CI runs the test-suite on Python 3.12, 3.13 and 3.14 on Linux and on macOS, builds the wheel and smoke-tests it with uvx.
License
GPL-3.0-or-later, like Calibre. Copyright Kovid Goyal and the Calibre contributors for the converted code (headers are kept in every file); the tooling and overlay modules are copyright their respective authors as noted in the files.
Metadata
Release files for ebook-convert 5.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| ebook_convert-5.0.0.tar.gz | 2.1 MB | Without provenance | Details for ebook_convert-5.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| ebook_convert-5.0.0-py3-none-any.whl | Python 3 | none | any | Details for ebook_convert-5.0.0-py3-none-any.whl |
Total release size: 4.4 MB
Release files / ebook_convert-5.0.0.tar.gz
| Download URL | ebook_convert-5.0.0.tar.gz |
|---|---|
| Size | 2.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
db787bdc91b16dc28389040e02709cbb29154e4825c07424a1e4b8ad508cd0bb
|
|
BLAKE2b-256 checksum How to use checksums |
839a0a9e6bf8f245279f61fdc2e4c901326ebcf3c63b8f38c873d63242973f74
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.5.26
|
Release files / ebook_convert-5.0.0-py3-none-any.whl
| Download URL | ebook_convert-5.0.0-py3-none-any.whl |
|---|---|
| Size | 2.3 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6661892fb59cf05dc4a28b767b735624c4b50b597ac4a32d169adeb34e661825
|
|
BLAKE2b-256 checksum How to use checksums |
374e45f4288f2c80ef179107c623f1735869412c3908832c0a31c57ed3d79ed9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.5.26
|
Security for ebook-convert 5.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.