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 instrucció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 instrucción try, se emite una excepción y luego se ejecuta el código de la instrucción except. Utilizar una instrucció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 instrucción except se utiliza para capturar el error. A continuación, se recupera e imprime el mensaje de error que genera la Zona de influencia. Tenga en cuenta que 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 instrucció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 realiza un check-in de ArcGIS 3D Analyst extension 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")

Instrucció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 instrucció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 generan 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
    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 instrucción except. Esta instrucció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 instrucció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. Significa que no es posible 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. 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.