Python异常捕获问题:except块捕获未声明的botocore SSO异常
问题原因分析
出现这种不符合预期的行为,核心原因是Python异常捕获的继承匹配规则:当except块指定异常类元组时,Python会检查抛出的异常实例是否是元组中任意类的子类实例(包括直接或间接继承),而非严格等于元组中的类。
你的aws_bad_request_exceptions元组里,大概率包含了SSOTokenLoadError等SSO相关异常的父类(比如botocore.exceptions.ClientError或BotoCoreError这类通用基类)。虽然type(e)(即SSOTokenLoadError本身)不在该元组中,但它的父类在元组内,因此当这个except块放在前面时,会优先捕获该异常。
举个极简示例验证这个逻辑:
class BaseError(Exception): pass class SSOError(BaseError): pass try: raise SSOError() except (BaseError,) as e: print("捕获到了BaseError的子类") # 会执行这行代码
解决方案
有两种可行的修复方式,推荐优先使用第一种:
方式一:调整异常捕获顺序(推荐)
遵循Python异常处理的最佳实践:先捕获具体异常,再捕获通用异常。不需要用inspect收集所有异常,直接捕获botocore所有异常的基类BotoCoreError,并将SSO异常的捕获块放在前面:
import botocore.exceptions aws_unauthorized_exceptions = ( botocore.exceptions.SSOError, botocore.exceptions.SSOTokenLoadError, botocore.exceptions.UnauthorizedSSOTokenError ) try: # 你的AWS接口调用代码 ... except aws_unauthorized_exceptions as e: err_msg = str(e) details = {'aws_error_message': err_msg, **req_msg} raise AwsUnauthorizedException(**details) from None except botocore.exceptions.BotoCoreError as e: # 处理所有非SSO的botocore异常 err_msg = e.response['Error']['Message'] details = {'aws_error_message': err_msg} raise AwsBadRequestException(**details)
这种方式简洁且维护成本低,完全符合你的需求。
方式二:精确过滤异常类(不推荐)
如果坚持要收集除SSO外的所有botocore异常,需要确保元组中不包含SSO异常的任何父类或子类。可以通过检查类的继承链来过滤:
import inspect import botocore.exceptions aws_unauthorized_exceptions = ( botocore.exceptions.SSOError, botocore.exceptions.SSOTokenLoadError, botocore.exceptions.UnauthorizedSSOTokenError ) aws_bad_request_exceptions = tuple() for name, obj in inspect.getmembers(botocore.exceptions): if inspect.isclass(obj): # 排除所有与SSO异常有继承关系的类 is_sso_related = False for sso_exc in aws_unauthorized_exceptions: if issubclass(obj, sso_exc) or issubclass(sso_exc, obj): is_sso_related = True break if not is_sso_related: aws_bad_request_exceptions += (obj,)
但这种方式的问题在于,botocore的异常类结构可能随版本变化,后续维护成本极高,因此不推荐使用。
内容的提问来源于stack exchange,提问作者David Gard
相关产品推荐
相关产品推荐

