0

I have an ArcPy script that adds new fields and then deletes unnecessary fields from a group of feature classes. I am a novice at ArcGIS and even more so at ArcPy, but have been able to piece together the code below from other working examples. I am currently using ArcGIS 10.0, and expect to get version 10.3 before long.

    import arcpy, os

try:
    # Set the workspace to edit
    arcpy.env.workspace = r'E:\Python Testing\NavajoAUM_SiteScreens.gdb\Central'
    # For loop to go through feature classes in the workspace
    for fc in arcpy.ListFeatureClasses():
    # add new fields
        arcpy.AddField_management(fc, "GammaMeas", "DOUBLE", field_precision = 9, field_scale = 0)
        arcpy.AddField_management(fc, "BkgLevel", "DOUBLE", field_precision = 9, field_scale = 0)
        arcpy.AddField_management(fc, "MineID", "TEXT", field_length = 10)
        arcpy.AddField_management(fc, "OrigFileName", "TEXT", field_length = 50)

    # Set the cursor
        cursor = arcpy.UpdateCursor(fc)
        row = cursor.next()
    # Save values for the MineID and OrigFileName
        desc = arcpy.Describe(fc)
        mineValue = desc.name[desc.name.rfind("_") + 1:]
        fileValue = desc.name
    # While loop updates values in each row
        while row:
            row.setValue("GammaMeas", row.getValue("Text"))
            row.setValue("BkgLevel", "12500")
            row.setValue("MineID", mineValue)
            row.setValue("OrigFileName", fileValue)
            cursor.updateRow(row)
            row = cursor.next()
except:
    pass

# Set the workspace to edit
arcpy.env.workspace = r'E:\Python Testing\NavajoAUM_SiteScreens.gdb\Central'
# Local Variables to keep  
keep = ['OBJECTID','FID','Shape', 'Text', 'Channel', 'Northing', 'Easting', 'GammaMeas', 'BkgLevel', 'MineID', 'OrigFileName']  # be SURE to include FID/OBJECTID field here!  
for fc in arcpy.ListFeatureClasses():  
    try:  
        discard = []  
        for field in [f.name for f in arcpy.ListFields(fc)if f.type <> 'Geometry']:  
            if field not in keep:  
                discard.append(field)  
        arcpy.DeleteField_management(fc, discard)  

    except:  
        pass

It seems like using memory management would greatly improve the performance of the script, and that error handling could be improved, but I'm at a loss on how to implement either of those correctly here. There might be other obvious improvements to make that I don't know about, or haven't attempted yet (e.g., maybe adding fields and deleting fields in one loop would be better).

As far as errors go, it appears that sometimes the script runs fine, sometimes it will throw an error and stop, and other times no error is raised but the script seems to stop early (e.g., not all fields added or filled, no fields deleted). I'd like to know where / which feature classes are causing the errors so I can QC the feature class / attributes table and fix.

closed as too broad by PolyGeo Jun 27 '16 at 20:14

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    Step 1: Take out the try/except statements (be sure to change your indentation accordingly). The reason for this is that try/except statements can hide errors that need to be addressed. If there is an error, you don't want it to pass unnoticed, which is what you're doing right now. – Tom Jun 27 '16 at 19:33
  • 2
    What version of ArcGIS are you using? If it's >= 10.1, then you can really ramp up your speed with data access cursors. – Tom Jun 27 '16 at 19:35
  • Thanks Tom. I'm using 10.0 currently, and I hope to have 10.3 soon. I thought I had listed the ArcGIS version but that was missing. – Mark F. Jun 27 '16 at 22:34
  • Rather than removing the try, except statements, you could also print the exception and keep running, therefore picking up all errors on the entire dataset, try: something.... except Exception as err: print err – JamesLeversha Jun 28 '16 at 11:25
  • @MarkF., I've added a 10.0-compatible version of the script. I hope it helps. – Tom Jun 30 '16 at 14:39
1

If you're using ArcGIS 10.1 or above, you can use data access cursors. You can also remove your second outer loop by doing all the same stuff within the first loop. You don't need to reset the arcpy workspace to the same path twice.

As I commented above, you pretty much never want to use try/except, until you have your script working properly.

I've added some additional comments in this updated code:

import arcpy, os

# Set the workspace to edit
arcpy.env.workspace = r'E:\Python Testing\NavajoAUM_SiteScreens.gdb\Central'

keep = ['FID','Text', 'Channel', 'Northing', 'Easting', 'GammaMeas', 'BkgLevel', 'MineID', 'OrigFileName']

