Crochet
Crochet is an MIT-licensed Python library that simplifies the integration of Twisted, an asynchronous networking framework, into regular blocking code. It transparently manages the Twisted reactor in a separate thread, allowing developers to call Twisted APIs from blocking applications like Django or Flask, or to create blocking APIs backed by Twisted. The library is currently at version 2.1.1 and is in a mature state, with development being slow due to its stable nature.
Common errors
-
RuntimeError: The Twisted reactor is not running, or has not been initialized by crochet.
cause `crochet.setup()` has not been called before attempting to use `@wait_for` or `EventualResult`.fixAdd `from crochet import setup; setup()` to the initialization section of your application. -
crochet.TimeoutError: Waited for 5.0 seconds
cause An operation decorated with `@wait_for(timeout=X)` exceeded the allowed X seconds, or the Twisted reactor got stuck.fixIncrease the `timeout` parameter in the `@wait_for` decorator if the operation legitimately takes longer, or debug the Twisted code to identify why it's not completing. -
ImportError: cannot import name 'wait_for' from 'crochet'
cause Attempting to import `wait_for` from a very old version of crochet, or a typo in the import statement.fixEnsure `crochet` is installed and updated to a recent version (`pip install --upgrade crochet`). The common import is `from crochet import wait_for`.
Warnings
- breaking Crochet version 2.1.0 dropped support for Python 3.6 and 3.7. Ensure your environment uses Python 3.8 or newer.
- gotcha The `crochet.setup()` function must be called exactly once before using any other Crochet functionality. Calling it multiple times is harmless, but not calling it at all will lead to runtime errors when attempting to use decorators or `EventualResult`.
- gotcha When using `@wait_for`, if the underlying Twisted operation does not complete within the specified `timeout` duration, a `crochet.TimeoutError` will be raised. This means the blocking call will be interrupted.
Install
-
pip install crochet
Imports
- setup
from crochet import setup
- wait_for
from crochet import wait_for
- run_in_reactor
from crochet import run_in_reactor
- TimeoutError
from crochet import TimeoutError
Quickstart
from crochet import setup, wait_for, TimeoutError
from twisted.internet import defer
import time
import logging
import os
# Configure basic logging to see Twisted output
logging.basicConfig(level=logging.INFO)
# Initialize crochet - this starts the Twisted reactor in a thread
setup()
@wait_for(timeout=5.0)
def long_running_twisted_task(duration):
d = defer.Deferred()
# Simulate an asynchronous operation in Twisted's reactor thread
def _complete_task():
if os.environ.get('SIMULATE_FAILURE') == '1':
d.err(ValueError("Simulated Twisted failure!"))
else:
d.callback(f"Task completed in {duration} seconds")
from twisted.internet import reactor
reactor.callLater(duration, _complete_task)
return d
if __name__ == "__main__":
print("Starting Crochet example...")
try:
# Call the Twisted-backed function from blocking code
result = long_running_twisted_task(2.0)
print(f"Blocking call returned: {result}")
# Demonstrate a timeout
print("\nAttempting a task that will timeout...")
try:
long_running_twisted_task(6.0) # Will timeout after 5 seconds
except TimeoutError:
print("Caught expected TimeoutError!")
# Demonstrate a Twisted error propagating
print("\nAttempting a task that will fail in Twisted...")
os.environ['SIMULATE_FAILURE'] = '1'
try:
long_running_twisted_task(1.0)
except ValueError as e:
print(f"Caught expected ValueError: {e}")
finally:
del os.environ['SIMULATE_FAILURE']
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
print("Crochet example finished.")