Python add in- update two fields in one feature based on same fields of another

8061
43
Jump to solution
04-14-2014 11:10 AM
AndrewMosley
Emerging Contributor
I'm totally new to making add ins and quite novice at python itself but I have a script that executes perfectly as a script tool or simply in the python window of ArcMap. I want to make this a quick button click so I looked into making an add-in toolbar with a button.

Just to get the hang of making the addin i made a print "Hello World!" that works as expected.

However, it seems something is going wrong with my code when put into the add-in. I can only assume I'm missing some syntax due to my inexperience with python.

The situation here is I have a percels layer and an address points layer, which both contain a PIN and TMS number. I simply want to have the function select the address points within the parcel geometry, find the value of PIN and TMS from the parcel layer's attribute table, and update the same fields in the address points' attribute table. Again, the script I've written executes perfectly inside the python console in ArcMap but not as an add-in. Thanks for any hints you all might have!

So here's what I've got:

import arcpy import pythonaddins  class BlueBird(object):     """Implementation for BlueBird.button (Button)"""     def __init__(self):         self.enabled = True         self.checked = False     def onClick(self): arcpy.SelectLayerByLocation_management("Address Points","COMPLETELY_WITHIN","Parcels")  #insert if statement checking that only one parcel is selected to prevent selecting all address points  with arcpy.da.SearchCursor("Parcels",'PIN') as cursor:  for row in cursor:   storedPIN = row[0] with arcpy.da.UpdateCursor("Address Points",'PIN') as cursor:  for row in cursor:   row[0] = storedPIN   cursor.updateRow(row)  del cursor  with arcpy.da.SearchCursor("Parcels",'TMS') as cursor:  for row in cursor:   storedTMS = row[0] with arcpy.da.UpdateCursor("Address Points",'TMS') as cursor:  for row in cursor:   row[0] = storedTMS   cursor.updateRow(row)  del cursor, storedPIN, storedTMS
Tags (2)
0 Kudos
43 Replies
TonyAlmeida
MVP Regular Contributor

I am trying to implement this into my  data but i am getting an error and i am not sure why i am getting this.

I am receiving an error on line 42...

Any help would be great.

import arcpy 

import os 

import pythonaddins 

 

# Assign string literal layer names to variables to make them easier to change with just one line of code. 

# Good practice for template code that you may not want to do a search and replace to adapt it for new layers. 

parcels = "Taxparcels" 

addressPoints = "CCAP" 

#Get the current map document and the first data frame. 

mxd = arcpy.mapping.MapDocument('current') 

df = arcpy.mapping.ListDataFrames(mxd)[0] 

#Check to make sure user had at least one parcel selected. 

parcelsCount = int(arcpy.GetCount_management(parcels).getOutput(0)) 

if 0 < parcelsCount < 2: 

    

    lyr = arcpy.mapping.ListLayers(mxd, addressPoints, df)[0] 

    workspace = lyr.workspacePath 

    # Start an edit session. Must provide the workspace. 

    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() 

    #Select Address Points within selected parcel 

    arcpy.SelectLayerByLocation_management(addressPoints, "HAVE_THEIR_CENTER_IN", parcels) 

    with arcpy.da.SearchCursor(parcels, ['ACCOUNT','SiteStreet']) as singleCursor: 

        for singleRow in singleCursor: 

            ACCOUNT = singleRow[0] 

            SiteStreet = singleRow[1] 

    with arcpy.da.UpdateCursor(addressPoints, ['Account', 'SiteStreet']) as singleCursor: 

        for singleRow in singleCursor: 

            singleRow[0] = Account 

            singleRow[1] = SiteStreet 

            singleCursor.updateRow(singleRow) 

    # Stop the edit operation. 

    edit.stopOperation() 

    print('Parcel address update is complete.') 

