Manejo de errores con Python

Los errores ocurren. Escribir scripts que esperen y gestionen errores puede ahorrarle tiempo y frustración. Cuando una herramienta devuelve un mensaje de error, ArcPy genera un error de sistema o una excepción. En Python, puede proporcionar una variedad de estructuras y métodos que pueden manejar excepciones. Por supuesto, un script puede generar errores por razones que no están relacionadas con una herramienta de geoprocesamiento. Estos errores también se deben detectar y tratar de un modo adecuado. Las siguientes secciones ofrecen algunas técnicas que presentan los conceptos básicos del manejo de excepciones de Python.

Cuando una herramienta escribe un mensaje de error, ArcPy genera una excepción arcpy.ExecuteError. Python permite escribir una rutina que se ejecuta automáticamente cuando se genera un error del sistema. En esta rutina de tratamiento de los errores, recupere el mensaje de error de ArcPy y actúe en consecuencia. Si un script no tiene una rutina de manejo de errores, falla inmediatamente, lo que disminuye su solidez. Utilice las rutinas de manejo de errores y mejore la utilidad de un script.

Los mensajes de error de la herramienta de geoprocesamiento están acompañados de un código de seis dígitos. Estos códigos de Id. se han documentado para proporcionar información adicional sobre su causa y la forma en la que se pueden solucionar.

declaración try-except

Se puede utilizar una declaración try-except para envolver programas completos o solo partes determinadas del código para interceptar e identificar errores. Si se produce un error dentro de la declaración try, se emite una excepción y luego se ejecuta el código de la declaración except. Utilizar una declaración except básica es la forma más básica de tratar los errores.

En el siguiente código, Zona de influencia falla porque no se ha proporcionado el argumento buffer_distance_or_field requerido. En lugar de fallar sin explicación, la declaración except se utiliza para capturar el error. A continuación, se recupera e imprime el mensaje de error generado por Zona de influencia. El bloque except solo se ejecuta si Zona de influencia devuelve un error.

import arcpy
import sys
try:
    # Execute the Buffer tool
    arcpy.Buffer_analysis("c:/transport/roads.shp", "c:/transport/roads_buffer.shp")
except Exception:
    e = sys.exc_info()[1]
    print(e.args[0])
    # If using this code within a script tool, AddError can be used to return messages 
    #   back to a script tool. If not, AddError will have no effect.
    arcpy.AddError(e.args[0])

La declaración try tiene una cláusula finally opcional que se puede utilizar para las tareas que siempre se deben ejecutar, independientemente de si se ha producido una excepción o no. En el siguiente ejemplo, se aplica un check-in a la extensión Extensión ArcGIS 3D Analyst en la cláusula finally, lo que garantiza que siempre se aplicará un check-in a la extensión.

class LicenseError(Exception):
    pass
import arcpy
try:
    if arcpy.CheckExtension("3D") == "Available":
        arcpy.CheckOutExtension("3D")
    else:
        # Raise a custom exception
        raise LicenseError
    arcpy.env.workspace = "D:/GrosMorne"
    arcpy.HillShade_3d("WesternBrook", "westbrook_hill", 300)
    arcpy.Aspect_3d("WesternBrook", "westbrook_aspect")
except LicenseError:
    print "3D Analyst license is unavailable"  
except arcpy.ExecuteError:
    print(arcpy.GetMessages(2))
finally:
    # Check in the 3D Analyst extension
    arcpy.CheckInExtension("3D")

Declaración raise

El ejemplo anterior trata una excepción que se ha producido en el código. En algunos casos, puede ser necesario crear excepciones personalizadas. Para este propósito, se puede utilizar una declaración raise. En el siguiente código, se utiliza una instrucción raise cuando se identifica una clase de entidad de entrada sin entidades. Esto no es estrictamente un error sino una condición de que el código se puede utilizar para evitar esta situación.

class NoFeatures(Exception):
    pass
import arcpy
import os
import sys
arcpy.env.overwriteOutput = True
fc = arcpy.GetParameterAsText(0)
try:
    # Check that the input has features
    result = arcpy.GetCount_management(fc)
    if int(result[0]) > 0:
        arcpy.FeatureToPolygon_management(
            fc, os.path.join(os.path.dirname(fc), 'out_poly.shp'))
    else:
        # Raise custom exception
        raise NoFeatures(result)
except NoFeatures:
    # The input has no features
    print('{} has no features'.format(fc))
except:
    # By default any other errors will be caught here
    e = sys.exc_info()[1]
    print(e.args[0])

Clase ExecuteError

Cuando una herramienta de geoprocesamiento falla, genera una clase de excepción arcpy.ExecuteError, lo que significa que puede dividir los errores en diferentes grupos, errores de geoprocesamiento (los que producen la excepción arcpy.ExecuteError) y otros tipos de excepción. Después puede manejar los errores de formas diferentes, como se demuestra en el siguiente código:

