Así que aquí está el código de mi herramienta de script en su totalidad:
import arcpy
import datetime
import os
import sys
import itertools
import traceback
#Set Environment Variables
arcpy.env.overwriteOutput = True
arcpy.env.workspace = arcpy.GetParameterAsText(1)
#Collect user info from ArcGIS
PTE_layer = arcpy.GetParameterAsText(0)
rlf = arcpy.GetParameterAsText(2)
output_folder = arcpy.GetParameterAsText(3)
pdf = arcpy.GetParameter(4)
excel = arcpy.GetParameter(5)
#Set usefuls for later
today = datetime.datetime.today()
mxd = arcpy.mapping.MapDocument("CURRENT")
df = arcpy.mapping.ListDataFrames(mxd)[0]
class ProjectPTE:
def __init__(self, CIP_ID = None, answer = None):
self.CIP_ID = CIP_ID
self.Yes = 0
self.No = 0
self.OwnerChange = 0
self.Other = 0
self.add(answer)
def add(self,answer):
if answer == "Y":
self.Yes += 1
elif answer == "N":
self.No += 1
elif answer == "New Ownership - Need PTE":
self.OwnerChange += 1
else:
self.Other += 1
def compare(self,other):
try:
if self.CIP_ID == other.CIP_ID:
return True
else:
return False
except AttributeError:
return False
#Create cursor to move through PTE layer
fields = ["CIP_ID","PTE_Rcvd"]
#Main loop
#Using the ProjectPTE class above to define the rules for comparison,
# initialization, and updating, the loop goes through each row in the PTE
# layer and adds it's information to the project list. This is accomplished
# by creating a ProjectPTE out of the current row and comparing that ProjectPTE
# with the existing ProjectPTEs in the project list.
project_list = []
pte_count = 0
with arcpy.da.SearchCursor(PTE_layer,fields) as PTE_cursor:
for row in PTE_cursor:
pte_count += 1
CIP_ID = row[0]
PTE_Rcvd = row[1]
#Use current row CIP_ID to initialize new ProjectPTE
current = ProjectPTE(CIP_ID,PTE_Rcvd)
#Search through project list
for project in project_list:
#Compare CIP_IDs of list project and current layer project
if current.compare(project):
#If a match is found, add PTE_Rcvd status to the project's
# respective variable
project.add(PTE_Rcvd)
break #Stop searching the project_list
#If break was never reached, no matching CIP_ID was found. Add current
# project to project list and update that project's respective attribute
else:
project_list.append(current)
arcpy.AddMessage(str(pte_count) + " total PTEs counted for " + str(len(project_list)) + " projects")
del PTE_cursor
#Create a new table and populate it with the information collected in the
# project_list
stat_table = "PTE_Status_" + today.strftime("%Y%m%d")
arcpy.CreateTable_management(arcpy.env.workspace, stat_table)
fields = ["CIP_ID","Yes","No","Change_Owner","Other","Total"]
types = ["TEXT","SHORT","SHORT","SHORT","SHORT","SHORT"]
lengths = 12
for field_name,field_type in itertools.izip(fields,types):
arcpy.AddMessage("Inserting " + field_name + " : " + field_type)
arcpy.AddField_management(in_table=stat_table, field_name=field_name,
field_type=field_type, field_length=12)
#Create an insert cursor to populate the table
stat_cursor = arcpy.da.InsertCursor(stat_table, fields)
for project in project_list:
total = project.Yes + project.No + project.OwnerChange + project.Other
row = [
project.CIP_ID,
project.Yes,
project.No,
project.OwnerChange,
project.Other,
total
]
stat_cursor.insertRow(row)
#Export Reports
export_string = "\\PTE_Status_" + today.strftime("%Y%m%d")
report_table = arcpy.mapping.TableView(stat_table)
#Insert the table into the current map
arcpy.mapping.AddTableView(df, report_table)
arcpy.RefreshTOC()
if report_table == arcpy.mapping.ListTableViews(mxd)[0]:
arcpy.AddMessage("They are the same!")
else:
arcpy.AddMessage("They are different!")
try:
output_location = output_folder + export_string
os.mkdir(output_location)
except WindowsError:
pass
except:
arcpy.AddWarning("Cannot create new folder. Generating files in "
"given folder instead.")
output_location = output_folder
export_stub = output_location + export_string
if pdf:
arcpy.AddMessage("Writing PDF from " + str(report_table) + " to " + export_stub + ".pdf")
try:
export_file = export_stub + ".pdf"
arcpy.mapping.ExportReport(report_table, rlf, export_file)
except:
arcpy.AddWarning("No PDF Written")
tb = sys.exc_info()[2]
tbinfo = traceback.format_tb(tb)[0]
pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + sys.exc_info()[1].args[0]
msgs = "ArcPy ERRORS:\n" + arcpy.GetMessages(2) + "\n"
arcpy.AddWarning(pymsg)
arcpy.AddWarning(msgs)
if excel:
arcpy.AddMessage("Writing spreadsheet from " + report_table.name + " to " + export_stub + ".xls")
try:
export_file = export_stub + ".xls"
arcpy.TableToExcel_conversion(report_table.name, export_file)
except:
arcpy.AddWarning("No Excel Spreadsheet written")
tb = sys.exc_info()[2]
tbinfo = traceback.format_tb(tb)[0]
pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + sys.exc_info()[1].args[0]
msgs = "ArcPy ERRORS:\n" + arcpy.GetMessages(2) + "\n"
arcpy.AddWarning(pymsg)
arcpy.AddWarning(msgs)
El error generado desde Export Report es un IOError: No se pudo escribir el archivo de salida del informe. Esto me indica que el informe se ejecuta correctamente (los campos de mi tabla generada coinciden con los campos de mi rlf) pero no se puede escribir.
No se genera ningún error de TabletoExcel_conversion. La salida, sin embargo, es un .xls válido con las cabeceras de tabla correctas y sin valores de atributo.
La tabla se ha creado correctamente y se ha añadido a mi mapa. Entonces puedo ejecutar manualmente la herramienta de geoprocesamiento TabletoExcel y exportar el informe a PDF desde ArcMap sin ningún problema. No hay ninguna razón por la que estas herramientas no se pueden ejecutar dentro de una herramienta de script ArcTool.
He hecho todas las pruebas que se me han ocurrido. Algunas todavía están en mi código (como la comprobación para ver si mi variable objeto TableView es la misma que la TableView en mi mapa). No veo ninguna razón por la que estas herramientas no estén funcionando correctamente. Sin embargo, creo que el error generado por ExportReport está directamente relacionado con la falta de datos escritos por TabletoExcel_conversion. No sé por qué ambas herramientas pueden ver mi tabla y los nombres de los campos pero no pueden leer los atributos.
Nota interesante: http://pro.arcgis.com/en/pro-app/tool-reference/conversion/table-to-excel.htm indica que la herramienta acepta un objeto TableView. Cuando paso "report_table" como objeto TableView, obtengo el siguiente error de ejecución:
Traceback (most recent call last):
File "c:\program files\arcgis\desktop10.3\ArcToolbox\Scripts\TableToExcel.py", line 222, in <module>
arcpy.GetParameter(3))
File "c:\program files\arcgis\desktop10.3\ArcToolbox\Scripts\TableToExcel.py", line 190, in table_to_excel
with arcpy.da.SearchCursor(in_table, field_names) as cursor:
RuntimeError: cannot open 'GPT0'
Cuando lo ejecuto como está actualmente (atributo TableView.name), crea las cabeceras sólo .xls. Estoy asumiendo que el nombre de cadena proporcionada genera una búsqueda de la tabla utilizando el espacio de trabajo por lo que encontrar con éxito la tabla. Sin embargo, la ayuda de la herramienta indica específicamente que un objeto TableView se debe pasar, no un nombre de cadena de la tabla.
Sí, la tabla existe, existe en mi mapa, se puede imprimir fila por fila en la ventana de mensajes, etc.
He utilizado con éxito herramientas similares para otros fines, algunos mucho más complicados. Esta me tiene perplejo. He incluido todo mi código porque en este punto el problema podría estar en cualquier parte. Esta debería ser la parte fácil.