vine

Lightweight Python promise implementation powering Celery's async callback chains

Library
PyPI
v5.1.0
128stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
58/100Fair
Development Activity52
Maintenance24
Community76
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
75/100Good
Architecture70
Code Quality78
Innovation68
Learning Curve82

vine is a small, dependency-free Python library that implements the promise pattern for both eventual values and lazy evaluation. Originally extracted from Celery, it lets callbacks, errbacks, and filters all be promises themselves, so callback chains can be composed the same way regardless of whether a value is already available or still pending.

Because it has almost no surface area — a promise class, a barrier for joining multiple promises, and a handful of functional helpers — vine is easy to drop into any project that needs deferred-callback semantics without pulling in a full async framework. It remains a core dependency of Celery and kombu, where it underpins message acknowledgement and result callback handling.

What You Get

  • A promise class supporting .then() chaining, .throw() error propagation, and cancellation
  • A barrier primitive that resolves once multiple promises have completed
  • Functional helpers (wrap, transform, ppartial, preplace, starpromise) for composing callables into promises
  • Weak-reference support (weak=True) so promises don’t keep bound methods alive unnecessarily
  • Zero runtime dependencies and a tiny, auditable codebase (under 600 lines)

Common Use Cases

  • Implementing callback/errback chains for async I/O libraries without adopting a full event-loop framework
  • Joining multiple independent async operations with barrier before continuing
  • Building message-broker client libraries (as Celery and kombu do) that need to notify callers when a message is acknowledged or a result is ready
  • Wrapping synchronous callables so they can participate in a promise chain via wrap()

Under The Hood

Architecture — vine is organized around a single promise class (vine/promises.py) that tracks ready/failed/cancelled state and an internal pending-callback slot that upgrades from a single value (_svpending) to a deque (_lvpending) once more than one listener is attached, avoiding list allocation for the common single-callback case. then() attaches callbacks, throw()/throw1() propagate exceptions to on_error handlers, and barrier (vine/synchronization.py) composes multiple promises into one that fires once all have resolved. Thenable (vine/abstract.py) is an ABC that any promise-like object can register against via @Thenable.register, decoupling vine’s dispatch from a single concrete class.

Tech Stack — Pure Python 3 (also supports PyPy) with zero runtime dependencies; uses only stdlib (collections.deque, weakref.WeakMethod/ref, inspect). Packaging is classic setup.py/setup.cfg, versioned via bumpversion, tested with tox across CPython/PyPy targets, and Travis/AppVeyor CI configs remain in the repo alongside a .pre-commit-config.yaml.

Code Quality — The t/unit/ suite (test_promises.py, test_abstract.py, test_funtools.py, test_synchronization.py) exercises chaining, cancellation, error propagation, and weak-reference behavior with pytest, and .coveragerc indicates coverage is tracked in CI. The core module uses __slots__ on promise to keep memory overhead low, and the codebase is small enough (under 600 lines across 6 modules) to audit in full; naming and structure are consistent with Celery’s broader code style since this was extracted from Celery itself.

API Design — The public API is intentionally tiny: promise(), .then(), .throw(), .cancel(), barrier(), and a handful of functional helpers (wrap, transform, ppartial, preplace, starpromise). Chaining reads naturally (promise.then(callback, on_error=errback)), and the library imposes almost no boilerplate to adopt — a plain callable can be wrapped into a promise in one line. The tradeoff is a fairly manual, callback-style API rather than the await-based ergonomics of native asyncio, which is expected given vine predates widespread async/await adoption in the Celery ecosystem.

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