Problem with UpdateCursor - cannot updagte table

3078
11
09-15-2023 10:55 AM
MarcSeliger
Emerging Contributor

Hi all.

I'm running into a problem with an UpdateCursor in arcpy.
As soon as the script is encountering the UpdateCursor line, it ends with an error "Cannot update table".

I can run a SearchCursor over the feature class without problems, just the UpdateCursor fails every time.

This is the (very simplified) code I'm looking at:

connection = "C:\\Users\\user_name\\AppData\\Roaming\\ESRI\\Desktop10.8\\ArcCatalog\\database.gds\\Utilities (VERSION:dbo.DEFAULT)"
fc = "CV_Valves"
fc_path = f"{connection}\\{fc}"

edit = arcpy.da.Editor(connection)
edit.startEditing(False, True)
edit.startOperation()

with arcpy.da.UpdateCursor(fc_path, "OBJECTID") as cursor:
for row in cursor:
print(row[0])
# cursor.updateRow(row)

edit.stopOperation()
edit.stopEditing(True)

I have the updateRow line commented out for testing purposes, and the actual user_name and db name are replaced by placeholders. I realize that the code is not updating anything, and this is just show the error I'm running into. I'm running Python 3.9

I'm not sure if this has something to do with the SDE I'm connecting to, because the code is simple enough where it shouldn't throw any errors. The same procedure works fine when I connect to an SDE DB on a different system. As I mentioned above, I can run a SearchCursor over the same table without any issues.

Any help or pointers would be greatly appreciated.

Thanks!

Mard

Tags (3)
11 Replies
HaydenWelch
Frequent Contributor

This is definitely a permissions issue, is the user in the connection file allowed to edit the features you're accessing? If you can use search, but not update this is probably what's causing the error because that exception is being thrown before the cursor is even initialized.

0 Kudos
MarcSeliger
Emerging Contributor

Hayden,

thanks for the quick response. I'm not at the machine that is running the code right now, but I'll double check on that next week However, when I looked at the content in ArcCatalog using the same SDE connection as in my script, and then dragged the feature class into ArcMap, I was able to make edits and save them. I've never experienced this error before. If it actually is a permission issue, what do I need to do to resolve this?

Thanks!!

 

HaydenWelch
Frequent Contributor

I'm not actually sure what to do as I mostly deal with the GDB format in my projects. The fact that your script is throwing an error before the cursor enters the table is the only thing that's tipping me off. If the error had something to do with updating a row incorrectly, it would be thrown on the cursor.updateRow line.

Is the permissions in gds connection files linked to the active machine? Or maybe you need to enable undo when connecting to an SDE? I'd try double checking your connection permissions and maybe trying to enable undo in the edit session.

Here's how I would structure that same code:

 

import arcpy

connection = r"<CONNECTION PATH>"
fc = "CV_Valves"
fc_path = f"{connection}\\{fc}"

with arcpy.da.Editor(connection, with_undo=True, multiuser_mode=True) as edit:
    edit.startOperation()
    with arcpy.da.UpdateCursor(fc_path, ["OID@"]) as upd_cur:
        for row in upd_cur:
            print(f"Updating OID {row[0]}")
            upd_cur.updateRow(row)
    edit.stopOperation()

 

 

0 Kudos
RPGIS
by
Frequent Contributor

Hi @MarcSeliger ,

A couple of things.

First, you typically don't edit the 'OBJECTID' field simply because that is merely an automated id that is added every time a new record is inserted into the table. You would typically any use any other field(s) for the update. You can use a search cursor or insert cursor for the 'OBJECTID' but that would be about it.

Second, you can get the file path in pro by going into the catalog, selecting the feature class you want to update, and then copy the file path using Ctrl + Alt + P to get the full path.

Third, the reason that you might not be able to update the other feature class is due to permission issues on the database or there might be a schema lock due to someone else editing.

You should be able to also check the database to see if anyone else is potentially editing.

I have also included a script that I have used to streamline editing that may or may not help.

 

import arcpy, os
from arcpy import ListFields
from arcpy.da import (
    Editor, SearchCursor, UpdateCursor, InsertCursor
    )

UpdateFeatureClass = r'{ file path of the specified feature class or shapefile }'
SearchFeatureClass = r' { file path of the feature with object ids to update the other feature class }'

