Back to results for “Exception Handling”
Python › Exception Handling

How would you write a context manager using @contextlib.contextmanager that both sets up a resource AND properly handles/logs any exception that occurs while it's in use?

Advanced

Answer

Wrap the yield in a try/except/finally: the try/yield gives control to the 'with' block's body, an except clause can inspect and optionally re-raise (or transform) any exception that occurred inside that body, and finally handles guaranteed cleanup regardless of the outcome.
from contextlib import contextmanager
import logging

@contextmanager
def managed_transaction(db):
    transaction = db.begin()
    try:
        yield transaction
        transaction.commit()
    except Exception:
        transaction.rollback()
        logging.exception("Transaction failed, rolled back")
        raise
    finally:
        transaction.close()
Real-world example Building a database transaction context manager that automatically commits on success, rolls back and logs on failure, and always cleans up.

Common follow-ups: Why does the 'except' block here re-raise the exception after rolling back, rather than swallowing it?