A lightweight Python exception handling utility library.
Code Style: Google PyPI Version Python Versions This week commits This month commits Past year commits Total commits badge OS support
pip install errortools
uv add 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