OIDField = ['OID@']
UpdateFeatureClassFields = [ field.name for field in ListFields( UpdateFeatureClass ) ] 
SearchFeatureClassFields = [ field.name for field in ListFields( UpdateFeatureClass ) ] 
# You can insert an if statement at the end if you need to get specific fields with particular names, types, or other field descriptions

# Optional matching fields
MatchingFields = list( set(UpdateFeatureClassFields).intersection(set(SearchFeatureClassFields)))

# update dictionary
UpdateRecords = { }
# search fields
MatchingFields = OIDField + MatchingFields
# specify search cursor
Searching = SearchCursor( SearchFeatureClass, MatchingFields )
with Searching as cursor:
    for row in cursor:
        UpdateRecords [ row[0] ] = row[1:]
# you can also use the search cursor in a single line as well if you did not know that
# UpdateRecords = { row[0]:row[1:] for row in Searching }

# update cursor
Updating = UpdateCursor( UpdateFeatureClass , MatchingFields )
# parent directory
ParentDirectory = os.pardir( UpdateFeatureClass )
# start editing featureclass
with Editor(ParentDirectory) as editor:
    with Updating as cursor:
        for row in cursor:
            if row[0] in UpdateRecords:
                recordupdates = UpdateRecords[ row[0] ]
                cursor.updateRow(recordupdates)

 

 

 

I am not quite sure what you are after but this should help depending on what you are trying to do.

0 Kudos
MarcSeliger
Emerging Contributor

Thanks for your reply.
This is just to show the error that I'm encountering. The UpdateCursor is part of a larger script that will eventually update UniqueID numbers in a different field.
I'm not trying to update any OBJECTIDs, I just wanted this (very simplified) example to do something, and the outcome is the same, whether I actually update data or just print the OID on the screen: the program fails with the error message "unable to update table"

Marc

0 Kudos
RPGIS
by
Frequent Contributor

It might either be a schema lock issue or a permissions issue. I have encountered those before and it is something that will prevent you from editing the table using any script.

AlfredBaldenweck
MVP Regular Contributor

If your data is versioned, that might be your problem.

To quote myself:

Update Cursors and versioned feature classes really don't mix.

You either have to open an edit session in arcpy (gross) or do the easier thing, which is to go through with a search cursor, create a dictionary of correct values, and then field calculate at the very end.

MarcSeliger
Emerging Contributor

Alfred,
how is using the field calculator (arcpy.management.CalculateField) different compared to using an update cursor? Wouldn't it throw the same or a similar error when I'm trying to update the field?

Marc

0 Kudos
AlfredBaldenweck
MVP Regular Contributor

Nope. So long as you have edit access to the data, you should be able to Field Calculate with no issue; the issue is specific to update cursors. 

Caveat here is whenever I'm working with versioned data, I'm using the python window to access a layer in my map, rather than accessing the datasource directly. (Connecting to an enterprise GDB outside of a map makes my head spin lol).

This was something I wrote a bit ago. We mass-added records to monitoring tables but didn't have anything set up to relate the records together; when appending into a table, the relIDs don't populate. So I wrote this to populate the relIDs based on the shared nestID in each table.

Further caveat is that I do not use a best practice here: it is not advised to nest cursors like I did. It did work, though, and now I know better.

aprx = arcpy.mp.ArcGISProject("CURRENT")
mp = aprx.activeMap
tbl = mp.listTables("RaptorMonitoring")[0]
lay = mp.listLayers("NestPoints")[0]

valDict = {}
checkList =[]
with arcpy.da.SearchCursor(tbl, ['Nest_ID','UUID']) as cursor:
    for row in cursor:
        #print(row[0])
        clause= f"Nest_ID = {row[0]}"
        with arcpy.da.SearchCursor(lay, ['Nest_ID', 'GlobalID']) as c2rsor:
            for r2w in c2rsor:
                #print(r2w[0])
                if(r2w[0] == row[0]):
                    valDict[row[0]] = r2w[1]
                if (r2w[0] == f"0{row[0]}"):
                    checkList.append(r2w)

#print(valDict)
#print("Checklist: ", checkList)
arcpy.management.CalculateField(tbl, 
                                'UUID', 
                                f"valDict.get(!Nest_ID!, !UUID!)", 
                                expression_type= 'PYTHON3')

 

 Anyway, I beat my head against the update cursor a bunch before giving up, especially when dealing with opening an edit session. Calculating from a dictionary works great.

0 Kudos