I'm trying to create a tool that compares two data sets. I do not want the Feature Compare tool. Most of the field names in the two data sets are the same, but not all. I want a way to map one field onto another, so I thought a Field Mappings parameter would be best suited for associating fields together. My expectation was that it would populate similar to how setting the 'Obtained From' sub-parameter to a layer populates the fields list with all available fields from that layer, but that did not happen. I want functionality almost exactly like the Append tool. It populates the 'Field Map (optional)' window with a list of field maps where the user can add input fields.
I've tried working with the tool validator class, in the UpdateParameters method, I've added code to create a FieldMappings object and fill it with FieldMap objects created from the fields in another parameter, but I can't get the window on the tool itself to fill with the FieldMap objects. I've debugged to the point where I know for a fact the FieldMappings object is filled how I want it. I just can't get it to display.
Here is my code for the updateParameters method. param[0]
and param[1]
are feature layers. param[2]
is a field mappings parameter.
def updateParameters(self):
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parameter
has been changed."""
if self.params[0].altered:
self.params[2].value = arcpy.FieldMappings()
for field in [a for a in arcpy.ListFields(self.params[0].value.dataSource) if not a.required]:
fm = arcpy.FieldMap()
fm.addInputField(self.params[0].value.dataSource,field.name)
self.params[2].value.addFieldMap(fm)
return
I have also tried this:
def updateParameters(self):
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parameter
has been changed."""
if self.params[0].altered:
fms = arcpy.FieldMappings()
for field in [a for a in arcpy.ListFields(self.params[0].value.dataSource) if not a.required]:
fm = arcpy.FieldMap()
fm.addInputField(self.params[0].value.dataSource,field.name)
fms.addFieldMap(fm)
self.params[2].value = fms
return
I can't find a single post on creating a field mapping parameter in a script similar to the append or spatial join tool.
If the autopopulation is not possible, even getting the FieldMapping parameter to work properly would be an acceptable middle ground. Right now, the 'Add Input Field' never appears when right clicking a field map parameter. If I set the Field Mapping parameter to single value, clicking the window gives 2 options, Add Output Field and Reset. If I add an output field, right clicking that gives more options, Delete, Rename, Merge Rule, and Properties. None of which allow me to add an input field to the field map.
1 Answer 1
I was trying to solve a similar problem and I've found the way to do it here. Field Mapping's parameter value is an empty object and before adding a field to the list, the list should be created. This can be done by adding an empty field mapping in updateParameters()
like this:
import arcpy
class Toolbox(object):
def __init__(self):
"""Define the toolbox (the name of the toolbox is the name of the
.pyt file)."""
self.label = "Toolbox"
self.alias = ""
# 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 = "Tool"
self.description = ""
self.canRunInBackground = False
def getParameterInfo(self):
"""Define parameter definitions"""
param0 = arcpy.Parameter(
displayName="Input Table",
name="in_table",
datatype="GPTableView",
parameterType="Required",
direction="Input")
param1 = arcpy.Parameter(
displayName="Field Mappings",
name="in_fieldmappings",
datatype="GPFieldMapping",
parameterType="Required",
direction="Input")
params = [param0, param1]
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 the input table view is changed
if parameters[0].altered:
inputTable = parameters[0].value
# add a temporary item to the field mappings list
# can be removed later by calling parameters[1].value.removeFieldMap(0)
parameters[1].value = str('Empty')
# add table fields
parameters[1].value.addTable(inputTable)
# or iterate through the fields...
# for field in arcpy.ListFields(inputTable):
# fm = arcpy.FieldMap()
# fm.addInputField(inputTable, field.name)
# parameters[1].value.addFieldMap(fm)
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."""
return
You can now load a table view and field mappings will be populated automatically. You can then add more fields or edit the initial ones.
Please check hasbeenValidated
property also: if parameters[0].altered and not parameters[0].hasbeenValidated:
if You want to get field(s) deleted or modified by end user from tool UI...
-
I realize this is a little old, but I am having trouble getting your example to work. I keep getting the error AttributeError: 'Parameter' object has no attribute 'addTable'user20224– user202242020年03月30日 17:54:23 +00:00Commented Mar 30, 2020 at 17:54
-
Hm, this is strange. How do you define your parameters? I've updated my answer and added the entire toolbox class so you can check
getParameterInfo()
method.Bogdan Hristozov– Bogdan Hristozov2020年04月01日 09:37:50 +00:00Commented Apr 1, 2020 at 9:37
self.params[2].value = fms.exportToString()
). This takes a looooong time in a Python toolbox (minutes). Even then, it doesn't function properly (you can't add new fields and setup input fields to them).