cquarry
Canonical Calibre database layer and search grammar engine for Calibre libraries.
This library powers CalibreQuarry (CLI/TUI), Hermitage (GTK4 gallery), Carrel-calibre-web (web reader), and Bindery (EPUB repair & audit). By centralizing the search grammar parser and metadata access, cquarry evaluates virtual library definitions and search queries consistently across frontends.
Features
- Direct SQLite access. No
calibredbbinary required, no Calibre Python initialization overhead. - Lock-safe snapshots. Automatically detects if Calibre holds an exclusive write lock on
metadata.dband routes queries through a temporary WAL-consistent copy. - Full search grammar parity. A recursive-descent parser implementing Calibre's native search capabilities: boolean logic, field prefixes, date math (hyphen and slash separators), hierarchical tags with
./..component modifiers on every text field, custom columns, identifiers, saved-search interpolation (search:"Name"), multi-valued count operators (tags:#>3), language canonicalization (languages:English→eng), and nested virtual library cross-references. - Native page counts. The
pages:location reads Calibre's ownbooks_pages_linktable first (maintained by upstream's CountPages integration) and falls back to an int custom column labelledpages; counts also ride along in every book row. - Entity secondary columns & display config. Book rows carry
author_sorts/author_linksparallel toauthors;get_entities(kind)exposes{id, name, sort, link, count}for authors/series/publishers/tags/languages; custom columns reporteditable,normalizedand their decodeddisplayJSON (enum_values,enum_colors, …); and a typed preferences accessor covers everything else (get_preference,get_field_metadata,get_user_categories,get_tag_browser_state). - Metadata portability. Read e-reader annotations, per-device reading progress, third-party plugin data, and conversion profiles; sanitize comments HTML for display.
- Opt-in write path.
cquarry.write.WritableCalibreDBoffers trigger-safe mutations in a separate module the read-only API can never touch: title, authors (withauthor_sortrecomputation), series (+index), publisher, rating (UNIQUE-deduped), languages (canonicalized to ISO codes), tags, identifiers, comments, generic custom-column writes (layout auto-detected, enumerations validated againstdisplay.enum_values, non-editable columns refused), format registration/removal,has_cover, and full book removal with orphan pruning; every mutation queued inmetadata_dirtiedfor OPF resync. - Context manager.
CalibreDBsupportswithstatements for automatic cleanup of snapshot files. - Zero dependencies. Pure Python 3.14+ stdlib (
sqlite3,re,json,unicodedata).
Usage
from cquarry.db import CalibreDB
# Open a library (creates a snapshot if Calibre has the lock)
with CalibreDB("~/Calibre Library/metadata.db") as db:
# Fetch all books with pre-joined metadata
books = db.get_all_books()
# Search using Calibre's native grammar
sci_fi = db.search("tags:Fic.SciFi and rating:>=4")
print(f"Found {len(sci_fi)} highly rated Sci-Fi books.")
# Resolve a virtual library to a set of book IDs
wing = db.resolve_vl("To Read")
# Interpolate a saved search straight from Calibre's preferences
award_winners = db.search('search:"Award Winners"')
# Inspect custom columns (#label, bare label, or display name all work)
cols = db.get_custom_columns()
status = db.load_custom_column("#reading_status")
# Single-entity helpers (no whole-library scan)
book = db.get_book(42)
epub = db.get_format_path(42, "EPUB")
# Metadata portability
highlights = db.get_annotations(42)
progress = db.get_last_read_positions(42)
wordcounts = db.get_plugin_data(name="wordcount")
The composed deep fetch combines metadata, formats, custom columns, and annotations:
dossier = db.get_book_dossier(42, include_comments=True)
print(dossier["formats"], dossier["custom_columns"])
print(dossier["comments"]["plain"]) # comments HTML, already stripped
Writes live behind an explicit opt-in import:
from cquarry.write import WritableCalibreDB
with WritableCalibreDB("~/Calibre Library/metadata.db") as wdb:
wdb.add_tag(42, "Audited")
wdb.set_identifier(42, "isbn", "9780123456789")
wdb.clear_identifier(42, "mobi-asin") # honest no-op when absent
# A multi-book curation pass commits exactly once:
with WritableCalibreDB("~/Calibre Library/metadata.db") as wdb:
with wdb.batch():
wdb.set_pubdate(42, "1991-10-01")
wdb.add_tag(43, "Audited")
# Every mutation queues an OPF regeneration; check what Calibre will resync:
with CalibreDB("~/Calibre Library/metadata.db") as db:
print(db.get_dirtied_books()) # e.g. [42, 43]
Installation
pip install cquarry
API at a glance
The full per-method reference lives in API.md. One line per module:
| Module | What it is |
|---|---|
cquarry.db |
The read-only database layer (CalibreDB): hydrated rows, single-entity fetches, format/cover path resolution, custom columns, preferences, annotations and progress extractors, VL/saved-search resolution, and the composed get_book_dossier() deep fetch. |
cquarry.search |
The lexer/parser/evaluator porting Calibre's search grammar; usable standalone behind the MetadataProvider protocol. |
cquarry.helpers |
Domain utilities: rating conversion, comment sanitization, author display, series gaps, image dimension sniffing, the ISBN family (isbn_normalize, isbn_check_digit_is_valid, to_isbn13), and tag_rollup. |
cquarry.integrity |
The shared library-integrity predicates: untagged, unrated, authorless, formatless, coverless, missing cover files, deprecated formats, low-res covers, duplicates, series gaps. |
cquarry.analytics |
Shared derivations: addition timeline, per-author stats, rating distribution, virtual library (wing) overlap. |
cquarry.write |
The opt-in mutation path (WritableCalibreDB): trigger-safe setters, batch() transactions, remove_book. Every mutation queues OPF resync. |
cquarry.config |
Saved database-path configuration (~/.config/cquarry/config.json). |
Development
python -m pytest tests/ # full suite
python -m pytest tests/ -v # verbose
Run with PYTHONPATH=src to exercise this checkout rather than any installed copy.
Six test modules: test_db.py (CalibreDB against fixture databases), test_helpers.py (utility functions), test_search.py (parser, matcher, and integration tests), test_write.py (opt-in write module with trigger-hazard fixtures), test_integrity.py (library integrity predicates), and test_analytics.py (analytics derivations).
See spec.md for the full contract and roadmap.md for planned work.
Acknowledgements
Carrel-calibre-web is a fork of calibre-web that uses cquarry as its search and virtual-library engine. Features proven there flow back into cquarry's roadmap (see Phase 7); calibre-web's original authors deserve the credit for the web experience that fork builds on.
Support
If cquarry is useful to you and you'd like to chip in:
- liberapay · liberapay.com/bdkl
- bitcoin
bc1qkge6zr45tzqfwfmvma2ylumt6mg7wlwmhr05yv
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cquarry-1.11.1.tar.gz.
File metadata
- Download URL: cquarry-1.11.1.tar.gz
- Upload date:
- Size: 139.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd1fed5b5d3b79f9217d55997c2c33acdac102c0bf5ed2a4f3ee706742b9a0a9
|
|
| MD5 |
f121bdb3ae8e7432d8f84d8f0c08a080
|
|
| BLAKE2b-256 |
42c141ec4cc1d9d8c2c02a092de85b5eaf428a26a8fef8dc651cdd9c4a3c78d7
|
Provenance
The following attestation bundles were made for cquarry-1.11.1.tar.gz:
Publisher:
publish.yml on VirInvictus/cquarry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cquarry-1.11.1.tar.gz -
Subject digest:
bd1fed5b5d3b79f9217d55997c2c33acdac102c0bf5ed2a4f3ee706742b9a0a9 - Sigstore transparency entry: 2705504391
- Sigstore integration time:
-
Permalink:
VirInvictus/cquarry@2f05b0dc419d1429a64ae2544e51f675a3bcdead -
Branch / Tag:
refs/tags/v1.10.0 - Owner: https://github.com/VirInvictus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f05b0dc419d1429a64ae2544e51f675a3bcdead -
Trigger Event:
push
-
Statement type:
File details
Details for the file cquarry-1.11.1-py3-none-any.whl.
File metadata
- Download URL: cquarry-1.11.1-py3-none-any.whl
- Upload date:
- Size: 55.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d59e8e940cca0ffd1d947e84ea2c3385b12e12c1900c840095d83bb2fbf688a2
|
|
| MD5 |
9be23e331ccc85935cca69d4d9355140
|
|
| BLAKE2b-256 |
368ac010d0d0ae6a5c6a182c442cfe6c5febeb61fffd435b425096f1ac4c1fb3
|
Provenance
The following attestation bundles were made for cquarry-1.11.1-py3-none-any.whl:
Publisher:
publish.yml on VirInvictus/cquarry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cquarry-1.11.1-py3-none-any.whl -
Subject digest:
d59e8e940cca0ffd1d947e84ea2c3385b12e12c1900c840095d83bb2fbf688a2 - Sigstore transparency entry: 2705504462
- Sigstore integration time:
-
Permalink:
VirInvictus/cquarry@2f05b0dc419d1429a64ae2544e51f675a3bcdead -
Branch / Tag:
refs/tags/v1.10.0 - Owner: https://github.com/VirInvictus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f05b0dc419d1429a64ae2544e51f675a3bcdead -
Trigger Event:
push
-
Statement type: