Estoy tratando de imaginar cómo hacer un manejo adecuado de errores con boto3.
Estoy tratando de crear un usuario de IAM:
def create_user(username, iam_conn):
try:
user = iam_conn.create_user(UserName=username)
return user
except Exception as e:
return e
Cuando la llamada a create_user tiene éxito, obtengo un objeto ordenado que contiene el código de estado http de la llamada API y los datos del usuario recién creado.
Ejemplo:
{'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'
}
}
Esto funciona muy bien. Pero cuando esto falla (como si el usuario ya existe), solo obtengo un objeto de tipo botocore.exceptions.ClientError con solo texto para decirme qué salió mal.
Ejemplo: ClientError ('Se produjo un error (EntityAlreadyExists) al llamar a la operación CreateUser: el usuario con el nombre omitido ya existe.')
Esto (AFAIK) hace que el manejo de errores sea muy difícil porque no puedo simplemente activar el código de estado http resultante (409 para el usuario ya existe de acuerdo con los documentos de la API de AWS para IAM). Esto me hace pensar que debo estar haciendo algo de manera incorrecta. La forma óptima sería que boto3 nunca arroje excepciones, pero los juts siempre devuelven un objeto que refleje cómo fue la llamada API.
¿Alguien puede aclararme sobre este tema o señalarme en la dirección correcta?
Respuestas:
Use la respuesta contenida dentro de la excepción. Aquí hay un ejemplo:
La respuesta dict en la excepción contendrá lo siguiente:
['Error']['Code']
por ejemplo, 'EntityAlreadyExists' o 'ValidationError'['ResponseMetadata']['HTTPStatusCode']
por ejemplo 400['ResponseMetadata']['RequestId']
por ejemplo, 'd2b06652-88d7-11e5-99d0-812348583a35'['Error']['Message']
por ejemplo, "se produjo un error (EntityAlreadyExists) ..."['Error']['Type']
por ejemplo, "remitente"Para obtener más información, consulte el manejo de errores de botocore .
[Actualizado: 2018-03-07]
AWS Python SDK ha comenzado a exponer excepciones de servicio en clientes (aunque no en recursos ) que puede capturar explícitamente, por lo que ahora es posible escribir ese código de la siguiente manera:
Desafortunadamente, actualmente no hay documentación para estas excepciones.
fuente
200
en su cheque, ya que el código de retorno podría ser un2xx
código de estado HTTP diferente (por ejemplo,204
al eliminar una bóveda o archivo,201
al crear, etc.). En el mejor de los casos, se debe buscar un código que no sea 4xx (p. Ej.statusCode < 400
) , Pero es realmente frágil y no lo recomendaría de todos modos: lo mejor es confiar enboto
arrojar excepciones a su código.Me pareció muy útil, ya que las excepciones no están documentadas, para enumerar todas las excepciones en la pantalla para este paquete. Aquí está el código que solía hacerlo:
Lo que resulta en:
fuente
Solo una actualización del problema 'sin excepciones en los recursos' como lo señaló @jarmod (no dude en actualizar su respuesta si a continuación parece aplicable)
He probado el siguiente código y funciona bien. Utiliza 'recursos' para hacer cosas, pero atrapa el
client.exceptions
- aunque 'se ve' algo mal ... prueba bien, las clases de excepción se muestran y coinciden cuando se considera el uso del depurador en el momento de la excepción ...Puede que no sea aplicable a todos los recursos y clientes, pero funciona para carpetas de datos (también conocidos como buckets s3).
Espero que esto ayude...
fuente
s3.meta.client.exceptions.NoSuchBucket
s3
es el recurso de servicio, por ejemplos3 = boto3.resource('s3')
. Funciona también para los recursos reales, como los cubos:boto3.resource('s3').Bucket('bucket-name').meta.client.exceptions. ...
Como algunos otros ya mencionaron, puede detectar ciertos errores utilizando el cliente de servicio (
service_client.exceptions.<ExceptionClass>
) o el recurso (service_resource.meta.client.exceptions.<ExceptionClass>
), sin embargo, no está bien documentado (también qué excepciones pertenecen a qué clientes). Así que aquí está cómo obtener el mapeo completo al momento de escribir (enero de 2020) en la región UE (Irlanda) (eu-west-1
):Aquí hay un subconjunto del documento bastante grande:
fuente
O una comparación en el nombre de la clase, por ejemplo
Debido a que se crean dinámicamente, nunca puedes importar la clase y capturarla usando Python real.
fuente
except Exception as e
y luego tendría instrucciones para determinar la excepción específica? ¿Cómo es eso diferente / mejor que la captura de excepciones específicas? Son más líneas, y de todas formas necesitarías importar la biblioteca para obtener el nombre de la clase. A menos que quieras ir con la codificación del nombre de la excepción. En general, parece una mala manera de hacerlo.Si está llamando a la API sign_up (AWS Cognito) usando Python3, puede usar el siguiente código.
error.response ['Error'] ['Código'] será InvalidPasswordException, UsernameExistsException, etc. Por lo tanto, en la función principal o donde está llamando a la función, puede escribir la lógica para proporcionar un mensaje significativo al usuario.
Un ejemplo para la respuesta (error.response):
Para mayor referencia: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cognito-idp.html#CognitoIdentityProvider.Client.sign_up
fuente
En caso de que tenga que lidiar con el
logs
cliente posiblemente hostil ( CloudWatch Logsput-log-events
), esto es lo que tuve que hacer para detectar correctamente las excepciones del cliente Boto3:Esto funciona tanto en el primer intento (con LogStream vacío) como en los posteriores.
fuente
Después de la actualización de @ armod sobre las excepciones que se agregan directamente en los
client
objetos. Le mostraré cómo puede ver todas las excepciones definidas para su clase de cliente.Las excepciones se generan dinámicamente cuando crea su cliente con
session.create_client()
oboto3.client()
. Internamente llama al métodobotocore.errorfactory.ClientExceptionsFactory._create_client_exceptions()
y llena elclient.exceptions
campo con clases de excepción construidas.Todos los nombres de clase están disponibles en el
client.exceptions._code_to_exception
diccionario, por lo que puede enumerar todos los tipos con el siguiente fragmento:Espero eso ayude.
fuente
Debe hacer algo cuando no puede manejar el problema. En este momento está devolviendo la excepción real. Por ejemplo, si no es un problema que el usuario ya exista y desea usarlo como una función get_or_create, tal vez maneje el problema devolviendo el objeto de usuario existente.
Dicho esto, tal vez sea un problema para su aplicación, en cuyo caso desea colocar el controlador de excepciones alrededor del código que llamó a su función de creación de usuario y dejar que la función de llamada determine cómo tratarla, por ejemplo, preguntando el usuario ingrese otro nombre de usuario, o lo que tenga sentido para su aplicación.
fuente