elif 1 < parcelsCount < 1000: 

    #Create in memory parcel layer 

    selectedParcels = arcpy.MakeFeatureLayer_management(parcels, "selectedParcels") 

    for lyr in arcpy.mapping.ListLayers(mxd, "", df): 

        if lyr.name == addressPoints: 

            addressLayer = lyr 

        if lyr.name == parcels: 

            parcelsLayer = lyr 

    workspace = addressLayer.workspacePath 

    # Start an edit session. Must provide the workspace. 

    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() 

    with arcpy.da.SearchCursor(parcels, ['ACCOUNT', 'SiteStreet', 'OBJECTID']) as parcelCursor: 

        for parcelRow in parcelCursor: 

            ACCOUNT = parcelRow[0] 

            SiteStreet = parcelRow[1] 

            OID = parcelRow[2] 

            OID = str(OID) 

            arcpy.SelectLayerByAttribute_management("selectedParcels", "NEW_SELECTION", "OBJECTID= "+OID) 

            #Select Address Points by location, within selected Parcels. 

            arcpy.SelectLayerByLocation_management(addressPoints,"HAVE_THEIR_CENTER_IN","selectedParcels") 

            with arcpy.da.UpdateCursor(addressPoints, ['Account', 'SiteStreet']) as addressCursor: 

                for addressRow in addressCursor: 

                    addressRow[0] = Account 

                    addressRow[1] = SiteStreet 

                    addressCursor.updateRow(addressRow) 

    del ACCOUNT, SiteStreet

    # Stop the edit operation. 

    edit.stopOperation() 

    arcpy.Delete_management("selectedParcels") 

    print('Parcel address update is complete.') 

else: 

    print('Please select a valid number of parcels.')

0 Kudos
RichardFairhurst
MVP Alum

Your ACCOUNT variable name is not consistently using the same upper case spelling.  It does not matter that the spelling changes in the data sources for the field, this variable must have the same spelling when being read and being assigned between the two data sources.  Try changing line 43 from:

            singleRow[0] = Account   

To

            singleRow[0] = ACCOUNT  

Also, are you certain that at least one address point exists within the parcel you chose as your test case?

0 Kudos
TonyAlmeida
MVP Regular Contributor

Thanks for the quick replay.

The address points have an attribute of "Account".

the taxparcels have an attribute of "ACCOUNT", all upper case.

I changed the line

singleRow[0] = Account   

To

singleRow[0] = ACCOUNT  

I still get the same error.

Yes there is one address point within the taxparcels that is selected.

0 Kudos
RichardFairhurst
MVP Alum

So what else does the error say, other than that it occurred on line 42?  An error normally would say something about the cause, like invalid use of unassigned variables, lack of edit rights, or some other problem that caused the error.

0 Kudos
TonyAlmeida
MVP Regular Contributor

that would definitely help, my bad.

Runtime error

Traceback (most recent call last):

  File "<string>", line 42, in <module>

RuntimeError: The operation is not supported within an edit session.

0 Kudos
RichardFairhurst
MVP Alum

That is a new one.  I have heard of the error where it won't let you use an Update cursor outside of an edit session, but not where it was prohibited by an edit session.  Does it let you process the cursor outside of an edit session (comment out all editor lines which all have the edit variable in them)?

Is it SDE data?  If so is it versioned or unversioned?  If it is unversioned SDE data then you have to change line 28 and line 70 to:

    edit.startEditing(False)

Is the address point layer a simple point layer?  Is it associated with a topology, geometric network, or some other complex layer type?

You have to look at exactly what configuration of database and feature class this data is set up to be in order to figure out how to structure this code.  It was written with only SDE versioned simple feature classes.in mind.  Other data configurations may need other code configurations.

There is also a chance that the editor should be tested to see if it is already open for editing before attempting to open this data for editing.  You did not set up an edit session in ArcMap before you ran this code I hope.

0 Kudos
TonyAlmeida
MVP Regular Contributor

The data i was working with was just shapefiles and after i commented out the editor lines it ran fine.

The data I will be working is in a SQL Sever Enterprise Geodatabase on my desktop so because the dataset is not registered as versioned with the database i had to change this line

edit.startEditing(True,False)

I did how ever run into something weird. I select a parcel that has an address point and run the code it runs fine. The attributes get updated but if i select a different parcel with an address point and run the code again it updates the current select features attribute but the previous address points attributes get deleted...some how the first address point attributes doesn't save...?

I also noticed that when i exit the mxd and reopen. The last address point didn't save, i check the attributes and it's blank/null.

Here is what i am working with.

import arcpy 

import os 

import pythonaddins 

 

# Assign string literal layer names to variables to make them easier to change with just one line of code. 

# Good practice for template code that you may not want to do a search and replace to adapt it for new layers. 

parcels = "Taxparcels" 

addressPoints = "TonyTwoWay.DBO.CCAP_Test" 

#Get the current map document and the first data frame. 

