Quick Start¶
This page walks through the most common errortools idioms end-to-end. Every example is runnable as-is — copy the snippets into a Python file or a REPL and they will work without further setup.
See also
Installation — install errortools in your environment.
Core Features — a deeper tour of every feature shown here.
API Reference — complete API reference.
A 30-second tour¶
from errortools import ignore, retry, BaseErrorCodes
from errortools.logging import logger
# 1. Suppress an exception, then introspect it
with ignore(KeyError) as err:
_ = {}["missing"]
print(err.exception) # KeyError('missing')
# 2. Retry a flaky operation
@retry(times=3, on=ConnectionError, delay=1.0)
def connect(host: str): ...
# 3. Raise a structured exception
raise BaseErrorCodes.not_found("user #42") # NotFoundError [3001]
# 4. Structured logging
logger.info("Server started on port {}", 8080)
Suppressing exceptions¶
With metadata — ignore()¶
ignore() is a context manager that swallows
the exceptions you list while keeping a full record of what happened.
Bind the result to a name with as to read the metadata after the
block exits.
from errortools import ignore
with ignore(KeyError) as err:
_ = {}["missing"]
if err.be_ignore:
print(f"Suppressed {err.name}: {err.exception}")
print(f"Traceback:\n{err.traceback}")
Attribute |
Description |
|---|---|
|
|
|
Class name of the suppressed exception ( |
|
Number of exceptions suppressed in the block. |
|
The original exception instance, or |
|
Pre-formatted traceback string, or |
Without metadata — fast_ignore()¶
When you don’t need any of the above metadata, use
fast_ignore(). It’s a thin wrapper around
contextlib.suppress() and adds essentially no overhead.
from errortools import fast_ignore
with fast_ignore(KeyError, IndexError):
_ = [][0] # suppressed, minimal overhead
By base class — ignore_subclass()¶
ignore_subclass() matches every subclass of
the type you pass. This is the most expressive form: “ignore anything
that derives from X”.
from errortools import ignore_subclass
with ignore_subclass(LookupError):
raise IndexError("out of range") # IndexError ⊆ LookupError
# IndexError is caught and discarded
Warnings — ignore_warns()¶
ignore_warns() mirrors
warnings.catch_warnings() for the common case of suppressing
specific categories.
from errortools import ignore_warns
with ignore_warns(DeprecationWarning):
# Deprecated API call that would otherwise warn
legacy_api()
See also
See Exception Handling for the full guide,
including the “subclass vs. tuple” rule and the
errortools.future zero-overhead variants.
Retrying and timing out¶
Automatic retry — retry()¶
retry() retries a callable on the
configured exception, with an optional delay between attempts.
from errortools import retry
@retry(times=3, on=ConnectionError, delay=1.0)
def connect(host: str):
# Will retry up to 3 times on ConnectionError
...
Async timeout — timeout()¶
timeout() cancels a coroutine
after the given deadline. It requires an active event loop.
from errortools import timeout
@timeout(5.0)
async def fetch_data(url: str):
# Raises asyncio.TimeoutError after 5 seconds
...
Defining custom exceptions¶
With error codes — PureBaseException¶
Subclass PureBaseException to attach a
numeric error code and a default message. The code is rendered in
the exception’s __str__ for easy log greppability.
from errortools import PureBaseException
class AppError(PureBaseException):
code = 9000
default_detail = "Application error"
raise AppError() # [9000] Application error
raise AppError("disk full") # [9000] disk full
With rich context — ContextException¶
ContextException adds a trace ID, a free
form context dict, and a chain of contextual events.
from errortools import ContextException
raise (
ContextException("user not found")
.with_context(request_id="abc-123", user_id=42)
.with_cause(KeyError("user"))
)
Predefined codes — BaseErrorCodes¶
For the most common cases, BaseErrorCodes
ships ready-made factories so you don’t have to subclass anything.
from errortools import BaseErrorCodes
raise BaseErrorCodes.not_found("user #42") # [3001] user #42
raise BaseErrorCodes.invalid_input("username too short")
raise BaseErrorCodes.access_denied()
See also
See Custom Exceptions for the complete taxonomy of codes, the error-class hierarchy, and chaining examples.
Structured logging¶
errortools.logging is a Loguru-inspired logger that ships with
the package — no extra install required.
from errortools.logging import logger
logger.info("Server started on port {}", 8080)
logger.warning("Disk at {pct:.1f}%", pct=92.5)
logger.success("All systems operational")
# Add a rotating file sink
logger.add("app.log", rotation=10_000_000, retention=5)
# Bind a context that propagates to every log call
req_log = logger.bind(request_id="abc-123")
req_log.info("Request received")
See also
See Logging for sinks, levels, formatting, and
the integration with the standard-library logging module.
Where to go next¶
Core Features — detailed tour of every feature above.
Examples — runnable, end-to-end examples.
API Reference — the complete API reference.