Python Toolbox failing to create a table

1272
8
02-16-2019 09:15 AM
GrantHaynes
Occasional Contributor

Hi Everyone,

I am working on a toolbox that creates a table of extracted values. I have the output parameter set to DEtable, but whenever I run the tool the table is not created. Any help on this would be appreciated.

# Start script
#-----------------------------------------------------------------------------
import arcpy
import os

# Tool initialization
#-----------------------------------------------------------------------------
class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the
        .pyt file)."""
        self.label = "Value_Extraction_Tool"
        self.alias = "Value Extraction Tool"

        # List of tool classes associated with this toolbox
        self.tools = [Tool]

class Tool(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Value Extraction Tool"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        DataSource = arcpy.Parameter(
		    displayName="DataSource",
		    name="DataSource",
		    datatype="DEWorkspace",
		    parameterType="Required",
		    direction="Input")

        InputPoint = arcpy.Parameter(
            displayName="InputPoint",
		    name="InputPoint",
		    datatype="DEFeatureClass",
		    parameterType="Required",
		    direction="Input")

        OutputTB = arcpy.Parameter(
            displayName="OutputTB",
		    name="OutputTB",
		    datatype="DEArcInfoTable",
		    parameterType="Required",
		    direction="Output")

        params = [DataSource, InputPoint, OutputTB]
        return params

    def isLicensed(self):
        # Set whether tool is licensed to execute.
        return True

    def updateParameters(self, parameters):
        # Modify the values and properties of parameters before internal
        # validation is performed.  This method is called whenever a parameter
        # has been changed.
        return

    def updateMessages(self, parameters):
        #Modify the messages created by internal validation for each tool
        #parameter.  This method is called after internal validation."""
        return

    def execute(self, parameters, messages):

        # User input arguments
        DataSource = parameters[0].valueAsText
        InputPoint = parameters[1].valueAsText
        OutputTB = parameters[2].valueAsText


        # Add geometry attributes to inupt point
        arcpy.AddGeometryAttributes_management(InputPoint, "POINT_X_Y_Z_M", "", "", 4326)

        # add fields to output table to hold the temporal data
        arcpy.AddField_management(OutputTB, "POINTID", "SHORT")
        arcpy.AddField_management(OutputTB, "DATAINDEX", "SHORT")
        arcpy.AddField_management(OutputTB, "VALUE", "DOUBLE")

        # Loop through geometry attributes and get the x and y
        with arcpy.da.SearchCursor(InputPoint,"*") as cursor:
            PointIndex = 0
            for row in cursor:
                X = row[3]
                Y = row[4]

                # Get rasters and extract data at an X and Y        
                index = 0
                for (path, dirs, files) in os.walk(DataSource):
                    for ThisFile in files:
                        fName,fExt = os.path.splitext(ThisFile)
                        if fExt.upper() == ".IMG" or fExt.upper() == ".TIF":
                            RasterPath = path + "\\" + ThisFile

                            data = (arcpy.GetCellValue_management(RasterPath, str(X) + " " + str(Y), ""))
                            aquisition_date = arcpy.GetRasterProperties_management(in_raster = RasterPath, property_type = "ACQUISITIONDATE")

                            if str(aquisition_date).upper() == "UNKNOWN":
                                insertcursor = arcpy.InsertCursor(OutputTB)
                                row = insertcursor.newRow()
                                row.setValue("POINTID", PointIndex)
                                row.setValue("DATAINDEX", index)
                                row.setValue("VALUE", data)
                                insertcursor.insertRow(row)
                                del insertcursor
                                index += 1

                PointIndex += 0
            del row
            del cursor
        return

0 Kudos
8 Replies
DanPatterson_Retired
MVP Emeritus

hard to tell since your code as posted will fail due to copy-paste issues, I presume,

/blogs/dan_patterson/2016/08/14/script-formatting 

0 Kudos
RandyBurton
MVP Alum

For a bit of clarity, here is the execute section formatted as Dan suggests.  I've added the return on line 28, but I think you have additional code that goes before that line.

class Tool(object):
    #......

    def execute(self, parameters, messages):
        """The source code of the tool."""

        DataSource = parameters[0].valueAsText
        InputPoint = parameters[1].valueAsText
        OutputTB = parameters[2].valueAsText

        # Add geometry attributes to inupt point
        arcpy.AddField_management(InputPoint, "POINTID", "SHORT")
        arcpy.AddGeometryAttributes_management(InputPoint, "POINT_X_Y_Z_M", "", "", 4326)
        with arcpy.da.UpdateCursor(InputPoint, "POINTID") as cursor:
            index = 0
            for row in cursor:
                row[index] = index
                index += 1

        del row
        del cursor

        # add fields to output table to hold the temporal data
        arcpy.AddField_management(OutputTB, "POINTID", "SHORT")
        arcpy.AddField_management(OutputTB, "DATAINDEX", "SHORT")
        arcpy.AddField_management(OutputTB, "VALUE", "DOUBLE")
        
        return

I believe you need to use Create Table before lines 23-26 that are adding fields.  Your third parameter appears to be the name for the table, but the table is not created just by giving it a name in the parameter form.  I'm also not sure if your code is getting past line 17, which probably should be row[0] = index.  Since you are incrementing index, the value of row[index] would quickly be out of range.

If I understand what you are trying to do, you are adding longitude and latitude fields to a point feature with the Add Geometry Attributes tool.  This will add two fields of type double to the feature (POINT_X and POINT_Y as default names).  You are also adding an id field as a short integer instead of using the OID@ field. 

I am assuming that you want to read the point id, longitude and latitude into your table.  Your table will need 2 fields of type double for the xy coordinates.  So it seems you may want to rethink your table design.

Since things can be a bit tricky to debug inside a python toolbox, I would suggest trying the execute function as a stand-alone script.  Then add it back into your toolbox script.

Hope this helps.

GrantHaynes
Occasional Contributor

Sort of, it seems like Arc wont create a table inherently like it will a feature class, guess I'll have to break up that input string to create a table. I've posted the entire updated script above.  

0 Kudos
Luke_Pinner
MVP Regular Contributor

You state:

I have the output parameter set to DEtable

But your code shows:

        OutputTB = arcpy.Parameter(
            displayName="OutputTB",
              name="OutputTB",
              datatype="DEArcInfoTable",  # <======== ???
              parameterType="Required",
              direction="Output")
‍‍‍‍‍‍‍‍‍‍‍‍‍

Are you really trying to create an INFO table?

it seems like Arc wont create a table inherently like it will a feature class

ArcMap won't inherently create a feature class either. If you're trying to create an empty feature class from scratch (rather than exporting or copying an existing one or as an output from a geoprocessing operation), you need to use the Create Feature Class tool, just like when you want to create an empty table, you need to use the Create Table tool.

GrantHaynes
Occasional Contributor

I was trying a few different table outputs, I accidentally pasted in a version of the script with a different table type. Whenever I've written one of these python toolboxes I've never had to use create feature class,when outputting a feature class, a blank one would be automatically be created. Ultimately this is all a mute point since I'm trying to use this script as a custom geoprocessing service and I just read that GP services on arcserver don't support tables.

curtvprice
MVP Esteemed Contributor

 I just read that GP services on arcserver don't support tables.

There are several approaches to returning 'non transportable' outputs, including tables.

Geoprocessing task settings: Outputs—Documentation | ArcGIS Enterprise 

0 Kudos
GrantHaynes
Occasional Contributor

Thanks, guess I must have misread something when I said it doesn't support tables, says right in there it does. I still don't know what I'm doing wrong, I ran this script successfully with a table output in arcmap only to have it fail in server. It kept creating the table locally on my machine and the feature class on the server. I've overcome this problem by returning a large feature class with 1 point per raster that holds the associated data. I know it's not the greatest way to do this, but its working.

0 Kudos
curtvprice
MVP Esteemed Contributor

I think a table is a 'non-transportable object' which means you can only pass it back as a file. The zip and ship example in the help is probably the way to move anything of appreciable size back.

Well, glad you got something to work for now, even if not ideal.

0 Kudos