1
import arcpy
import os.path
arcpy.env.workspace = "C:/Users/melis/Documents/HenryWork.gdb"
arcpy.env.overwriteOutput = True
buffer = "LS_buffer"
landcov = "ForestLC_clip"

#create search cursor to access table. may need to change field name with other data.
buffCursor = arcpy.da.SearchCursor(buffer, ["buff_id"])

for row in buffCursor:
    #select one buffer
    query = """ "buff_id" = %s """ %row[0]
    arcpy.SelectLayerByAttribute_management(buffer, "NEW_SELECTION", query)

    #define clip out path
    clip_out = "LS" + str(row[0])

    #clip w one buffer
    arcpy.Clip_analysis(landcov, buffer, clip_out)

    #add fields to clip_out
    arcpy.AddField_management(clip_out, "clip_id", "TEXT", 20)
    arcpy.AddField_management(clip_out, "area_ha", "FLOAT")

    #create updatecursor for new clip_out
    clipCursor = arcpy.da.UpdateCursor(clip_out, ["clip_id", "area_ha"])

    for polys in clipCursor:

        #calc geom for area ha
        exp = "!SHAPE.AREA@HECTARES!"
        arcpy.CalculateField_management(clip_out, "area_ha", exp, "PYTHON_9.3")

        #field calc for buffer id
        polys[0] = row[0]

del clipCursor

The code works all the way down to the first calculate field, and then I get the error: "Cannot acquire a lock". However, when I test whether I can acquire a lock on that feature class (the new clip_out ("LS1"), I get a "True".

arcpy.TestSchemaLock("LS1")
True

Any idea why the cursor code can't acquire a lock, but when outside the code, I can acquire the lock?

  • 4
    Probably because you are using CalculateField inside an UpdateCursor. Normally you would do use one or the other, not both at the same time. – Andy Dec 24 '18 at 0:09
3

As @Andy said, you're using calculate field in a double cursor loop, it's the cursor that's locking the calculate field.. instead try it like this:

#create search cursor to access table. may need to change field name with other data.
with arcpy.da.SearchCursor(buffer, ["buff_id"]) as buffCursor:
    for row in buffCursor:
            #select one buffer
            query = """ "buff_id" = %s """ %row[0]
            arcpy.SelectLayerByAttribute_management(buffer, "NEW_SELECTION", query)

            #define clip out path
            clip_out = "LS" + str(row[0])

            #clip w one buffer
            arcpy.Clip_analysis(landcov, buffer, clip_out)

            #add fields to clip_out
            arcpy.AddField_management(clip_out, "clip_id", "TEXT", 20)
            arcpy.AddField_management(clip_out, "area_ha", "FLOAT")

            #create updatecursor for new clip_out
            with arcpy.da.UpdateCursor(clip_out, ["clip_id", "area_ha","SHAPE@AREA"]) as clipCursor:
                for polys in clipCursor:

                    #calc geom for area ha
                    polys[1] = polys[2].area / 10000 # A hectare is 10000 square metres

                    #field calc for buffer id
                    polys[0] = row[0]
                    clipCursor.updateRow(polys) # IMPORTANT don't forget to commit the update

I've changed your cursors to with blocks, this handles the removing when the cursor passes out of scope. I am assuming here that your data is in a spatial reference with units in metres, see this post about other units (like feet) for a simple conversion but if your data is in geographical units you can choose a suitable projected coordinate system (for example WGS84 UTM Zone 55 south, EPSG code 32755) and project the geometry on the fly:

CalcSR = arcpy.SpatialReference(32755) # declare this outside the loop using EPSG code
with arcpy.da.UpdateCursor(clip_out, ["clip_id", "area_ha","SHAPE@"]) as clipCursor:
    for polys in clipCursor:
        #calc geom for area ha, project to UTM and calculate from the area
        polys[1] = polys[2].projectAs(CalcSR).area / 10000 # A hectare is 10000 square metres

        #field calc for buffer id
        polys[0] = row[0]
        clipCursor.updateRow(polys) # IMPORTANT don't forget to commit the update

Either way though the use of a cursor-in-cursor loop is discouraged, it's better to build a list and then iterate:

#create list to access table. may need to change field name with other data.
# builds a list of all buff_id values... you might want to do something about
# removing duplicates but this works as an example
AllBuffID = [r[0] for r in arcpy.da.SearchCursor(buffer, ["buff_id"])]

for thisBuffID in AllBuffID:
        #select one buffer
        query = """ "buff_id" = %s """ %thisBuffID
        arcpy.SelectLayerByAttribute_management(buffer, "NEW_SELECTION", query)

        #define clip out path
        clip_out = "LS" + str(thisBuffID)

        #clip w one buffer
        arcpy.Clip_analysis(landcov, buffer, clip_out)

        #add fields to clip_out
        arcpy.AddField_management(clip_out, "clip_id", "TEXT", 20)
        arcpy.AddField_management(clip_out, "area_ha", "FLOAT")

        #create updatecursor for new clip_out
        with arcpy.da.UpdateCursor(clip_out, ["clip_id", "area_ha","SHAPE@"]) as clipCursor:
            for polys in clipCursor:
                #calc geom for area ha, project to UTM and calculate from the area
                polys[1] = polys[2] / 10000 # A hectare is 10000 square metres

                #field calc for buffer id
                polys[0] = thisBuffID
                clipCursor.updateRow(polys) # IMPORTANT don't forget to commit the update
  • thanks for the thoughtful answer. I finally had some time to get back to this and have a followup question. I got an error at line 30 (polys[1] = polys[2] / 10000). I changed it to polys[1] = (polys[2].area) / 10000, which fixed the error. However, there's another error I can't fix. It only went through one iteration of the for loop and then stopped, meaning I only got one feature class output called "LS1". How do I get it to give me the rest? Thanks – Melissa Jan 4 at 20:21
  • Well spotted, you're right. The script is written for a single iteration, to do all feature classes in a workspace set your arcpy.env.workspace to the folder/gdb you need to loop through and use for buffer in arcpy.ListFeatureClasses(feature_type='Polygon'): (don't forget to indent the code) to iterate all of the polygon feature classes. Have a look at the examples resources.arcgis.com/en/help/main/10.2/index.html#//… and if you are still having problems post a new question with a link to this post. – Michael Stimson Jan 7 at 0:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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