Exceptions and Context
Error handling and resource lifecycle with exceptions and context managers. Results appear in the same fence: same-line # when short, multiline # blocks below the sample when not.
Search across all documentation pages
Error handling and resource lifecycle with exceptions and context managers. Results appear in the same fence: same-line # when short, multiline # blocks below the sample when not.
else runs when no exception occurred - useful for success-only code.
try:
data = {"ok": True}
except OSError:
data = None
else:
data = data["ok"] # True
data # TrueChain exceptions to preserve the underlying cause.
try:
int("x")
except ValueError as e:
err = ValueError("bad config")
err.__cause__ = e
type(err.__cause__) # <class 'ValueError'>Handle multiple errors together (3.11+) with except*.
try:
raise ExceptionGroup("eg", [ValueError("a"), TypeError("b")])
except* ValueError as eg:
[type(e).__name__ for e in eg.exceptions] # ['ValueError']Build context managers from generators with a decorator.
from contextlib import contextmanager
@contextmanager
def tag(name: str):
yield f"<{name}>"
with tag("x") as t:
t # '<x>'Ignore expected exception types in a block.
from contextlib import suppress
from pathlib import Path
with suppress(FileNotFoundError):
Path("/no/such/file").unlink() # no raise
"ok" # 'ok'finally runs on success and failure - close resources here if not using with.
steps = []
try:
steps.append("body")
finally:
steps.append("finally")
steps # ['body', 'finally']Order except clauses from specific to broad.
def classify(e: Exception) -> str:
try:
raise e
except FileNotFoundError:
return "missing"
except OSError:
return "os"
classify(FileNotFoundError()) # 'missing'
classify(TimeoutError()) # 'os' (TimeoutError is OSError)Domain exceptions carry stable names for callers.
class NotFoundError(Exception):
def __init__(self, id: str) -> None:
super().__init__(f"not found: {id}")
self.id = id
e = NotFoundError("42")
e.id, str(e) # ('42', 'not found: 42')Assertions document internal invariants - not for user input validation in production.
idx = 0
assert idx >= 0, "index must be non-negative" # passes
# assert -1 >= 0 # AssertionErrorEnter a variable number of context managers safely.
from contextlib import ExitStack, nullcontext
with ExitStack() as stack:
a = stack.enter_context(nullcontext("A"))
b = stack.enter_context(nullcontext("B"))
(a, b) # ('A', 'B')Format exceptions for logs without re-raising.
import traceback
try:
1 / 0
except ZeroDivisionError:
text = traceback.format_exc()
"ZeroDivisionError" in text # TrueAdd notes to exceptions (3.11+) for extra context.
e = ValueError("bad")
e.add_note("while parsing user input")
e.__notes__ # ['while parsing user input']Use bare raise inside except to rethrow the active exception.
def boom():
try:
raise RuntimeError("x")
except RuntimeError:
flag = True
raise
try:
boom()
except RuntimeError as e:
str(e) # 'x'Adapt .close() objects into context managers.
from contextlib import closing
class S:
def close(self): self.done = True
s = S()
with closing(s):
pass
s.done # Truelogger.exception includes the stack in the current except block.
import logging, io
log = logging.getLogger("demo")
buf = io.StringIO()
h = logging.StreamHandler(buf)
log.addHandler(h); log.setLevel(logging.ERROR)
try:
1 / 0
except ZeroDivisionError:
log.exception("work failed")
"ZeroDivisionError" in buf.getvalue() # TrueStack versions: Python 3.14.0 (stable 3.14, maintenance 3.13) · uv 0.6+ · ruff 0.9+
Reviewed by Chris St. John·Last updated Jul 31, 2026