botocore icon indicating copy to clipboard operation
botocore copied to clipboard

Copying WaiterError causes a TypeError

Open iainelder opened this issue 3 years ago • 4 comments

Describe the bug

WaiterError causes a TypeError when you try to copy it.

Steps to reproduce

In [1]: from botocore.exceptions import WaiterError

In [2]: error = WaiterError(
   ...:     name="FakeWaiter", reason="FakeReason", last_response="FakeResponse"
   ...: )

In [3]: from copy import copy

In [4]: copy(error)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [4], in <module>
----> 1 copy(error)

File /usr/lib/python3.8/copy.py:102, in copy(x)
    100 if isinstance(rv, str):
    101     return x
--> 102 return _reconstruct(x, None, *rv)

File /usr/lib/python3.8/copy.py:264, in _reconstruct(x, memo, func, args, state, listiter, dictiter, deepcopy)
    262 if deep and args:
    263     args = (deepcopy(arg, memo) for arg in args)
--> 264 y = func(*args)
    265 if deep:
    266     memo[id(x)] = y

File ~/.cache/pypoetry/virtualenvs/bp-1082-udpate-apt-002-product-kAdUhv53-py3.8/lib/python3.8/site-packages/botocore/exceptions.py:28, in _exception_from_packed_args(exception_cls, args, kwargs)
     26 if kwargs is None:
     27     kwargs = {}
---> 28 return exception_cls(*args, **kwargs)

TypeError: __init__() missing 1 required positional argument: 'last_response'

Expected behavior

That a copy of the WaiterError instance is created.

Additional context

This bug makes it more difficult to work with the botocove library to query multiple AWS accounts in the organization. Botocove copies the output, including the exceptions, before returning the final result to the client. See botocove issue #26.

The ClientError class is copyable because it implements the __reduce__ method.

https://github.com/boto/botocore/blob/a692f50213f4480f5fdf8faf30b87ad362bf0519/botocore/exceptions.py#L482-L486

To be copyable the WaiterError class needs also to implement the __reduce__ method to match its __init__ method.

https://github.com/boto/botocore/blob/a692f50213f4480f5fdf8faf30b87ad362bf0519/botocore/exceptions.py#L414-L420

iainelder avatar Feb 11 '22 17:02 iainelder

Hi @iainelder,

Thanks for the report. We'll take a look to see what the best solution is to make this exception copyable.

kdaily avatar Feb 14 '22 17:02 kdaily

This might overlap somewhat with https://github.com/boto/boto3/issues/1221

tim-finnigan avatar Nov 23 '22 20:11 tim-finnigan

Is there a reason why the below function can't be added to the WaiterError class?

def __reduce__(self):
    return _exception_from_packed_args, (
        self.__class__,
        (self.kwargs["name"], self.kwargs["reason"], self.last_response),
        {},
    )

becaue my code is now outputing the below text and I have no clue where it came from because it's an asynchronous error

Exception in thread Thread-3 (_handle_results): Traceback (most recent call last): File "/usr/local/lib/python3.11/threading.py", line 1038, in _bootstrap_inner self.run() File "/usr/local/lib/python3.11/threading.py", line 975, in run self._target(*self._args, **self._kwargs) File "/usr/local/lib/python3.11/multiprocessing/pool.py", line 579, in _handle_results task = get() ^^^^^ File "/usr/local/lib/python3.11/multiprocessing/connection.py", line 250, in recv return _ForkingPickler.loads(buf.getbuffer()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/botocore/exceptions.py", line 28, in _exception_from_packed_args return exception_cls(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: WaiterError.init() missing 1 required positional argument: 'last_response'

hb2638 avatar Jun 15 '23 14:06 hb2638

One workaround is patching it

import botocore.exceptions
def wait_error_reduce(wait_error: botocore.exceptions.WaiterError) -> botocore.exceptions.WaiterError:
    return botocore.exceptions._exception_from_packed_args, (
        wait_error.__class__,
        (wait_error.kwargs["name"], wait_error.kwargs["reason"], wait_error.last_response),
        {},
    )
botocore.exceptions.WaiterError.__reduce__ = wait_error_reduce

hb2638 avatar Jun 15 '23 14:06 hb2638