Python UpdateCursor & CalculateField working together

3935
13
Jump to solution
07-31-2015 07:54 PM
CoyPotts1
Occasional Contributor III

I have a script that I recently created an alternate copy of and updated many of the calculate field functions to make use of UpdateCursor.  When I run the original script, all runs through just fine, but whenever I try to run the alternate version, the tool gets hung up on any of the parts that are still in CalculateField format.  Is there a known issue with mixing UpdateCursors and CalculateField functions within the same script?  Is there a common procedure that needs to be followed to do so?  Sample code below. 

Other than changing from CalculateField to UpdateCursor, the only other difference that I see that I made was moving some of the variables into the functions as global variables so I could use them outside of the function (I think I had to anyway...these sections started working after I did so).

#########################
# Calculate Region
#########################

# Start message
arcpy.AddMessage("Determining the correct region field to be updated for all node features...")

# Set local variables
inTable = nodeFeatures
cursor = arcpy.UpdateCursor(inTable)

# Determine the correct region field to update
def Get_node_regionField():
    global node_regionField
    if carrier == "CUST1":
        node_regionField = "CUST1Region"
    elif carrier == "CUST2":
        node_regionField = "CUST2Region"
    elif carrier == "CUST3":
        node_regionField = "CUST3Region"
    elif carrier == "CUST4":
        node_regionField = "CUST4Region"
    elif carrier == "CUST5":
        node_regionField = "CUST5Region"
    else:
        pass
Get_node_regionField()

# Execute UpdateCursor
for row in cursor:
    row.setValue(node_regionField, region)
    cursor.updateRow(row)

# End message
arcpy.AddMessage("The " + carrier + " region field has been updated for all node features!")
arcpy.AddMessage("...")
arcpy.AddMessage("...")

Each one of these IF statements used to be its own CalculateField (I didn't know how to incorporate them all into one, as I do above using the UpdateCursor method).  The above code works just fine.  I originally had the "node_regionField" variable as "inField", but there was an issue with doing so since I used inField for multiple other UpdateCursors.  I'm assuming it had something to do with the fact that it is a global variable...?  Not sure.  Comment on that if you know, but the real issue is below:

#########################
# Calulate latitude
#########################

# Start message
arcpy.AddMessage("Calculating the latitude values for all node features...")

# Set local variables
inTable = nodeFeatures
inField = "Latitude"
expression = "!Shape.Centroid.Y!"

# Execute CalculateField
arcpy.CalculateField_management(inTable, inField, expression, "PYTHON_9.3")


# End message
arcpy.AddMessage("The latitude values have been calculated for all node features!")
arcpy.AddMessage("...")
arcpy.AddMessage("...")

This code will not run, and all it does is return a generic 99999 error code:

"Traceback (most recent call last):

  #my python script filepath#

    arcpy.CalculateField_management(inTable, inField, expression, "PYTHON_9.3")

  File "c:\program files (x86)\arcgis\desktop10.2\arcpy\arcpy\management.py", line 3354, in CalculateField

    raise e

ExecuteError: ERROR 999999: Error executing function.

Failed to execute (CalculateField)."

This error code doesn't really tell me much.  The weirdest thing is that it still works (copied identically) in the script that utilizes all CalculateField functions.  I have 2 sections that calculate longitude, 2 that calculate latitude, 1 that calculates feet, 1 for meters, and 1 for miles.  All 7 of them are constructed the same, and all 7 generate the same error message while in the mixed script, and all 7 work just fine in the all CalculateField version.

Side note...if the !shape.centroid@y! can be done using the UpdateCursor method (I couldn't figure out how), I would much rather that anyway.

0 Kudos
1 Solution

Accepted Solutions
ModyBuchbinder
Esri Regular Contributor

Hi

You should use the da.UpdateCursor and use the "with" keyword (see docs).

Then the cursor  close and release the table after it finished.

Then you can use the calculate.

In your code the cursor is not closed

Have fun

Mody

View solution in original post

13 Replies
WesMiller
Regular Contributor III

See this thread it has an example of populating fields Lat Lon populate x,y  if you need a more straight forward example I'd be glad to help. Your first script, I don't see where your are declaring what carrier is but instead of the if elif statements  i would use a dictionary see below.

carrierdict = {"CUST1":"CUST1Region","CUST2":"CUST2Region"}
if carrier in carrierdict:
  carrier = carrierdict[carrier]
else:
  arcpy.AddMessage("carrier not in dict")
CoyPotts1
Occasional Contributor III

Thanks for the helpful information, Wes.  Looking at the link that you provided, I'm not really sure what's going on.  From what I can tell the script allows the user to place the points and then the X/Y is auto-generated?

The carrier field is derived earlier in the script.  I do believe, though, that the dictionary method that you reference above would work nicely instead of the way that I was doing it.  Although your method does seem to be a quicker way to do it, the way I am doing it does work...it's the second code that I can't get to work. 

As I mentioned in the original post, the second script works when used in my script that utilizes ALL calculate field methods.  It's only when I try to use it while mixed in with UpdateCursors as well.  I'm not sure if there is something between the two that throws one off or what.  The theories that I can think of are the fact that I'm using global variables, maybe using UpdateCursors and CalculateField together in the same script creates some sort of conflict, or possibly the mix of the two creates a conflict between 32bit and 64bit processing...not sure.  Those theories may not even hold water, but they're the only things I could think of when trying to figure out why it wouldn't run properly.

0 Kudos
ModyBuchbinder
Esri Regular Contributor

Hi

You should use the da.UpdateCursor and use the "with" keyword (see docs).

Then the cursor  close and release the table after it finished.

Then you can use the calculate.

In your code the cursor is not closed

Have fun

Mody

CoyPotts1
Occasional Contributor III

I actually do use .da in other examples...maybe not in this exact script, though.  I don't have access to that script to double check at this time, as it's on a different machine.  If I use the .da version of UpdateCursor for every instance of UpdateCursor that I use, it will release the table for edits by other functions, such as CalculateField in my example?

If that is indeed the case then there is a conflict between using the two methods together, and it is corrected by using the .da version, correct?  Just trying to make sure I am understanding you correctly.

Thanks!

0 Kudos
ModyBuchbinder
Esri Regular Contributor

The old cursor has a problem with release. It can be solved but it not always works.

When you use the "with" keyword with da cursors it's releasing the resources much better and it is also faster.

This should be always the way, no reason to use old cursors.

WesMiller
Regular Contributor III

Here is a more straight forward example below. I don't see where you are deleting your cursor in your first script. That may be why your second is not working.

import arcpy


fc = "your feature class here"


ucur = arcpy.da.UpdateCursor(fc,["Shape@XY","Latitude"])
for row in ucur:
    x,row[1] = row[0]
    ucur.updateRow(row)
del row, ucur
    
Zeke
by
Regular Contributor III

If you use the 'with' construction, you don't have to worry about deleting cursors:

with arcpy.da.UpdateCursor(fc,["Shape@XY","Latitude"])  as ucur:
    x,row[1] = row[0
    ucur.updateRow(row) 
WesMiller
Regular Contributor III

He's not using with in his script he 's using for

0 Kudos
BlakeTerhune
MVP Regular Contributor

You can use both, I think Greg Keith just forgot to add it in his code sample.

with arcpy.da.UpdateCursor(fc,["Shape@XY","Latitude"]) as ucur:
    for row in ucur:
        x,row[1] = row[0]
        ucur.updateRow(row)