A lightweight Python exception handling utility library.
pip install errortools- Suppress:
ignore(),super_fast_ignore(),@suppress()— silence exceptions gracefully - Retry & Timeout:
@retry(),@timeout()— auto retry with delay, async timeout - Raise & Convert:
raises(),reraise(),@convert()— batch raise, type conversion - Catch & Collect:
super_fast_catch(),ExceptionCollector— inspect or batch exceptions - Caching:
@error_cache— LRU exception cache, likefunctools.lru_cache - Custom Exceptions:
PureBaseException,ContextException,BaseErrorCodes - Logging: structured logger with sinks, context binding, and exception capture
from errortools import ignore, retry, reraise, error_cache, suppress, convert
from errortools.future import super_fast_ignore, super_fast_catch, ExceptionCollector
# ── Suppress ─────────────────────────────────────────────────
with ignore(KeyError) as err: # full metadata
_ = {}["missing"]
# err.be_ignore=True, err.name='KeyError', err.traceback=...
with super_fast_ignore(ValueError): # zero-overhead
int("bad")
@suppress(ZeroDivisionError, default=0) # decorator form
def divide(a, b): return a / b
# ── Retry ────────────────────────────────────────────────────
@retry(times=3, on=ConnectionError, delay=1.0)
def connect(host: str): ...
# ── Convert ──────────────────────────────────────────────────
@convert(KeyError, ValueError) # decorator
def lookup(d, key): return d[key]
with reraise(KeyError, ValueError): # context manager
raise KeyError("x") # → ValueError
# ── Catch & Collect ──────────────────────────────────────────
with super_fast_catch(ValueError) as ctx:
raise ValueError("oops")
# ctx.exception → ValueError('oops')
collector = ExceptionCollector()
collector.catch(int, "bad1")
collector.catch(int, "bad2")
collector.raise_all() # → ExceptionGroup
# ── Cache ────────────────────────────────────────────────────
@error_cache(maxsize=64)
def load(uid: int):
if uid < 0: raise ValueError(f"invalid: {uid}")
return {"id": uid}from errortools import PureBaseException, ContextException, BaseErrorCodes
class AppError(PureBaseException):
code = 9000
default_detail = "Application error."
err = ContextException("failed").with_context(service="db")
raise BaseErrorCodes.not_found("user #42") # NotFoundError [3001]from errortools.logging import logger
logger.info("Server started on port {}", 8080)
logger.add("app.log", rotation=10_485_760, retention=5)
with logger.catch():
int("not a number") # logged + suppressed