import arcpy
import sys
try:
    result = arcpy.GetCount_management("C:/invalid.shp")
  
# Return geoprocessing specific errors
except arcpy.ExecuteError:    
    arcpy.AddError(arcpy.GetMessages(2))    
# Return any other type of error
except:
    # By default any other errors will be caught here
    e = sys.exc_info()[1]
    print(e.args[0])

traceback

En scripts más grandes y complejos, puede resultar difícil determinar la ubicación exacta de un error. Los módulos sys y traceback de Python se pueden utilizar juntos para aislar la ubicación exacta y la causa del error, identificar la causa de un error con más precisión y ahorrar tiempo de depuración.

# Import the required modules
#
import arcpy
import sys
import traceback
arcpy.env.workspace = "C:/Data/myData.gdb"
try:
    arcpy.CreateSpatialReference_management()
    #--------------------------
    # Your code goes here
    #
    # See the table below for examples
    #--------------------------
except arcpy.ExecuteError: 
    # Get the tool error messages 
    msgs = arcpy.GetMessages(2) 
    # Return tool error messages for use with a script tool 
    arcpy.AddError(msgs) 
    # Print tool error messages for use in Python/PythonWin 
    print(msgs)
except:
    # Get the traceback object
    tb = sys.exc_info()[2]
    tbinfo = traceback.format_tb(tb)[0]
    # Concatenate information together concerning the error into a message string
    pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + str(sys.exc_info()[1])
    msgs = "ArcPy ERRORS:\n" + arcpy.GetMessages(2) + "\n"
    # Return python error messages for use in script tool or Python window
    arcpy.AddError(pymsg)
    arcpy.AddError(msgs)
    # Print Python error messages for use in Python / Python window
    print(pymsg)
    print(msgs)

Si se utilizara el código anterior y se produjera un error de la herramienta de geoprocesamiento, como una entrada no válida, se generaría arcpy.ExecuteError y se utilizaría la primera declaración except. Esta declaración imprimirá los mensajes de error mediante la función GetMessages. Si se utilizara el mismo código, pero se produjera un tipo diferente de error, se utilizaría la segunda declaración except. En lugar de imprimir mensajes de geoprocesamiento, obtiene un objeto traceback e imprime los mensajes de error correspondientes del sistema.

La siguiente tabla muestra los errores esperados que son el resultado de tres líneas diferentes de códigos que se pueden sustituir en el código anterior. El primero es un error de la herramienta de geoprocesamiento, que imprime la información de traceback y los mensajes de error de geoprocesamiento. Los ejemplos segundo y tercero no se determinan de manera específica y solamente se imprime la información de traceback.

Su códigoError resultante

arcpy.GetCount_management("")

PYTHON ERRORS:
Traceback info:
  File "c:\temp\errortest.py", line 10, in <module>
    arcpy.GetCount_management("")
Error Info:
Failed to execute. Parameters are not valid.
ERROR 000735: Input Rows: value is required
Failed to execute (GetCount).
ArcPy ERRORS:
Failed to execute. Parameters are not valid.
ERROR 000735: Input Rows: value is required
Failed to execute (GetCount).

x = "a" + 1

PYTHON ERRORS:
Traceback info:
  File "c:\temp\errortest.py", line 10, in <module>
    x = "a" + 1
Error Info:
cannot concatenate 'str' and 'int' objects

float("a text string")

PYTHON ERRORS:
Traceback info:
  File "c:\temp\errortest.py", line 10, in <module>
    float("a text string")
Error Info:
invalid literal for float(): a text string

Resultados de error

Obtener mensajes de error desde un objeto de resultados

A continuación, se muestra un breve análisis sobre el objeto Result:

result = arcpy.GetCount_management("c:/data/rivers.shp")

Si la llamada a GetCount_management genera una excepción, el objeto Result no se crea. Esto significa que no puede recuperar mensajes de error desde el objeto Result.

import arcpy
try:
    result = arcpy.GetCount_management("c:/data/rivers.shp")
# Return Geoprocessing specific errors
# (this method is incorrect!)
except arcpy.ExecuteError:
    arcpy.AddError(result.getMessages(2))

El código anterior falla con el mensaje name 'result' is not defined. Esto se debe a que no se pudo crear el objeto Result por el error de la herramienta. Como no se ha creado el objeto Result, se muestra un error de Python cuando se intenta utilizar el método getMessages.

Nota:

Un objeto Result que se crea mediante la llamada a un servicio de geoprocesamiento en ArcGIS Server se crea, aunque se haya producido un error en la herramienta. Un objeto Result no se puede crear únicamente cuando una herramienta se ejecuta localmente y genera un error. Para obtener más información sobre el uso del objeto de resultados, consulte Utilizar herramientas en Python.