我试图弄清楚如何使用boto3进行正确的错误处理。

我正在尝试创建一个IAM用户:

def create_user(username, iam_conn):
    try:
        user = iam_conn.create_user(UserName=username)
        return user
    except Exception as e:
        return e

当调用create_user成功时,我得到一个整洁的对象,其中包含API调用的http状态代码和新创建用户的数据。

例子:

{'ResponseMetadata': 
      {'HTTPStatusCode': 200, 
       'RequestId': 'omitted'
      },
 u'User': {u'Arn': 'arn:aws:iam::omitted:user/omitted',
           u'CreateDate': datetime.datetime(2015, 10, 11, 17, 13, 5, 882000, tzinfo=tzutc()),
           u'Path': '/',
           u'UserId': 'omitted',
           u'UserName': 'omitted'
          }
}

这很有效。但是当这个失败时(比如如果用户已经存在),我只得到一个botocore.exceptions.ClientError类型的对象,其中只有文本告诉我哪里出错了。

例子: ClientError('调用CreateUser操作时发生错误(EntityAlreadyExists):省略名称的用户已经存在。')

这(AFAIK)使得错误处理非常困难,因为我不能只是打开结果的http状态代码(409用户已经存在根据AWS API文档的IAM)。这让我觉得我一定是做错了什么。最优的方法是boto3永远不抛出异常,但juts总是返回一个反映API调用如何进行的对象。

有没有人能在这个问题上给我一些启发,或者给我指出正确的方向?


当前回答

只是更新了@jarmod指出的“资源上没有例外”问题(如果下面似乎适用,请随时更新您的答案)

我已经测试了下面的代码,它运行良好。它使用“资源”来做事情,但捕获客户端。例外-尽管它“看起来”有点错误…它测试得很好,在异常时使用调试器查看异常类时显示和匹配……

它可能不适用于所有资源和客户端,但适用于数据文件夹(又名s3桶)。

lab_session = boto3.Session() 
c = lab_session.client('s3') #this client is only for exception catching

try:
    b = s3.Bucket(bucket)
    b.delete()
except c.exceptions.NoSuchBucket as e:
    #ignoring no such bucket exceptions
    logger.debug("Failed deleting bucket. Continuing. {}".format(e))
except Exception as e:
    #logging all the others as warning
    logger.warning("Failed deleting bucket. Continuing. {}".format(e))

希望这对你有所帮助……

其他回答

只是更新了@jarmod指出的“资源上没有例外”问题(如果下面似乎适用,请随时更新您的答案)

我已经测试了下面的代码,它运行良好。它使用“资源”来做事情,但捕获客户端。例外-尽管它“看起来”有点错误…它测试得很好,在异常时使用调试器查看异常类时显示和匹配……

它可能不适用于所有资源和客户端,但适用于数据文件夹(又名s3桶)。

lab_session = boto3.Session() 
c = lab_session.client('s3') #this client is only for exception catching

try:
    b = s3.Bucket(bucket)
    b.delete()
except c.exceptions.NoSuchBucket as e:
    #ignoring no such bucket exceptions
    logger.debug("Failed deleting bucket. Continuing. {}".format(e))
except Exception as e:
    #logging all the others as warning
    logger.warning("Failed deleting bucket. Continuing. {}".format(e))

希望这对你有所帮助……

只需要一个导入。 不需要if语句。 按预期使用客户端内置异常。

Ex:

from boto3 import client

cli = client('iam')
try:
    cli.create_user(
        UserName = 'Brian'
    )
except cli.exceptions.EntityAlreadyExistsException:
    pass

CloudWatch示例:

cli = client('logs')
try:
    cli.create_log_group(
        logGroupName = 'MyLogGroup'
    )
except cli.exceptions.ResourceAlreadyExistsException:
    pass

使用异常中包含的响应。这里有一个例子:

import boto3
from botocore.exceptions import ClientError

try:
    iam = boto3.client('iam')
    user = iam.create_user(UserName='fred')
    print("Created user: %s" % user)
except ClientError as e:
    if e.response['Error']['Code'] == 'EntityAlreadyExists':
        print("User already exists")
    else:
        print("Unexpected error: %s" % e)

异常中的响应字典将包含以下内容:

(“错误”)(“代码”)。'EntityAlreadyExists'或'ValidationError' [' responsemetdata ']['HTTPStatusCode']例:400 [“ResponseMetadata”][' RequestId ']。“d2b06652 - 88 - d7 - 11 - e5 - 99 - d0 - 812348583 - a35” (“错误”)(“信息”)。"发生错误(EntityAlreadyExists)…" ['错误']['类型']。“发送”

有关更多信息,请参阅:

Boto3错误处理 Botocore错误处理

(更新:2018-03-07)

AWS Python SDK已经开始公开客户端上的服务异常(虽然不是资源上的异常),你可以显式地捕获这些异常,所以现在可以像这样编写代码:

import botocore
import boto3

try:
    iam = boto3.client('iam')
    user = iam.create_user(UserName='fred')
    print("Created user: %s" % user)
except iam.exceptions.EntityAlreadyExistsException:
    print("User already exists")
except botocore.exceptions.ParamValidationError as e:
    print("Parameter validation error: %s" % e)
except botocore.exceptions.ClientError as e:
    print("Unexpected error: %s" % e)

不幸的是,目前没有关于这些错误/异常的文档,但你可以得到一个核心错误列表,如下所示:

import botocore
import boto3
[e for e in dir(botocore.exceptions) if e.endswith('Error')]

注意,必须同时导入botocore和boto3。如果你只导入botocore,你会发现botocore没有名为exceptions的属性。这是因为异常被boto3动态地填充到botocore中。

您可以获得以下特定于服务的异常列表(根据需要将iam替换为相关的服务):

import boto3
iam = boto3.client('iam')
[e for e in dir(iam.exceptions) if e.endswith('Exception')]

(更新:2021-09-07)

除了前面提到的客户端异常方法之外,还有一个名为aws-error-utils的第三方帮助包。

如果你不得不处理不友好的日志客户端(CloudWatch logs put-log-events),这是我必须做的,以正确捕获Boto3客户端异常:

try:
    ### Boto3 client code here...

except boto_exceptions.ClientError as error:
    Log.warning("Catched client error code %s",
                error.response['Error']['Code'])

    if error.response['Error']['Code'] in ["DataAlreadyAcceptedException",
                                           "InvalidSequenceTokenException"]:
        Log.debug(
            "Fetching sequence_token from boto error response['Error']['Message'] %s",
            error.response["Error"]["Message"])
        # NOTE: apparently there's no sequenceToken attribute in the response so we have
        # to parse response["Error"]["Message"] string
        sequence_token = error.response["Error"]["Message"].split(":")[-1].strip(" ")
        Log.debug("Setting sequence_token to %s", sequence_token)

这在第一次尝试(空LogStream)和后续尝试时都有效。

跟随@armod关于在客户端对象上添加异常的更新。我将展示如何查看为客户端类定义的所有异常。

异常是在使用session.create_client()或boto3.client()创建客户端时动态生成的。它在内部调用方法botocore.errorfactory.ClientExceptionsFactory._create_client_exceptions()并填充客户端。带有构造异常类的异常字段。

所有的类名都在client.exceptions中可用。_code_to_exception字典,所以你可以用下面的代码段列出所有类型:

client = boto3.client('s3')

for ex_code in client.exceptions._code_to_exception:
    print(ex_code)

希望能有所帮助。