Script finishes but fails to update field

419
7
Jump to solution
03-14-2024 07:07 PM
SteveCole
Frequent Contributor

This is driving me crazy. I used a different Python script developed in Arcmap as a framework for this new script for use in ArcGIS Pro. The script is pretty basic- the user specifies two polygon layers and the script loops through all features in the first layer (theUnits in the script) and then does an overlap select against features in the second layer (theParcels). It then builts a unique list for values for a specific field and then populates a field in the first layer with that list of values.

The script runs through to completion but the attribute field it's supposed to populate remains empty. What am I overlooking? I've been running the script through a Toolbox Script tool and choosing the two layers which are present in my map.

FWIW, here's the tail end of the output pushed to the details window:

...Parcel FID List: 1502; 12075
2 parcels intersected and Trusts Encountered were: 2,42
Current ObjectID: 17482
Parcel FID List: 4656
1 parcels intersected and Trusts Encountered were: 1
Current ObjectID: 17483
Parcel FID List: 12100
1 parcels intersected and Trusts Encountered were: 1
Current ObjectID: 17484
Parcel FID List: 10375
1 parcels intersected and Trusts Encountered were: 1
Current ObjectID: 17485
Parcel FID List: 3101; 5204; 7300
3 parcels intersected and Trusts Encountered were: 1
Current ObjectID: 17490
Parcel FID List: 6957; 16736
2 parcels intersected and Trusts Encountered were: 3
Current ObjectID: 17491
Parcel FID List: 745; 3102; 4127; 5613
4 parcels intersected and Trusts Encountered were: 1
Current ObjectID: 17494
Parcel FID List: 97
1 parcels intersected and Trusts Encountered were: 3
Current ObjectID: 17495
Parcel FID List: 358
1 parcels intersected and Trusts Encountered were: 3
Current ObjectID: 17496
Parcel FID List: 97
1 parcels intersected and Trusts Encountered were: 3
Current ObjectID: 17500
Parcel FID List: 1011
1 parcels intersected and Trusts Encountered were: 3


SCRIPT SUCCESSFULLY PROCESSED 3948 SALE UNITS IN 0:19:04.009152

Here's the actual script:

 

 

#==============================================================================
# Import python modules
#==============================================================================
import arcpy, os, time
from datetime import timedelta
startTime = time.time()

#==============================================================================
# Link to and establish the required layers specified in the Toolbox dialog
#==============================================================================
theUnits = arcpy.GetParameterAsText(0)
theParcels = arcpy.GetParameterAsText(1)

arcpy.AddMessage('Timber Sale Units: ' + theUnits)
arcpy.AddMessage('Parcels: ' + theParcels)

workspace = 'G:/gis/PlannedSales\/20230907/20230907_pdr_7971.gdb'

# Start an edit session. Must provide the workspace.
edit = arcpy.da.Editor(workspace)
edit.startEditing(with_undo=False, multiuser_mode=True)

# Start an edit operation
edit.startOperation()

#==============================================================================  
# Now let's loop through all of the Timber Sale Units.....
#==============================================================================
theCounter = 0
totalRecordCount = arcpy.GetCount_management(theUnits)

fields = ['OBJECTID', 'tTrusts', 'SHAPE@']
with arcpy.da.UpdateCursor(theUnits,fields) as theCursor:
    for row in theCursor:
        #--------------------------------------------------------------------------
        # Step 1: Unselect all applicable overlay themes & reset any variables ----
        #--------------------------------------------------------------------------
        arcpy.SelectLayerByAttribute_management(theUnits, "CLEAR_SELECTION")
        curTrustList = []
        theCounter = theCounter + 1
                
        #--------------------------------------------------------------------------
        # STEP 2: Get the current sale unit shape ---------------------------------
        #--------------------------------------------------------------------------
        if (theCounter % 100 == 0):
            curTime = time.time()
            totalTime = curTime - startTime
            totalTimeFormatted = "{:0>8}".format(str(timedelta(seconds=totalTime)))
            arcpy.AddMessage("{0} of {1} records processed (elapsed time: {2})..".format(theCounter,totalRecordCount,totalTimeFormatted) )
        curObjectID = row[0] #OBJECTID

        arcpy.AddMessage('Current ObjectID: ' + str(curObjectID))
        
        #--------------------------------------------------------------------------
        # STEP 4: Perform an overlap select against the Stands Polygons -----------
        #--------------------------------------------------------------------------
        SelPoly = arcpy.SelectLayerByAttribute_management(theUnits, "NEW_SELECTION", "\"OBJECTID\" =" + str(curObjectID))
        SelectedFeatures = arcpy.SelectLayerByLocation_management(theParcels, "INTERSECT", SelPoly)
        
        matchcount = int(arcpy.GetCount_management(SelectedFeatures)[0])
        desc = arcpy.Describe(SelectedFeatures)
        arcpy.AddMessage('Parcel FID List: ' + desc.FIDSet)
        
        trustFields = ['TIMBER_TRUST_CD', 'SHAPE@']
        with arcpy.da.SearchCursor(SelectedFeatures,trustFields) as parcelCursor:
            parcelCounter = 0
            curList = []
            for parcelRow in parcelCursor:
                parcelCounter = parcelCounter + 1
                curList.append(parcelRow[0])

            curUniqueList = list(set(curList))
        theTrustList = ",".join(str(element) for element in curUniqueList)
        arcpy.AddMessage(str(matchcount) + ' parcels intersected and Trusts Encountered were: ' + theTrustList)
        row[1] = theTrustList
        theCursor.updateRow(row)     

