I am currently attempting to create a Python Add_in tool which will perform a set of geoprocessing operations resulting in new values for a specific !shape.area!acres calculation on a new layer and then update rows in an existing feature class with these new values. I am using da.UpdateCursor as my edit tool to update the rows in the feature class from a dictionary of the new values. Basically, my script runs through all of the geoprocessing operations just fine and then either stops or skips over the da.UpdateCursor w/out throwing any errors. The last MessageBox trap that fires is right before the edit.startEditing, after that the code stops in the mxd w/ no errors.
I am open to any suggestions as to modifying the process as I am still fairly new to python programming and many of you might find my methods a little clunky. Also, this a trial tool for intended for later use on a versioned Feature Class in SDE once I get the process and methods understood.
I am using ArcGIS 10.2.1 for Desktop, with Windows 7.
# Import arcpy module
import arcpy, traceback
import pythonaddins
import os, sys
from arcpy import env
arcpy.env.overwriteOutput = True
arcpy.env.addOutputsToMap = False
workspace = r'C:\TEST\GEODATABASE.mdb'
arcpy.env.workspace = workspace
edit = arcpy.da.Editor(arcpy.env.workspace)
class Net_Stands(object):
"""Implementation for Net_Stands_addin.button (Button)"""
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
try:
self.mxd = arcpy.mapping.MapDocument('current')
df = self.mxd.activeDataFrame
layers = arcpy.mapping.ListLayers(self.mxd)
Stands = arcpy.mapping.ListLayers(self.mxd, "StandsMaintenance", df)[0]
CompanyRoads = arcpy.mapping.ListLayers(self.mxd, "roads", df)[0]
layers = arcpy.mapping.ListLayers(self.mxd)
#creates Stands layer as temp Stands_lyr
arcpy.MakeFeatureLayer_management(Stands,"Stands_lyr")
#defines layer as temp Stands_lyr
Stands_temp = arcpy.mapping.Layer("Stands_lyr")
#creates a NetStands_Temp to cut the roads_buffer out of
arcpy.MakeFeatureLayer_management(Stands_temp, "NetStands_Temp")
#defines layer as temp NetStands_Temp
NetStands_Temp = arcpy.mapping.Layer("NetStands_Temp")
#From the roads feature class in the mxd, it makes a temp TRACT_BOUNDARY in the mxd.
arcpy.MakeFeatureLayer_management(CompanyRoads,"CompanyRoads_lyr")
#defines layer as temp TRACTS_BOUNDARY
CompanyRoads_temp = arcpy.mapping.Layer("CompanyRoads_lyr")
#Calculates the buffer distance based on value in Row_Feet into meters
arcpy.CalculateField_management(CompanyRoads_temp,"ROW_METERS_HALF","!ROW_FEET! * 0.1524","PYTHON_9.3","#")
#creates the buffer layer based on CompanyRoads_temp
mybuffer = arcpy.Buffer_analysis(CompanyRoads_temp,"#","ROW_METERS_HALF","FULL","ROUND","ALL","#")
#Erases the area that from mybuffer that overlap with Stands_temp
Erase_FC = arcpy.Erase_analysis(Stands_temp, mybuffer.getOutput(0))
#Recalculates the polygon shape since the roads buffer has been erased
arcpy.CalculateField_management(Erase_FC.getOutput(0),"NET_ACRES","!shape.area@acres!","PYTHON_9.3","#")
#Marker, this is the last line of code that works.
saysomething = pythonaddins.MessageBox("Completed Net_Acres Processing", "Clicked", 0)
print saysomething
#Start Editing
edit.startEditing(True,False)
edit.startOperation()
try:
joinfields = ['STID', 'NET_ACRES']
joindict = {}
with arcpy.da.SearchCursor(out_fc, joinfields) as rows:
for row in rows:
#joindict.append(row[0]),joindict.append(row[1])
joinval = row[0]
val1 = row[1]
joindict[joinval]= [val1]
print pythonaddins.MessageBox((row[0]) + " " + str(row[1]) + " joindict", "Joindict", 1)
del row, rows
with arcpy.da.UpdateCursor(Stands, joinfields) as recs:
for rec in recs:
keyval = rec[0]
if joindict.has_key(keyval):
print pythonaddins.MessageBox((rec[1]) + " rec" + str(rec[1]) + " rec"+ str(joindict[keyval]) + " joindict", "In the Update", 1)
rec[1] = joindict[keyval]
#print rec
recs.updateRow(rec)
del rec, recs
except Exception, e:
# If an error occurred, print line number and error message
tb = sys.exc_info()[2]
print pythonaddins.MessageBox("Line %i" % tb.tb_lineno)
print pythonaddins.MessageBox(e.message)
#print e.message
exceptions = pythonaddins.MessageBox(arcpy.GetMessages())
print exceptions
edit.stopOperation()
edit.stopEditing(True)
print pythonaddins.MessageBox("complete")
arcpy.RefreshActiveView()
arcpy.RefreshTOC()
arcpy.Delete_management(out_fc)
arcpy.Delete_management(Erase_FC)
arcpy.Delete_management(mybuffer_temp)
code_errors = pythonaddins.MessageBox(arcpy.GetMessages(), "Code Errors", 1)
print code_errors
except arcpy.ExecuteError:
lasterrors = pythonaddins.MessageBox(arcpy.GetMessages(), "WTF_Except Errors",1)
print lasterrors
Best Answer
After many trials and tribulations, I have got a working code with many bells and whistles that I feel obliged to share since they are a culmination of many 'stolen' snippets obtained from this site. I have included comments in much of the script to describe what is going on, so hopefully that is helpful. Basically, I was able to get both a arcpy.UpdateCursor and a arcpy.da.UpdateCursor to work. One of the trickiest aspects was for the code to be able to edit a workspace that was dynamic, in that if they were direct editing a Versioned SDE or if they had 'Checked Out' their data from SDE and working locally. The code had to account for this, but not all of my wishes were granted. The code will kick back a message if the user is NOT in edit mode already ONLY when in SDE. If they are using a local GDB, then the code still runs, but the edits are essentially not written...The new numbers appear in the attribute table, however, if you 'Reload Cache', they revert back and the edits aren't saved regardless. If already the user has already initiated an edit session, the edits aren't saved until the user "Saves Edits". Furthermore, if the SDE connection is not the 'hard coded' SDE_versioned Connection I'm assuming, a DialogMessage will appear for them to choose the Database Connection which must match the intended lyr. If not, it will loop until they choose the correct one. Also, this is all done "in_memory" and is lightening fast when run on a local GDB. So here goes: