Escribir mensajes en las herramientas de secuencia de comandos

Debe importar ArcPy en las secuencias de comandos de la manera siguiente:

 import arcpy 

Cuando la secuencia de comandos se ejecuta como una herramienta de secuencia de comandos, ArcPy estará completamente al tanto de la aplicación que la invoca, como ArcMap o ArcCatalog. En realidad, está utilizando los mismos objetos que la aplicación en lugar de crear unos nuevos. Toda la configuración del entorno que se hace en la aplicación, como overwriteOutput y scratchWorkspace, se encuentra disponible. Un efecto principal de esto es que puede escribir mensajes con ArcPy y éstos aparecen automáticamente en el cuadro de diálogo de progreso, en el resultado de la herramienta y en la ventana de Python. También significa que cualquier modelo o herramienta de secuencia de comandos que invoque la herramienta de secuencia de comandos tiene acceso a los mensajes que usted escribe.

Compare esto con una secuencia de comandos independiente. En una secuencia de comandos independiente, la secuencia de comandos no se invoca desde una aplicación de ArcGIS. Por lo tanto, no hay cuadro de diálogo de progreso, resultado o ventana de Python en donde se puedan visualizar los mensajes. Si invoca otra secuencia de comandos (independiente) desde dentro de la secuencia de comandos, la secuencia de comandos invocada (si utiliza herramientas de geoprocesamiento) está completamente separada, es diferente de la que usted creó, y no se comparten los mensajes entre ellas. Una de las ventajas más importantes de las herramientas de secuencia de comandos es que se pueden compartir los mensajes y los entornos.

Las cuatro funciones de ArcPy para escribir mensajes son las siguientes:

Ejemplo de agregar mensajes

El ejemplo siguiente copia una lista de clases de entidad de un espacio de trabajo a otro. Ocurre una conversión automática si los espacios de trabajo son de un tipo distinto, como de geodatabase a carpeta. El manejo de errores se utiliza para detectar problemas y devolver mensajes; en caso contrario, los mensajes informativos de éxito se devuelven durante la ejecución. En este ejemplo se utiliza la directiva importar desde <módulo>. En este caso, el módulo es ScriptUtils, y su código también se indica a continuación. Este código también utiliza bloques try/except .

Más información sobre los bloques try/except

 # ConvertFeatures.py  #   Converts feature classes by copying them from one workspace to another # # Import the ScriptUtils utility module which, in turn,  imports the  #  standard library modules and imports arcpy # from ScriptUtils import *  # Get the list of feature classes to be copied to the output workspace # in_feature_classes = arcpy.GetParameterAsText(0)  # Establish an array of input feature classes using the ScriptUtils routine. # in_feature_classes = SplitMulti(in_feature_classes)  # Get the output workspace # out_folder = arcpy.GetParameterAsText(1)  # Loop through the array copying each feature class to the output workspace # for in_feature_class in in_feature_classes:     try:         # Create the output name         #         feature_class_name = arcpy.ValidateTableName(in_feature_class, out_folder)          # Add an output message         #         arcpy.AddMessage("Converting: " + in_feature_class + " To " +\                          feature_class_name + ".shp")              # Copy the feature class to the output workspace using the ScriptUtils routine         #         CopyFeatures(in_feature_class, out_folder + os.sep + \                      feature_class_name)          # If successful, add another message         #         arcpy.AddMessage("Successfully converted: " + in_feature_class + \                           " To " + out_folder)              except StandardError, ErrDesc:         arcpy.AddWarning("Failed to convert: " + in_feature_class)         arcpy.AddWarning(ErrDesc)     except:         arcpy.AddWarning("Failed to convert: " + in_feature_class)         if not arcpy.GetMessages(2) == "":             arcpy.AddError(arcpy.GetMessages(2))

A continuación se encuentra el módulo ScriptUtils utilizado anteriormente.

 # ScriptUtils.py  # Import required modules # import arcpy import sys import string import os  def SplitMulti(multi_input):     try:         # Split the multivalue on the semi-colon delimiter         #         multi_as_list = string.split(multi_input, ";")         return multi_as_list     except:         ErrDesc = "Error: Failed in parsing the inputs."         raise StandardError, ErrDesc          def CopyFeatures(in_table, out_table):     try:         ErrDesc = "CopyFeatures failed"          # Copy each feature class to the output workspace         #         arcpy.CopyFeatures_management(in_table, out_table)     except:         if arcpy.GetMessages(2) != "":             ErrDesc = arcpy.GetMessages(2)         raise StandardError, ErrDesc 

Notas sobre las secuencias de comando anteriores

Las funciones, los módulos y los objetos se pueden importar desde otras secuencias de comando de Python para simplificar la secuencia de comandos y centralizar el código. La instrucción import se utiliza para extraer toda la información de otra secuencia de comandos o sólo las entidades que desee.

Las excepciones son eventos que pueden modificar el flujo de control mediante un programa. Pueden desencadenarse o interceptarse dentro de una secuencia de comandos mediante las instrucciones try y raise . StandardError es una excepción integrada en la cual se basan la mayoría de los tipos de excepción en Python. Se invoca si ocurre un error de herramienta con la variable ErrDesc establecida por el mensaje de error de la herramienta.

Más información sobre cómo manejar errores en Python

Las cadenas de texto, definidas en el módulo string , son un tipo integrado utilizado para almacenar y representar texto. Se admiten varias operaciones para manipular las cadenas de texto, como la concatenación, la segmentación y la indexación.

El módulo del sistema operativo (os) le suministra una interfaz genérica al conjunto de herramientas básico del sistema operativo.

Devolver todos los mensajes de una herramienta

Hay veces en las que puede desear devolver todos los mensajes de la herramienta que invocó, sin importar la gravedad del mensaje. Al utilizar un parámetro de índice, la función AddReturnMessage devuelve un mensaje desde el conjunto de mensajes de ArcPy. El siguiente ejemplo muestra cómo devolver todos los mensajes de una herramienta:

arcpy.Clip_analysis("roads","urban_area","urban_roads") # Return the resulting messages as script tool output messages # x = 0 while x < arcpy.MessageCount:     arcpy.AddReturnMessage(x)     x = x + 1

Mensajes en una secuencia de comandos de propósito dual

Puede diseñar la secuencia de comandos para propósitos duales: se puede utilizar como secuencia de comandos independiente (del sistema operativo) o como una herramienta de secuencia de comandos. Existen tres consideraciones:

La práctica estándar consiste en escribir una rutina de informes de error que escriba mensajes en la salida estándar (mediante print) y por medio de ArcPy (mediante las funciones AddMessage, AddWarning y AddError). A continuación se presenta una rutina de ese tipo, tomada de la herramienta Zona de influencia en anillos múltiples, una herramienta de secuencia de comandos de la caja de herramientas Análisis. Puede visualizar la secuencia de comandos de Zona de influencia en anillos múltiples si ubica la herramienta en la caja de herramientas Análisis, hace clic con el botón derecho del ratón y a continuación hace clic en Editar.

 def AddMsgAndPrint(msg, severity=0):     # Adds a Message (in case this is run as a tool)     # and also prints the message to the screen (standard output)     #      print msg      # Split the message on \n first, so that if it's multiple lines,      #  a GPMessage will be added for each line     try:         for string in msg.split('\n'):             # Add appropriate geoprocessing message              #             if severity == 0:                 arcpy.AddMessage(string)             elif severity == 1:                 arcpy.AddWarning(string)             elif severity == 2:                 arcpy.AddError(string)     except:         pass 

Controlar el cuadro de diálogo de progreso

Debido a que las herramientas de secuencia de comandos comparten la aplicación, usted tiene control sobre el cuadro de diálogo de progreso. Puede controlar la apariencia del cuadro de diálogo de progreso seleccionando el indicador de progreso predeterminado o el indicador de progreso por pasos, como se muestra a continuación.

Indicadores de progreso predeterminado y por pasos

Existen cuatro funciones que puede utilizar para controlar el cuadro de diálogo de progreso y su indicador de progreso.

Función

Descripción

SetProgressor

Establece el tipo de indicador de progreso (predeterminado o por pasos); su etiqueta y el mínimo, el máximo y el intervalo para los indicadores de progreso por pasos

ResetProgressor

Restablece el indicador de progreso

SetProgressorPosition

