psycogreen

Wait-callback adapters that let psycopg2 run asynchronously under gevent or eventlet coroutine event loops.

Library
PyPI
v1.0.2
110stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
29/100Needs Attention
Development Activity0
Maintenance0
Community36
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
61/100Good
Architecture65
Code Quality45
Innovation78
Learning Curve55

psycogreen is a small integration library that lets psycopg2 cooperate with coroutine-based concurrency frameworks. Psycopg2’s C extension can’t be monkey-patched directly, but it exposes a wait-callback hook that fires whenever a libpq call would block — psycogreen implements that hook for gevent and eventlet, so ordinary blocking-style psycopg2 code can run non-blocking inside a green-thread event loop without any application-code changes.

The package ships two independent modules, psycogreen.gevent and psycogreen.eventlet, each exposing a patch_psycopg() call that registers the appropriate wait callback via psycopg2.extensions.set_wait_callback(). It is intentionally minimal, with no dependencies beyond the coroutine library it targets, and is aimed at psycopg2 users on Python 2 or 3 — Psycopg 3 has gevent support built in and does not need this package.

What You Get

  • Gevent wait callback - psycogreen.gevent.patch_psycopg() registers a callback that polls the connection and yields to gevent’s wait_read/wait_write instead of blocking.
  • Eventlet wait callback - psycogreen.eventlet.patch_psycopg() registers a callback that polls the connection and yields via eventlet’s trampoline().
  • Zero-config integration - one function call patches psycopg2 process-wide; no changes needed to existing query code.
  • Reference test scripts - tests/test_gevent.py and tests/test_eventlet.py demonstrate concurrent downloads overlapping DB queries against a bundled wait_server.py.

Common Use Cases

  • Green-threaded web workers - gevent- or eventlet-based WSGI servers (e.g. gunicorn gevent workers) that use psycopg2 and need DB calls to not block other greenlets.
  • High-concurrency connection pooling - apps holding many concurrent psycopg2 connections where blocking libpq calls would otherwise serialize an event loop.
  • Legacy Python 2/3 codebases on psycopg2 - projects that cannot move to Psycopg 3 (which has native gevent support) but still want cooperative I/O.
  • Mixed I/O workloads - services that interleave HTTP requests and DB queries and want both to overlap under a single-threaded coroutine scheduler.

Under The Hood

Architecture The package is two flat, independent modules — psycogreen/gevent.py and psycogreen/eventlet.py — each exposing a patch_psycopg() entry point and a *_wait_callback(conn, timeout) function that loops on conn.poll() and delegates the wait to its coroutine library’s socket-wait primitive (gevent.socket.wait_read/wait_write versus eventlet.hubs.trampoline). There is no shared base or abstraction layer between the two backends — the poll loop is duplicated across both files — which keeps each module importable without pulling in the other coroutine library’s dependencies, but means the two implementations could drift if psycopg2.extensions.set_wait_callback’s contract ever changed.

Tech Stack Packaging uses a legacy setup.py/setuptools flow rather than a modern PEP 517 build backend (the pyproject.toml only carries Black configuration). The runtime dependency is psycopg2 plus whichever of gevent or eventlet the calling application has installed, imported directly at module scope. The test fixtures pull in six for Python 2/3 compatibility and a small wsgiref-based wait_server.py to simulate blocking I/O, with tox.ini/tools/flake8/tools/black wrapper scripts standing in for CI-grade linting.

Code Quality There is no automated assertion-based test suite: the two scripts under tests/ are manual demonstration programs that require a live PostgreSQL connection and the bundled HTTP server, and they log output rather than assert correctness. No type hints are present, consistent with the project’s Python 2/3-compatible era, though error handling is explicit and narrow (ImportError when set_wait_callback is unavailable, OperationalError on an unexpected poll state). Naming is consistent and functions carry clear docstrings; flake8 and Black wrapper scripts show some lint/format discipline, but there is no visible CI workflow enforcing them.

API Design The public surface is extremely small and symmetric: one patch_psycopg() call per backend module, mirrored function names (gevent_wait_callback/eventlet_wait_callback), and no implicit monkeypatching — the caller opts in explicitly. Getting started requires a single import plus a single function call, and each function’s docstring states exactly what it does, making the developer experience unusually low-friction for such a narrowly scoped integration shim.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search