Exception handling

Satella provides a rich functionality to register exception hooks.

Note

Satella does not install a custom faulthandler. Do it yourself.

Writing your own exception handlers

To write your own exception handlers, subclass the following class:

And then instantiate it and call install().

If you got a callable of signature [type, BaseException, types.TracebackType] (type, value, traceback) that returns True upon a request to swallow the exception, you can convert it to a Satella exception handler in two ways.

First:

a = FunctionExceptionHandler(exception_handle)
a.install()

Or

@exception_handler
def exception_handle(type, value, traceback) -> bool
    ...

exception_handle().install()
satella.exception_handling.exception_handler(priority: int = 0)

Convert a callable to an FunctionExceptionHandler. Usage

>>> @exception_handler(priority=-10)
>>> def handle_exc(type_, val, traceback):
>>>     ...

You can use also:

>>> @exception_handler
>>> def handle_exc(type_, val, traceback):
>>>     ...

The default priority is 0. But this way of calling it is not recommended, and will result in a UserWarning.

Returns:

ExceptionHandler instance

class satella.exception_handling.FunctionExceptionHandler(fun: Callable[[type, BaseException, TracebackType], Sequence[bool] | bool], priority: int = 0)

A exception handler to make callables of given signature into Satella’s exception handlers.

Your exception handler must return a bool, whether to intercept the exception and not propagate it.

handle_exception(type_, value, traceback)

Return True to intercept the exception, so that it won’t be propagated to other handlers.

Pre-defined exception handlers

MemoryErrorExceptionHandler

class satella.exception_handling.MemoryErrorExceptionHandler(custom_hook: ~typing.Callable[[type, BaseException, ~types.TracebackType], ~typing.Sequence[bool] | bool] = <function MemoryErrorExceptionHandler.<lambda>>, kill_pg: bool = False)

A handler that terminates the entire process (or process group) is a MemoryError is seen.

custom_hook is an exception callable to implement you own behavior. If it returns True, then MemoryErrorExceptionHandler won’t kill anyone. You can also provide a CallableGroup with gather=True - if any of callables returns True, the process won’t be killed.

Parameters:

kill_pg – whether to kill entire process group, if applicable

This exception hook kills the entire process if a MemoryError is spotted, under the rule that it’s better to fail early than admit undefined behaviour.

DumpToFileHandler

class satella.exception_handling.DumpToFileHandler(human_readables: Iterable[str | TextIO | Logger | Tuple[Logger, int]], trace_pickles: Iterable[str | BinaryIO] | None = None)

Write the stack trace to a stream-file.

Note that your file-like objects you throw into that must support only .write() and optionally .flush()

Parameters:
  • human_readables – iterable of either a file-like objects, or paths where human-readable files will be output. Also a logger can be put here, or a tuple of logger, logging level. Default logging level will be ERROR.

  • trace_pickles – iterable of either a file-like objects, or paths where pickles with stack status will be output

Raises:

TypeError – invalid stream

A handler that will dump each stack frame of the exception, along with it’s variables, to a file (or stdout/stderr). Two file handles/names are admitted:

  • human_readables - where human-readable form of the exception and it’s values will be output

  • trace_pickles - where pickled `Traceback`s from the exception will be put.

You can throw there either:

  • a str - file of given name will be created and data will be output to it

  • a file-like object supporting write() (and optionally flush()) - data will be output to it

  • a None - output will be piped to /dev/null

Note that the arguments are lists, so you can specify multiple target sources.