I have a function that makes a request to AWS using boto3
, and I wish to capture any exceptions and raise one of two custom errors, depending on the botocore.exceptions
exception that is returned. I thought I had this working, but an except
block is catching errors that are not listed for that block.
First and foremost, I want to return the custom AwsUnauthorizedException
for any SSO errors. This is fairly simple, and works as follows.
aws_unauthorized_exceptions = (botocore.exceptions.SSOError, botocore.exceptions.SSOTokenLoadError, botocore.exceptions.UnauthorizedSSOTokenError)
...
except aws_unauthorized_exceptions as e:
err_msg = str(e)
details = {'aws_error_message': err_msg, **req_msg}
raise AwsUnauthorizedException(**details) from None
However next I wish to return the custom AwsBadRequestException
for any other botocore.exceptions
exception. The trouble is, using Exception
means that every other exception is caught, rather than just other botocore.exceptions
exceptions, which isn't what I want to do at this point in my code.
So I'm using the inspect
module and creating a tuple containing all exceptions in botocore.exceptions
, except for those in aws_unauthorized_exceptions
.
for name, obj in inspect.getmembers(botocore.exceptions):
if inspect.isclass(obj) and obj not in aws_unauthorized_exceptions:
aws_bad_request_exceptions = aws_bad_request_exceptions (obj,)
...
except aws_bad_request_exceptions as e:
err_msg = e.response['Error']['Message']
details = {'aws_error_message': err_msg}
raise AwsBadRequestException(**details)
However, when I include both except
blocks with the block catching aws_bad_request_exceptions
first, it still catches exceptions from aws_unauthorized_exceptions
.
To be sure that the exception in question (botocore.exceptions.SSOTokenLoadError
in this example) was not in the tuple aws_bad_request_exceptions
I added the following line to the except
block.
printed(type(e) in aws_bad_request_exceptions)
This printed False
.
Can anyone suggest why I'm seeing this unexpected behaviour?
CodePudding user response:
All exceptions in botocore have a couple common superclasses: botocore.exceptions.BotoCoreError
and botocore.exceptions.ClientError
.
Your aws_bad_request_exceptions
tuple will end up including those superclasses, and since except clauses are matched in order, all BotoCore exceptions get matched.
Happily, exactly since botocore's errors have these superclasses, you don't need to construct that tuple at all; just catch the auth errors in a first except block, then every other boto error in another block (and other exceptions will not be caught).
import botocore.exceptions
try:
...
except (
botocore.exceptions.SSOError,
botocore.exceptions.SSOTokenLoadError,
botocore.exceptions.UnauthorizedSSOTokenError,
) as auth_err:
err_msg = str(auth_err)
details = {'aws_error_message': err_msg, **req_msg}
raise AwsUnauthorizedException(**details) from None
except (
botocore.exceptions.BotoCoreError,
botocore.exceptions.ClientError,
) as boto_err:
...