brotlicffi
Python CFFI bindings for Google's Brotli compression library, providing an API-compatible fallback for PyPy and other non-CPython runtimes.
Repository Health
Technical Analysis
brotlicffi provides Python bindings to Google’s reference Brotli encoder and decoder using CFFI instead of the CPython C API, making it usable on PyPy and other non-CPython implementations where the standard brotli package’s C extension won’t build. It bundles the reference C implementation of Brotli as a git submodule and statically compiles it by default, so no separate system Brotli library needs to be installed unless USE_SHARED_BROTLI=1 is set.
The library exposes a small, drop-in-compatible API — module-level compress()/decompress() functions plus streaming Compressor/Decompressor classes — that mirrors the CPython C-extension Brotli package closely enough that projects typically install both and fall back to brotlicffi conditionally based on platform_python_implementation.
What You Get
- One-shot
compress()/decompress()functions for single-call compression of complete byte strings - Streaming
Compressor/Decompressorclasses for incremental compression of data that arrives in chunks - A statically bundled copy of the reference Brotli C library (via git submodule) so no system-level Brotli install is required
- An API-compatible drop-in replacement for the CPython
BrotliC-extension package, letting projects support PyPy and other non-CPython runtimes
Common Use Cases
- Adding Brotli compression support to an HTTP client or server running on PyPy, where the C-extension
brotlipackage cannot be installed - Decompressing Brotli-encoded HTTP response bodies (Content-Encoding: br) in an HTTP library
- Building cross-implementation Python packages that need Brotli support on both CPython and non-CPython interpreters
- Streaming compression of large payloads where data arrives incrementally and cannot be buffered in memory all at once
Under The Hood
Architecture brotlicffi is architected as a thin single-module wrapper (src/brotlicffi/_api.py, roughly 600 lines) sitting directly atop a build-time-generated CFFI extension. src/brotlicffi/_build.py declares the C signatures via ffi.cdef() and set_source(), and setup.py’s custom BuildClibBeforeExt subclass of build_ext forces the build_clib step to run first so the vendored libbrotli C sources (a git submodule under libbrotli/) get statically compiled and linked into the resulting _brotlicffi extension module. _api.py then imports that generated ffi/lib pair and exposes two layers: high-level, one-shot compress()/decompress() convenience functions, and lower-level Compressor/Decompressor classes that each own a single native encoder/decoder instance guarded by a threading.Lock/RLock (raising error() if a concurrent caller tries to reuse the same instance). init.py does nothing more than re-export the public names and version. There is essentially no additional layering — no plugin system, no dependency injection — which is appropriate for a binding library whose only job is to move bytes between Python and a native compression routine.
Tech Stack The project’s only runtime dependency is cffi, used for the FFI binding instead of the CPython C-API so the same extension can build on PyPy. By default (unless the USE_SHARED_BROTLI=1 environment variable is set) it statically compiles the vendored reference Brotli C sources from the libbrotli git submodule rather than requiring a system-installed libbrotli; when USE_SHARED_BROTLI=1 it links against system brotlienc/brotlidec (plus stdc++ on non-Windows) instead. Testing runs through pytest and pytest-cov, orchestrated by tox across a matrix from py37 through py314(t) plus PyPy, and linting runs via flake8 with a max-complexity-10 gate. CI (GitHub Actions) runs the lint job plus the full test matrix across ubuntu-latest, macos-latest, and windows-latest. Documentation is built with Sphinx from docs/source/, and an example/ directory demonstrates the CPython/CFFI fallback pattern end-to-end.
Code Quality Test coverage comes from four dedicated files (test_simple_compression.py, test_simple_decompression.py, test_compatibility.py, test_multithreaded_sharing.py) totalling seventeen test functions plus a shared conftest.py, run under pytest with coverage instrumentation and gated by flake8 in CI across three operating systems and a wide Python version/implementation matrix. Error handling is explicit around a single custom error/Error exception class, with dedicated _validate_mode/_validate_quality/_validate_lgwin/_validate_lgblock helpers that raise clear, parameter-specific messages rather than letting invalid values reach the native layer silently. The codebase has no static type hints or mypy configuration, relying instead on Sphinx-style docstrings with :param:/:type:/:versionadded: annotations for documentation; naming is consistent and the module is small enough that this is a minor gap rather than a real risk.
API Design The public API is deliberately designed for drop-in compatibility with the CPython brotli C-extension package: the same compress()/decompress() function signatures, the same Compressor/Decompressor class names and methods, and the same MODE_GENERIC/MODE_TEXT/MODE_FONT constants, so calling code can try/except ImportError between import brotli and import brotlicffi as brotli without any branching logic. This isn’t algorithmic innovation — the compression algorithm itself is Google’s unmodified reference Brotli implementation — but it is a deliberate, low-boilerplate developer-experience choice: a single conditional import lets existing brotli-based code work unchanged on PyPy and other non-CPython runtimes where the C extension can’t be built.