Skip to content

Improve Typing and Error Handling in on_exception #194

Open
@davidslater

Description

@davidslater

Currently, on_exception takes an argument exception: _MaybeSequence[Type[Exception]].

However, this cannot handle any Sequence of Type[Exception]. For instance, if a list[Type[Exception]] is given, as in the following code:

import backoff

i: int = 0
@backoff.on_exception(backoff.expo, [ValueError])
def _retry():
    global i
    i += 1
    print(f"i = {i}")
    if i < 3:
        raise ValueError(f"failure {i}")
    if i == 3:
        raise RuntimeError("runtime error")

    return "success"

_retry()

then a hard-to-understand stack trace is generated:

i = 1
Traceback (most recent call last):
  File "/Users/davidslater/git/litl/backoff/backoff/_sync.py", line 107, in retry
    ret = target(*args, **kwargs)
  File "/Users/davidslater/git/litl/backoff/script.py", line 10, in _retry
    raise ValueError(f"failure {i}")
ValueError: failure 1

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/davidslater/git/litl/backoff/script.py", line 16, in <module>
    _retry()
  File "/Users/davidslater/git/litl/backoff/backoff/_sync.py", line 108, in retry
    except exception as e:
TypeError: catching classes that do not inherit from BaseException is not allowed

Similar issues can also arise with the same traceback, such as:

@backoff.on_exception(backoff.expo, ValueError())

which are hard to understand and debug, as there are no lines between the function call in user code and the except exception as e in the library.

I see two major different ways to improve this:
A) modify the type information. If done directly, this would change the type to Union[Type[Exception], Tuple[Type[Exception]]],
Alternatively, you could add to _typing.py:

_MaybeTuple = Union[T, Tuple[T]]

and then change the type to _MaybeTuple[Type[Exception]].

B) Do checking of exception when it is given to the function to improve error response. Essentially, just check if it is an Exception or a tuple of exception types and raise a ValueError if not.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions