11

I created a Python Toolbox tool to reorder fields and create a new feature class with the reordered fields. The tool works nicely and I am able to use a value table to let the user arrange the fields in the order they choose or they can fill in a rank value for each field. However, the annoying part of this tool is that all fields need to be added to the value table one at a time before reordering.

I am trying to set this up to bring in all the fields to the value table by default and any unwanted fields can be removed before reordering them. Has anyone had success doing something like this before? I am trying to achieve this in the UpdateParameters method. Here is the code I am trying:

import arcpy
import os
class Toolbox(object):
 def __init__(self):
 """Define the toolbox (the name of the toolbox is the name of the
 .pyt file)."""
 self.label = "Reorder Fields"
 self.alias = "Reorder Fields"
 # List of tool classes associated with this toolbox
 self.tools = [ReorderFields]
class ReorderFields(object):
 def __init__(self):
 """Define the tool (tool name is the name of the class)."""
 self.label = "Reorder Fields"
 self.description = ""
 self.canRunInBackground = False
 def getParameterInfo(self):
 """Define parameter definitions"""
 fc = arcpy.Parameter(displayName='Features',
 name='features',
 datatype='Feature Layer',
 parameterType='Required',
 direction='Input')
 vt = arcpy.Parameter(
 displayName='Fields',
 name='Fields',
 datatype='Value Table',
 parameterType='Required',
 direction='Input')
 output = arcpy.Parameter(
 displayName='Output Features',
 name='output_features',
 datatype='Feature Class',
 parameterType='Required',
 direction='Output')
 vt.columns = [['Field', 'Fields'], ['Long', 'Ranks']]
 vt.parameterDependencies = [fc.name] 
 params = [fc, vt, output]
 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."""
 if parameters[0].value:
 if not parameters[1].altered:
 fields = [f for f in arcpy.Describe(str(parameters[0].value)).fields
 if f.type not in ('OID', 'Geometry')]
 vtab = arcpy.ValueTable(2)
 for field in fields:
 vtab.addRow("{0} {1}".format(field.name, ''))
 parameters[1].value = vtab
 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):
 """The source code of the tool."""
 fc = parameters[0].valueAsText
 vt = parameters[1].valueAsText
 output = parameters[2].valueAsText

enter image description here

I want to bring all the fields as shown in the value table above by default. I also tried using the parameters[1].value to add rows the the specific value table from the GUI, but that gave me errors. I'm using ArcGIS 10.2.2.

PolyGeo
65.5k29 gold badges115 silver badges349 bronze badges
asked Nov 24, 2014 at 18:28
2
  • 1
    I haven't done anything like that before, so just throwing an idea out there and it could be very unreasonable, but can you store all the fields from all the layers in your init and then when a user selects a layer, it uses that data structure to populate the fields? as I said I've never worked with this before and just trying to put in my 2 insignificant cents Commented Dec 3, 2014 at 21:37
  • Thanks for the suggestion. I tried that in the getParameterInfo() method with both adding rows to the vt param object itself and creating a new value table, adding the rows and setting the vt.value to the new value table with still no luck. I don't think I can use this in the ReorderFields instantiation because the fields are dependent on an input feature class. Maybe I can make a value table object in the init and try setting the vt.value to the self.valueTable once the rows have been populated. Commented Dec 3, 2014 at 22:00

1 Answer 1

8
+50

Change the updateParameters as follows:

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."""
 if parameters[0].value:
 if not parameters[1].altered:
 fields = [f for f in arcpy.Describe(str(parameters[0].value)).fields
 if f.type not in ('OID', 'Geometry')]
 vtab = []
 for field in fields:
 vtab.append([field.name,None])
 parameters[1].values = vtab
 return

Your mistake here is to try changing an already initiated parameter instead of its values due to using wrong property. Please see 'values' property of Parameter (arcpy).

answered Dec 5, 2014 at 6:14
1
  • 1
    Beautiful! I can't believe I missed that...It seems so obvious. Thank you very much! Commented Dec 5, 2014 at 15:17

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.