vine

Lightweight Python promise implementation powering Celery's async callback chains

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

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
71 /100 Good
Development Activity 76
Maintenance 52
Community 76
Maturity 60
Momentum 20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
75 /100 Good
Architecture 70
Code Quality 78
Innovation 68
Learning Curve 82

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