Mueve el indicador de progreso por pasos según un incremento

SetProgressorLabel

Cambia la etiqueta del indicador de progreso

Funciones de indicador de progreso de geoprocesamiento

El siguiente código demuestra el uso completo de los indicadores de progreso predeterminado y por pasos. Copie este código en el editor de Python, guárdelo y a continuación cree una herramienta de secuencia de comandos para él. La herramienta de secuencia de comandos tiene dos parámetros de entrada largos como se describe en los comentarios del código. A continuación, ejecute la herramienta de secuencia de comandos, y suministre valores diferentes para los parámetros (comience con n = 10 y p = 1, después pruebe con n = 101 y p = 3).

 # Demonstration script showing examples of using the progressor #  Parameters: #   n - number to count to (a good first choice is 10) #   p - interval to count by (a good first choice is 1) # The various time.sleep() calls are just to slow the dialog down #  so you can view messages and progressor labels. # import arcpy import time  n = int(arcpy.GetParameterAsText(0)) p = int(arcpy.GetParameterAsText(1))  readTime = 2.5 # Pause to read what's written on dialog loopTime = 0.3 # Loop iteration delay  arcpy.AddMessage("Running demo with: " + str(n) + " by " + str(p))  # Start by showing the default progress dialog, where the #  progress bar goes back and forth. Note how the progress label #  mimics working through some "phases", or chunks of work that #  a script may perform. # arcpy.SetProgressor("default", "This is the default progressor") time.sleep(readTime)  for i in range(3):   arcpy.SetProgressorLabel("Working on \"phase\" " + str(i + 1))   arcpy.AddMessage("Messages for phase " + str(i+1))   time.sleep(readTime) arcpy.AddMessage("-------------------------")  # Setup the progressor with its initial label, min, max, and interval # arcpy.SetProgressor("step", "Step progressor: Counting from 0 to " + str(n), 0, n, p) time.sleep(readTime)  # Loop issuing a new label when the increment is divisible by the #  value of countBy (p). The "%" is python's modulus operator - we #  only update the position every p'th iteration # for i in range(n):   if (i % p) == 0:     arcpy.SetProgressorLabel("Iteration: " + str(i))     arcpy.SetProgressorPosition(i)     time.sleep(loopTime)  # Update the remainder that may be left over due to modulus operation #   arcpy.SetProgressorLabel("Iteration: " + str(i+1)) arcpy.SetProgressorPosition(i+1)  arcpy.AddMessage("Done counting up") arcpy.AddMessage("-------------------------") time.sleep(readTime)  # Just for fun, make the progressor go backwards. # arcpy.SetProgressor("default", "Default progressor: Now we'll do a countdown") time.sleep(readTime) arcpy.AddMessage("Here comes the countdown...") arcpy.SetProgressor("step", "Step progressor: Counting backwards from " + str(n), 0, n, p) time.sleep(readTime) arcpy.AddMessage("Counting down now...")  for i in range(n, 0, -1):   if (i % p) == 0:     arcpy.SetProgressorLabel("Iteration: " + str(i))     arcpy.SetProgressorPosition(i)     time.sleep(loopTime)  # Update for remainder # arcpy.SetProgressorLabel("Iteration: " + str(i-1)) arcpy.SetProgressorPosition(i-1) time.sleep(readTime)     arcpy.AddMessage("-------------------------") arcpy.AddMessage("All done") arcpy.ResetProgressor() 

Seleccionar un incremento adecuado cuando el máximo puede ser grande

Es bastante común escribir secuencias de comandos que iteren una cantidad de veces no conocida. Por ejemplo, la secuencia de comandos puede utilizar un SearchCursor para iterar por todas las filas de una tabla y no se conoce la cantidad de filas de antemano: la secuencia de comandos se puede utilizar con tablas de cualquier tamaño, desde varios miles de filas hasta millones de filas. Incrementar un indicador de progreso por pasos para cada fila en una tabla grande es un cuello de botella de rendimiento y es posible que usted desee evitar tales situaciones.

