I am working on creating a addon button to update some address points and copy that updated feature. The first part of the code does what it is suppose to do (only update the selected feature) but the second part of the code doesn't do what it is suppose to do and that is copy "only" the selected feature to the file geodatbase feature class. The code runs fine i don't get any errors but the second part of the codes doesn't copy the selected feature.
I would also like to an an "if" statement. if there is no feature selected i want it to do nothing or tell me there is nothing selected. if there is something selected i want it to only updates the selected feature and only copy the selected feature. Any ideas?
import arcpy, time import pythonaddins import os #populate selected feature APT = "TEST" arcpy.env.overwriteOutput = True mxd = arcpy.mapping.MapDocument("CURRENT") if int(arcpy.GetCount_management(APT).getOutput(0)) > 0: rows = arcpy.UpdateCursor(APT) for row in rows: row.FacltyType = ("Single Family Home") row.StructType = ("Primary, Private") row.Verified = ("Yes, GRM, TA") row.Status = ("Active") row.StructCat = ("Residential") row.APA_CODE = ("1110") rows.updateRow(row) del row, rows #Copies address point to backup address points in filegeodatabase fc1 = "CCAP" #Database workspace = r"C:\GIS\CCAP\CCAP.mdb" arcpy.env.overwriteOutput = True # Start an edit session. Must provide the worksapce. edit = arcpy.da.Editor(workspace) # Edit session is started without an undo/redo stack for versioned data # (for second argument, use False for unversioned data) edit.startEditing(True) # Start an edit operation edit.startOperation() if int(arcpy.GetCount_management(APT).getOutput(0)) > 0: arcpy.Append_management(APT, fc1, "NO_TEST") # Stop the edit operation. edit.stopOperation() # Stop the edit session and save the changes edit.stopEditing(True) arcpy.RefreshActiveView()
Solved! Go to Solution.
Richard, thank you for your help, i gratefully appreciate it.
The reason i have two update cursors is because i need to update "only" the selected features (could be 1 or 20 or 100) of FC layer first with the first arcpy.da.UpdateCursor, then after the attributes have been updated i need to copy over the features that were updated in the first cursor to incidentsFC. I was trying to implement the InsertCursor you suggested and since none of the FC layers get copied over i used another updatecursor.
The FC already has the already has "Account" and "SiteStreet, those are fileds i need to copy over to the incidentFC as well .
The code you posted give me an error;
Runtime error
Traceback (most recent call last):
File "<string>", line 26, in <module>
RuntimeError: unknown geometry token 'SHAPE@CENTROID.X'
import arcpy from datetime import datetime as d startTime = d.now() #set to folder where features are located arcpy.env.workspace = r"C:\GIS\CCAP\CCAP_NEW.mdb" #on windows use \ instead of / arcpy.env.overwriteOutput = True #--------------------------- #define variables for cursor #--------------------------- FC = "test" incidentsFC = "CCAP" parcelsCount = int(arcpy.GetCount_management(FC).getOutput(0)) dsc = arcpy.Describe(FC) rowInserter = arcpy.da.InsertCursor(incidentsFC, ["SHAPE@", 'Account', 'SiteStreet']) selection_set = dsc.FIDSet if len(selection_set) == 0: print "There are no features selected" elif parcelsCount >= 1: with arcpy.da.UpdateCursor(FC, ["FacltyType", "StructType", "Verified", "Status", "StructCat", "APA_CODE", "ACCOUNT", 'SiteStreet', 'SHAPE@CENTROID.X', 'SHAPE@CENTROID.Y']) as rows: for row in rows: row[0] = ("Single Family Home") row[1] = ("Primary, Private") row[2] = ("Yes, GRM, TA") row[3] = ("Active") row[4] = ("Residential") row[5] = ("1110") ACCOUNT = row[6] SiteStreet = row[7] X = row[8] Y = row[9] rows.updateRow(row) inPoint = arcpy.PointGeometry(arcpy.Point(X,Y)) rowInserter.insertRow((inPoint, ACCOUNT, SiteStreet)) del row del rows del rowInserter arcpy.RefreshActiveView() try: print '(Elapsed time: ' + str(d.now() - startTime)[:-3] + ')' except Exception, e: # If an error occurred, print line number and error message import traceback, sys tb = sys.exc_info()[2] print "Line %i" % tb.tb_lineno print e.message
I fixed the code in my previous post. SHAPE@X is the Centroid, so I changed SHAPE@CENTEROID.X and Y to the correct syntax.
I see nothing that indicates that you need another cursor. My code will back up each selected point and should include any attributes of the FC pioint when the point is being inserted through the InsertRow metnod. Note that my code gets the point and ACCOUNT and SiteStreet inserted in one command. If there are other shared fields, just read them from the FC and follow the pattern to insert them while the point feature is being created.
You can insert the point and all attributes of the point at the same time with one insert cursor. The only reason attributes are not being copied is that you are not including the fields in one cursor or the other, either to be read from the updateCursor or to be written to the point being inserted while it is being inserted.
Since I have no idea what your data actually looks like and I cannot divine what you really want, I just made the code do what the code you posted did. If you think your other code did something else point it out.
I assumed you never wanted a back up of points if no selection existed on your FC. If that is not the case, let me know. That is the only thing my code won't do.
After making the correction to the SHAPE@X AND SHAPE@Y the code ran fine. You code make more sense now that i can see it. I did not know that you can use insertRow of one layer inside an updateCursor for a different layer.
I need to copy pretty pretty much every field of the selected point or points to the back up, i was just testing my code and figured that once i got it working i could add the other fields but there are like 50 fields and i would prefer not to have to type every one. I think you touched on this with dictionaries and lists?
Yes, if nothing is selected then i don't need anything backed up.
I have attached a small portion of the feature classes.
Yes, lists are the key to what you want to do. that is why the arcpy.ListFields function returns a list of field objects (not just field names). With two of these lists from different databases you can create a looping structure that is nearly identical to the code I provided to relate the two lists and perform updates. The list of field objects can easily be converted to the list of field names used by the cursors.
So here is some code that should work for relating two field lists for two different data sources using the ListFields function. Since the field lists for both the update cursor and insert cursor match you can use the same row object for the updateRow and InsertRow methods:
import arcpy from datetime import datetime as d startTime = d.now() #set to folder where features are located arcpy.env.workspace = r"C:\Users\OWNER\Desktop\Test" #on windows use \ instead of / arcpy.env.overwriteOutput = True #--------------------------- #define variables for cursor #--------------------------- FC = "test" incidentsFC = "CCAP" FCfields = arcpy.ListFields(FC) incidentsFCfields = arcpy.ListFields(incidentsFC) # Create a field list of fields you want to manipulate and not just copy # All of these fields must be in the incidentsFC manualFields = ["FacltyType", "StructType", "Verified", "Status", "StructCat", "APA_CODE", "ACCOUNT", 'SiteStreet', 'SHAPE@X', 'SHAPE@Y'] matchedFields = [] for manualField in manualFields: matchedFields.append(manualField.upper()) for FCfield in FCfields: for incidentFCfield in incidentsFCfields: # if FCfield.name.upper() == incidentFCfield.name.upper() and \ # FCfield.type == incidentFCfield.type and \ # incidentFCfield.editable() and \ # not FCfield.name.upper() in matchedFields: if FCfield.name.upper() == incidentFCfield.name.upper() and FCfield.type == incidentFCfield.type and incidentFCfield.editable == True and not (FCfield.name.upper() in matchedFields): matchedFields.append(FCfield.name) break parcelsCount = int(arcpy.GetCount_management(FC).getOutput(0)) dsc = arcpy.Describe(FC) rowInserter = arcpy.da.InsertCursor(incidentsFC, matchedFields) selection_set = dsc.FIDSet if len(selection_set) == 0: print "There are no features selected" elif parcelsCount >= 1: with arcpy.da.UpdateCursor(FC, matchedFields) as rows: for row in rows: row[0] = ("Single Family Home") row[1] = ("Primary, Private") row[2] = ("Yes, GRM, TA") row[3] = ("Active") row[4] = ("Residential") row[5] = ("1110") rows.updateRow(row) rowInserter.insertRow(row) del row del rows del rowInserter arcpy.RefreshActiveView() try: print '(Elapsed time: ' + str(d.now() - startTime)[:-3] + ')' except Exception, e: # If an error occurred, print line number and error message import traceback, sys tb = sys.exc_info()[2] print "Line %i" % tb.tb_lineno print e.message
I am getting an error on line 17 "unexpected character after line continuation character.
I believe the forward slashes are erroring out on lines 17, 25-27. I also noticed that some fields in the manualFields list have single quotes and other have double quotes is this correct?
Python doesn't care about double or single quotes, except that they are paired when they enclose a string The slashes are just for readability and according to some posts I read were supposed to act as line continuations. So I have just removed them and put the line break version as a comment so it can be read..
I get the folloing on line 20
Runtime error
Traceback (most recent call last):
File "<string>", line 20, in <module>
AttributeError: 'str' object has no attribute 'name'
Fixed. That was a simple copy paste error that carried over from the list of field objects and incorrectly applied to the list of field name strings. Although I do want to make my post have the code correct, you should also not just report the error, but attempt to figure out what an error like that is telling you and attempt to fix it yourself.
Once this new code works you will need to mark it as the answer for others.
Richard thank your your patience and help. python is not my strong point obviously.
i am not familiar with list. when i first got the error i removed .name from manualField.name.upper but once i removed i got an error on line 35, in TypeError: 'bool' object is not callable. i proceeding to remove all of them from line 28 and got error an line 23, in 'Field' object has no attribute 'upper'. So i didn't understand the error so that's why i posted the error i got. i am still stuck on the error.
Thanks.
I believe that error occurred, because I just put "incidentFCfield.editable() and " and did not put "incidentFCfield.editable() == True and..." Try the revised code from my post again. The name property is not the problem and this is not a list issue, it is a field object property and expression issue.