mxd = arcpy.mapping.MapDocument('current') 

df = arcpy.mapping.ListDataFrames(mxd)[0] 

#Check to make sure user had at least one parcel selected. 

parcelsCount = int(arcpy.GetCount_management(parcels).getOutput(0)) 

if 0 < parcelsCount < 2: 

    

    lyr = arcpy.mapping.ListLayers(mxd, addressPoints, df)[0] 

    workspace = r"C:\Users\***\AppData\Roaming\ESRI\Desktop10.2\ArcCatalog\Connection to dsd15_sqlexpress.sde" 

    # Start an edit session. Must provide the workspace. 

    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,False) 

    # Start an edit operation 

    edit.startOperation() 

    #Select Address Points within selected parcel 

    arcpy.SelectLayerByLocation_management(addressPoints, "HAVE_THEIR_CENTER_IN", parcels) 

    with arcpy.da.SearchCursor(parcels, ['ACCOUNT','SiteStreet']) as singleCursor: 

        for singleRow in singleCursor: 

            ACCOUNT = singleRow[0] 

            SiteStreet = singleRow[1] 

    with arcpy.da.UpdateCursor(addressPoints, ['Account', 'SiteStreet']) as singleCursor: 

        for singleRow in singleCursor: 

            singleRow[0] = ACCOUNT 

            singleRow[1] = SiteStreet 

            singleCursor.updateRow(singleRow) 

    # Stop the edit operation. 

    edit.stopOperation() 

    print('Parcel address update is complete.') 

elif 1 < parcelsCount < 1000: 

    #Create in memory parcel layer 

    selectedParcels = arcpy.MakeFeatureLayer_management(parcels, "selectedParcels") 

    for lyr in arcpy.mapping.ListLayers(mxd, "", df): 

        if lyr.name == addressPoints: 

            addressLayer = lyr 

        if lyr.name == parcels: 

            parcelsLayer = lyr 

    workspace = addressLayer.workspacePath 

    # Start an edit session. Must provide the workspace. 

    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,False) 

    # Start an edit operation 

    edit.startOperation() 

    with arcpy.da.SearchCursor(parcels, ['ACCOUNT', 'SiteStreet', 'OBJECTID']) as parcelCursor: 

        for parcelRow in parcelCursor: 

            ACCOUNT = parcelRow[0] 

            SiteStreet = parcelRow[1] 

            OID = parcelRow[2] 

            OID = str(OID) 

            arcpy.SelectLayerByAttribute_management("selectedParcels", "NEW_SELECTION", "OBJECTID= "+OID) 

            #Select Address Points by location, within selected Parcels. 

            arcpy.SelectLayerByLocation_management(addressPoints,"HAVE_THEIR_CENTER_IN","selectedParcels") 

            with arcpy.da.UpdateCursor(addressPoints, ['Account', 'SiteStreet']) as addressCursor: 

                for addressRow in addressCursor: 

                    addressRow[0] = Account 

                    addressRow[1] = SiteStreet 

                    addressCursor.updateRow(addressRow) 

    del ACCOUNT, SiteStreet

    # Stop the edit operation. 

    edit.stopOperation() 

    arcpy.Delete_management("selectedParcels") 

    print('Parcel address update is complete.') 

else: 

    print('Please select a valid number of parcels.')

0 Kudos
RichardFairhurst
MVP Alum

Originally this code was written with versioned data in mind and the code enabled undo and kept the editor session open.  The user was required to save the edits.  But you are doing unversioned edits, so you may as well close the edit session and save the edits.  That way you don't have to manually do the save step and you don't have the ability to undo edits anyway.  So add this after lines 48 and 96

   edit.stopEditing(True)

0 Kudos
TonyAlmeida
MVP Regular Contributor

Thanks Richard, i should have known that duh.

I have selected two or three parcels and tried to run the code but i get the following. I would like to be able to update the attributes of one or more then just one parcel at a time.

Runtime error

Traceback (most recent call last):

  File "<string>", line 67, in <module>

RuntimeError: cannot open workspace

0 Kudos
RichardFairhurst
MVP Alum

Make line 63 in the posted code above identical to line 21 since I presume you want to edit the same workspace in the lower part of the code as you are in the upper part of the code.  It looks like your actual line numbers have changed slightly, so it may be line 64 or 65 in your most current code.

0 Kudos