pnpnpn / timeout-decorator

Timeout decorator for Python
MIT License
620 stars 96 forks source link

Error when specifying a different exception type with an exception message. #54

Closed tlalexander closed 5 years ago

tlalexander commented 5 years ago

https://github.com/pnpnpn/timeout-decorator/blob/3ad0308d30c4904b9ea272da326c0c3795161378/timeout_decorator/timeout_decorator.py#L47

As far as I can tell, this decorator does not work when passing a normal exception (RuntimeError, IOError, or base Exception) and an exception message. This occurs because the base exception class and the others I mentioned do not accept the 'value' argument. Instead, trying to call a RuntimeError with the value keyword throws a TypeError exception.

See below.

Python 2.7.13 (default, Nov 24 2017, 17:33:09)

raise Exception(value='My Message.') Traceback (most recent call last): File "", line 1, in TypeError: exceptions.Exception does not take keyword arguments

I will try to submit a pull request, but note that I believe a one line change solves this.

Change raise exception(value=exception_message) to raise exception(exception_message)

This works with the builtin TimeoutError class as well, where the value keyword was added, since TimeoutError only has one keyword argument.

tlalexander commented 5 years ago

Pull request created!

minherz commented 1 year ago

A similar issue happens when an exception is raised using a customized constructor (e.g.):

class RegexSyntaxError(Exception):

  def __init__(self, exp, msg):
    super(RegexSyntaxError, self).__init__()
    self.msg = 'Invalid expression "{}": {}'.format(exp, msg)

When such an exception is raised in the decorated method (via raise RegexSyntaxError('-1+1', 'wrong syntax')) the following error is reported:

File "/third_party/py/timeout_decorator/timeout_decorator/timeout_decorator.py", line 152, in __call__
    return self.value
  File "third_party/py/timeout_decorator/timeout_decorator/timeout_decorator.py", line 172, in value
    flag, load = self.__queue.get()
  File "<embedded stdlib>/multiprocessing/queues.py", line 122, in get
    return _ForkingPickler.loads(res)
TypeError: __init__() missing 2 required positional arguments: 'exp' and 'msg'

The decorator's sources are stored in the private repo in the path /third_party/py, hence the callstack.

In other words, it is impossible to raise an exception with a custom list of arguments from within the decorated method.