# Stop the edit operation.
#edit.stopOperation()

# Stop the edit session and save the changes
#edit.stopEditing(save_changes=True) # <== Throws error if uncommented: 'Cannot acquire a lock'
        
endTime = time.time()
totalTime = endTime - startTime
totalTimeFormatted = "{:0>8}".format(str(timedelta(seconds=totalTime)))
arcpy.AddMessage("\n\nSCRIPT SUCCESSFULLY PROCESSED {0} SALE UNITS IN {1}\n\n".format(totalRecordCount, totalTimeFormatted) )

 

 

 

1 Solution

Accepted Solutions
AlfredBaldenweck
MVP Regular Contributor

So uh, dumb question I have to ask:

Did you refresh your table view after running the code? 
A frequent issue with update cursors is that, unlike Field Calculator, the table view looks the same until you refresh. Everything’s worked well, but the updates just haven’t caught up to the UI.

(Although beware if you have the table open while running an update cursor with 200+ records. That will throw a lock error. So best practice honestly is to just run the script with the table closed and open when it completes.)

View solution in original post

7 Replies
DanPatterson
MVP Esteemed Contributor

consider deleting your cursors prior to stopping the edit session.  See the Discussion section in...

UpdateCursor—ArcGIS Pro | Documentation

A "with" statement is no guarantee that locks will be removed


... sort of retired...
0 Kudos
SteveCole
Frequent Contributor

Thanks, Dan. After adding the code to delete the cursors, my initial re-run resulted in no change in the end result. I'm trying to run it a second time but it's taking forever. If I run the script tool inside a project where the two datasets have been loaded into a map inside the project, the script runs in about 18 minutes but has the lock error. In this setup, the two script parameters have a type of "layer".

I'm currenting running the script after starting Pro without a template & manually navigating to the 2 layers (type specified as "dataset" this time) and the script is still running (about 11 hours so far) with a couple hundred records yet to process.

Sigh. "It worked in Arcmap.."

0 Kudos
AlfredBaldenweck
MVP Regular Contributor

So uh, dumb question I have to ask:

Did you refresh your table view after running the code? 
A frequent issue with update cursors is that, unlike Field Calculator, the table view looks the same until you refresh. Everything’s worked well, but the updates just haven’t caught up to the UI.

(Although beware if you have the table open while running an update cursor with 200+ records. That will throw a lock error. So best practice honestly is to just run the script with the table closed and open when it completes.)

SteveCole
Frequent Contributor

No dumb questions here as my distain for Pro is large and it's entirely possible I'm doing something wrong.

The table was open during my initial runs (not the case with my current run in a blank project) and I did hit the refresh button after it ran and used the identify tool and clicked on feature in the map.

The attribute field is still blank.

0 Kudos
SteveCole
Frequent Contributor

I'm using Alfred's reply as the solution because re-running the script tool with the table closed finally resolved my issue with no field values after running the script. That being said, Dan's mention of deleting the cursors prior to stopping the edit session also merited kudos.

Thanks to you both.

0 Kudos
Shauna-RaeBrown
Occasional Contributor

@SteveCole , I seem recall from a python class that you need to "del" your "theCursor" to close the table/layer.  So on line 77 in your script put "del theCursor" at the far left.  You may already know that, but the documentation doesn't really mention anything about deleting cursors, when you're done with that table.  I hope that helps a little.

0 Kudos
SteveCole
Frequent Contributor

Yes, that is what Dan suggested in the first reply of this thread but that alone did not solve the issue I was having. Ultimately, running the script with the table closed is what finally worked for me.

0 Kudos