0

We have a script that regularly copies a bunch of feature classes out to shapefiles, keeping only the most important attributes (e.g. customer category) and dropping useless/private information (e.g. customer name).

Right now, it repeats the same set of steps without much variation. I am attempting to significantly simplify it by defining a function to do all those steps (the entire purpose of functions, of course.) Also, by introducing the arcpy.FieldMappings objects instead of verbose field mapping strings, it's possible to quickly understand what fields are coming from which data sources.

This works great for most of my feature classes.

def generate_field_mapping(inTable, inFieldList):
    fm = arcpy.FieldMappings()
    for field in inFieldList:
        vars()[field] = arcpy.FieldMap()
        vars()[field].addInputField(inTable, field)
        fm.addFieldMap(vars()[field])
    return fm

def subset_attributes(origFC, fieldList, outFC):
    fStart = time.time()
    name = origFC.split('.')[-1]
    # make feature class with only desired fields
    stringFieldMappings = generate_field_mapping(origFC, fieldList)
    tempfc = os.path.join(scratchWS, "temp_{}".format(name))
    arcpy.FeatureClassToFeatureClass_conversion(origFC, scratchWS, outFC, "", stringFieldMappings)
    print "  > done with {} ({} seconds)".format(name, round((time.time() - fStart), 2))

But, I have one feature class for which we want all of the fields dropped and I am not sure if I can accomplish this in the existing function workflow.

  • If I pass an empty list of fields, it breaks: FieldMap: Error in adding input field to field map
  • If I pass an empty ("") value, and put in a conditional to skip fieldmapping if there's no list, then all the original fields are passed.
  • If I pass OBJECTID (logic being, that would definitely be in the output), it breaks: Field mapping error: merge rule not valid for output field OBJECTID

I'm happy to just bypass the fieldmapping part of the function with a conditional, but I am not sure how to drop all the resulting attributes. (I don't want to DeleteField_management each one, that would be clumsy and I switched to FieldMappings to get away from that.) Any ideas for a workaround?

3
  • Is it a shape file? Not sure what the value of scratchWS is... Shapefiles MUST have another field and the FID/SHAPE which is why when you create one it has FID/SHAPE/ID in it - you can't drop the ID until you add another field to replace it (like add Name as text then delete ID).\ Commented Sep 11, 2014 at 21:29
  • scratchWS is a geodatabase; input is from an SDE, output is to a local file gdb.
    – Erica
    Commented Sep 11, 2014 at 22:56
  • So it's not that... If there's nothing in the list then a null object is returned. Perhaps set a boolean first like ValidFields = False, set to True in the for field in inFieldList: and then test - if true return fm else return "" or some other object like [].. I think the problem is than if you supply None you get back None and you want to get back a different flavor of nothing like an empty string or list. Commented Sep 11, 2014 at 23:02

1 Answer 1

4

The FieldInfo() object seems to me to be more appropriate than the FieldMappings if you want to drop fields from your input. It allows you to modify some properties of your input fields when passing them to the output. One of these properties is visibility (if a field is not visible, it won't be passed to the output). It is used among other by the Make Feature Layer tool. I would copy your input to a feature layer with a FieldInfo specifying which fields have to be dropped (hidden), and then use Feature Class to Feature Class without FieldMappings:

def subset_attributes(origFC, fieldList, outFC):

    # List input fields
    fields= arcpy.ListFields(origFC)

    # Create a fieldinfo objects
     fieldinfo = arcpy.FieldInfo()

    # Iterate over input fields, add them to the FieldInfo and hide them if 
    # they aren't in the list of fields to be kept
    for field in fields:
        if not field.name in fieldList:
            fieldinfo.addField(field.name, field.name, "HIDDEN", "")

    # Copy features to a layer using the FieldInfo
    arcpy.MakeFeatureLayer_management(origFC, "temp", "", "", fieldinfo)

    # Export the layer to a feature class
    arcpy.FeatureClassToFeatureClass_conversion("temp", scratchWS, outFC)

This code will work even if you drop all atrributes from the input.

1
  • This is very effective and exactly the shortcut I needed. Thanks!
    – Erica
    Commented Sep 12, 2014 at 16:38

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.