Para demostrar y evaluar los problemas de rendimiento con indicadores de progreso por pasos, copie el siguiente código en el editor de Python, guárdelo, y a continuación cree una herramienta de secuencia de comandos para él. La herramienta tiene dos entradas: un parámetro de tabla y un parámetro de campo. Ejecute la herramienta de secuencia de comandos con una variedad de tamaños de tablas, pero asegúrese de intentar con una clase de entidad o tabla que contenga 10.000 filas o más para ver las diferencias en el rendimiento. (También puede intentar la ejecución de la herramienta dentro y fuera del proceso para evaluar el aumento de rendimiento al ejecutarla dentro del proceso).

La secuencia de comandos ejecuta tres bucles separados y cada bucle captura todas las filas de la tabla. Los bucles se diferencian en la manera de actualizar el indicador de progreso por pasos. El primer y segundo bucle actualizan el indicador de progreso por pasos en incrementos grandes y el último bucle incrementa el indicador de progreso por pasos una vez para cada fila. Cuando ejecute la herramienta, verá que este último bucle tarda más en ejecutarse.

Es posible que desee emplear las técnicas que se encuentran en este código en las herramientas de secuencia de comandos.

# Demonstrates a step progressor by looping through records #  on a table. Use a table with 10,000 or so rows - smaller tables #  just whiz by. #   1 = table name #   2 = field on the table  import arcpy  try:   inTable = arcpy.GetParameterAsText(0)   inField = arcpy.GetParameterAsText(1)    # Determine n, number of records on the table   #   arcpy.AddMessage("Getting row count")   n = arcpy.GetCount_management(inTable)   if n == 0:     raise "no records"      arcpy.AddMessage("Number of rows = " + str(n))   arcpy.AddMessage("")   arcpy.AddMessage("---------------------------------")      # Method 1: Calculate and use a suitable base 10 increment    # ===================================   import math   p = int(math.log10(n))   if not p:     p = 1   increment = int(math.pow(10, p-1))    arcpy.SetProgressor("step", "Incrementing by " + str(increment) + " on " + \                       inTable, 0, n, increment)    rows = arcpy.SearchCursor(inTable)   i = 0   beginTime = time.clock()   for row in rows:     if (i % increment) == 0:       arcpy.SetProgressorPosition(i)     fieldValue = row.getValue(inField)     i = i + 1    arcpy.SetProgressorPosition(i)   arcpy.AddMessage("Method 1")   arcpy.AddMessage("Increment = " + str(increment))   arcpy.AddMessage("Elapsed time: " + str(time.clock() - beginTime))   arcpy.AddMessage("---------------------------------")      del rows   del row    # Method 2: let's just move in 10 percent increments   # ===================================   increment = int(n/10.0)   arcpy.SetProgressor("step", "Incrementing by " + str(increment) + " on " + inTable, \                    0, n, increment)      rows = arcpy.SearchCursor(inTable)   i = 0   beginTime = time.clock()   for row in rows:     if (i % increment) == 0:       arcpy.SetProgressorPosition(i)     fieldValue = row.getValue(inField)     i = i + 1        arcpy.SetProgressorPosition(i)   arcpy.AddMessage("Method 2")   arcpy.AddMessage("Increment = " + str(increment))   arcpy.AddMessage("Elapsed time: " + str(time.clock() - beginTime))   arcpy.AddMessage("---------------------------------")      del rows   del row    # Method 3: use increment of 1   # ===================================   increment = 1   arcpy.SetProgressor("step", "Incrementing by 1 on " + inTable, 0, n, increment)      rows = arcpy.SearchCursor(inTable)    beginTime = time.clock()   while row:     arcpy.SetProgressorPosition()     fieldValue = row.getValue(inField)    arcpy.SetProgressorPosition(n)   arcpy.ResetProgressor()   arcpy.AddMessage("Method 3")   arcpy.AddMessage("Increment = " + str(increment))   arcpy.AddMessage("Elasped time: " + str(time.clock() - beginTime))   arcpy.AddMessage("---------------------------------")   arcpy.AddMessage("")   arcpy.AddMessage("Pausing for a moment to allow viewing...")   time.sleep(2.0) # Allow viewing of the finished progressor    del rows   del row  except "no records":   arcpy.AddWarning(inTable + " has no records to count")  except:   if rows:     del rows   if row:     del row   arcpy.AddError("Exception occurred")

7/10/2012