# For loop to go through feature classes in the workspace
for fc in arcpy.ListFeatureClasses():
    # Go ahead and delete any fields that you don't need; using the old-style
    #   cursors, as you were and as you must if you're pre-10.1, all fields
    #   will be in-memory when you use the cursor, and this can be a real drag
    #   on performance. Some other operations (e.g., copying features, etc.)
    #   will be slowed down by extraneous fields. Remove all unnecessary fields
    #   as soon as you can.
    for field in arcpy.ListFields(fc):
        # Check that it's not a required field and that it's not in the list
        #   of fields to keep; then delete it. Arcpy's DeleteField tool is
        #   sadly inefficient. There are work-arounds; let me know if this is a
        #   bottleneck for you.
        if not i.required and i.name not in keep:
            arpcy.DeleteField_management(fc, i.name)

    # Add new fields
    arcpy.AddField_management(fc, "GammaMeas", "DOUBLE", field_precision = 9, field_scale = 0)
    # You're assigning the value of 12500 to every BkgLevel. If you only have
    #   integer values, and they're below 32,767, save yourself the space and
    #   use SHORT integers:
        # http://desktop.arcgis.com/en/arcmap/10.3/manage-data/geodatabases/arcgis-field-data-types.htm
    arcpy.AddField_management(fc, "BkgLevel", "SHORT")
    arcpy.AddField_management(fc, "MineID", "TEXT", field_length = 10)
    arcpy.AddField_management(fc, "OrigFileName", "TEXT", field_length = 50)

    # Save values for the MineID and OrigFileName
    desc = arcpy.Describe(fc)
    fileValue = desc.name
    mineValue = fileValue[fileValue.rfind("_") + 1:]

    # Cursor
    fields_cur = ['Text', 'GammaMeas', 'BkgLevel', 'MineID', 'OrigFileName']
    # Data access cursors are much faster than old-style cursors.
    #   http://pro.arcgis.com/en/pro-app/arcpy/get-started/data-access-using-cursors.htm
    with arcpy.da.UpdateCursor(fc, fields_cur) as cursor:
        for row in cur:
            row[1] = row[0]
            # Previously, you were trying to assign a text value to this field,
            #   but hyou had created it as a DOUBLE field. That won't work.
            #   Always ensure that your data type match between the object your
            #   assigning and its destination
            row[2] = 12500
            row[3] = mineValue
            row[4] = fileValue
            cursor.updateRow(row)

And here's a version for 10.0:

import arcpy, os

# Set the workspace to edit
arcpy.env.workspace = r'E:\Python Testing\NavajoAUM_SiteScreens.gdb\Central'

keep = ['FID','Text', 'Channel', 'Northing', 'Easting', 'GammaMeas', 'BkgLevel', 'MineID', 'OrigFileName']

# For loop to go through feature classes in the workspace
for fc in arcpy.ListFeatureClasses():
    # Go ahead and delete any fields that you don't need; using the old-style
    #   cursors, as you were and as you must if you're pre-10.1, all fields
    #   will be in-memory when you use the cursor, and this can be a real drag
    #   on performance. Some other operations (e.g., copying features, etc.)
    #   will be slowed down by extraneous fields. Remove all unnecessary fields
    #   as soon as you can.
    for field in arcpy.ListFields(fc):
        # Check that it's not a required field and that it's not in the list
        #   of fields to keep; then delete it. Arcpy's DeleteField tool is
        #   sadly inefficient. There are work-arounds; let me know if this is a
        #   bottleneck for you.
        if not i.required and i.name not in keep:
            arpcy.DeleteField_management(fc, i.name)

    # Add new fields
    arcpy.AddField_management(fc, "GammaMeas", "DOUBLE", field_precision = 9, field_scale = 0)
    # You're assigning the value of 12500 to every BkgLevel. If you only have
    #   integer values, and they're below 32,767, save yourself the space and
    #   use SHORT integers:
        # http://desktop.arcgis.com/en/arcmap/10.3/manage-data/geodatabases/arcgis-field-data-types.htm
    arcpy.AddField_management(fc, "BkgLevel", "SHORT")
    arcpy.AddField_management(fc, "MineID", "TEXT", field_length = 10)
    arcpy.AddField_management(fc, "OrigFileName", "TEXT", field_length = 50)

    # Save values for the MineID and OrigFileName
    desc = arcpy.Describe(fc)
    fileValue = desc.name
    mineValue = fileValue[fileValue.rfind("_") + 1:]

    # Cursor
    cur = arcpy.UpdateCursor(fc)
    for row in cur:
        row.setValue('GammaMeas', row.getValue('Text'))
        # Previously, you were trying to assign a text value to this field,
        #   but hyou had created it as a DOUBLE field. That won't work.
        #   Always ensure that your data type match between the object your
        #   assigning and its destination
        row.setValue('BkgLevel', 12500)
        row.setValue('MineID', mineValue)
        row.setValue('OrigFilename', fileValue)
        cursor.updateRow(row)

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