Python add-in help - restricting da.SearchCursor and da.UpdateCursor

1868
2
Jump to solution
10-08-2013 05:32 AM
JamesMcBroom1
New Contributor
I have a small add-in that I use for a building footprints map. Essentially, the add-in reads the data from the parcel layer, and copies the data to the buildings layer (I use this when I have to 'split' a building that lies over multiple parcels).

The code is set up to work with one (manually selected) parcel and one footprint, no more. However, if I were to click the add-in when no parcel or footprint was selected, it assigns the last record of the parcel data to every footprint! If I am in an edit session, it's OK, but I would like to let other people use this add-in.

I understand why I get this behavior (the search/update cursor are looping through every record if none is selected) Is there some pre-script logic I can add to make sure that only one record is updated?

Here is my code:

import arcpy
import pythonaddins
import webbrowser
import threading

mxd = arcpy.mapping.MapDocument("CURRENT")
layerList = arcpy.mapping.ListLayers(mxd)
tableList = arcpy.mapping.ListTableViews(mxd)
for layer in layerList:
    if "Footprints_Edit" in layer.name:
        footprints_fc = layer
    if "Parcels_Edit" in layer.name:
        parcels_fc = layer
    if "Address" in layer.name:
        address_fc = layer
for table in tableList:
    if "Assessing" in table.name:
        assessing_table = table
    if "Condos" in table.name:
        condo_table = table

def rows_as_update_dicts(cursor):
    colnames = cursor.fields
    for row in cursor:
        row_object = dict(zip(colnames, row))
        yield row_object
        cursor.updateRow([row_object[colname] for colname in colnames])

class assignparceldata(object):
    """Implementation for building_footprints_Addin_addin.assignParcelData (Button)"""
    def __init__(self):
        self.enabled = True
        self.checked = False
    def onClick(self):
        parcelfields = ["PIN","PADDRESS"]
        with arcpy.da.SearchCursor(parcels_fc,parcelfields) as rows:
            for row in rows:
                new_pin = row[0]
                new_paddress = row[1]
        print "Assigning parcel: PIN is %s, Address is %s" % (new_pin,new_paddress)
        footprint_fields = ["BUILDINGID", "TAXID","BADDRESS"]
        with arcpy.da.UpdateCursor(footprints_fc,footprint_fields) as brows:
            for row in rows_as_update_dicts(brows):
                row['TAXID'] = new_pin
                row['BADDRESS'] = new_paddress
                print "Updating building footprint %d with parcel info: PIN is (%s), address is (%s)" % (row['BUILDINGID'], new_pin, new_paddress)

0 Kudos
1 Solution

Accepted Solutions
DouglasSands
Occasional Contributor II
Have you tried validating the record count using arcpy.GetCount (http://resources.arcgis.com/en/help/main/10.1/index.html#//0017000000n7000000)? GetCount respects any selection applied, and if no selection is applied then it returns the full feature count. Perhaps you can test the result and see if the count is equal to exactly one?

I have a small add-in that I use for a building footprints map. Essentially, the add-in reads the data from the parcel layer, and copies the data to the buildings layer (I use this when I have to 'split' a building that lies over multiple parcels).

The code is set up to work with one (manually selected) parcel and one footprint, no more. However, if I were to click the add-in when no parcel or footprint was selected, it assigns the last record of the parcel data to every footprint! If I am in an edit session, it's OK, but I would like to let other people use this add-in.

I understand why I get this behavior (the search/update cursor are looping through every record if none is selected) Is there some pre-script logic I can add to make sure that only one record is updated?

Here is my code:

import arcpy
import pythonaddins
import webbrowser
import threading

mxd = arcpy.mapping.MapDocument("CURRENT")
layerList = arcpy.mapping.ListLayers(mxd)
tableList = arcpy.mapping.ListTableViews(mxd)
for layer in layerList:
    if "Footprints_Edit" in layer.name:
        footprints_fc = layer
    if "Parcels_Edit" in layer.name:
        parcels_fc = layer
    if "Address" in layer.name:
        address_fc = layer
for table in tableList:
    if "Assessing" in table.name:
        assessing_table = table
    if "Condos" in table.name:
        condo_table = table

def rows_as_update_dicts(cursor):
    colnames = cursor.fields
    for row in cursor:
        row_object = dict(zip(colnames, row))
        yield row_object
        cursor.updateRow([row_object[colname] for colname in colnames])

class assignparceldata(object):
    """Implementation for building_footprints_Addin_addin.assignParcelData (Button)"""
    def __init__(self):
        self.enabled = True
        self.checked = False
    def onClick(self):
        parcelfields = ["PIN","PADDRESS"]
        with arcpy.da.SearchCursor(parcels_fc,parcelfields) as rows:
            for row in rows:
                new_pin = row[0]
                new_paddress = row[1]
        print "Assigning parcel: PIN is %s, Address is %s" % (new_pin,new_paddress)
        footprint_fields = ["BUILDINGID", "TAXID","BADDRESS"]
        with arcpy.da.UpdateCursor(footprints_fc,footprint_fields) as brows:
            for row in rows_as_update_dicts(brows):
                row['TAXID'] = new_pin
                row['BADDRESS'] = new_paddress
                print "Updating building footprint %d with parcel info: PIN is (%s), address is (%s)" % (row['BUILDINGID'], new_pin, new_paddress)

View solution in original post

0 Kudos
2 Replies
DouglasSands
Occasional Contributor II
Have you tried validating the record count using arcpy.GetCount (http://resources.arcgis.com/en/help/main/10.1/index.html#//0017000000n7000000)? GetCount respects any selection applied, and if no selection is applied then it returns the full feature count. Perhaps you can test the result and see if the count is equal to exactly one?

I have a small add-in that I use for a building footprints map. Essentially, the add-in reads the data from the parcel layer, and copies the data to the buildings layer (I use this when I have to 'split' a building that lies over multiple parcels).

The code is set up to work with one (manually selected) parcel and one footprint, no more. However, if I were to click the add-in when no parcel or footprint was selected, it assigns the last record of the parcel data to every footprint! If I am in an edit session, it's OK, but I would like to let other people use this add-in.

I understand why I get this behavior (the search/update cursor are looping through every record if none is selected) Is there some pre-script logic I can add to make sure that only one record is updated?

Here is my code:

import arcpy
import pythonaddins
import webbrowser
import threading

mxd = arcpy.mapping.MapDocument("CURRENT")
layerList = arcpy.mapping.ListLayers(mxd)
tableList = arcpy.mapping.ListTableViews(mxd)
for layer in layerList:
    if "Footprints_Edit" in layer.name:
        footprints_fc = layer
    if "Parcels_Edit" in layer.name:
        parcels_fc = layer
    if "Address" in layer.name:
        address_fc = layer
for table in tableList:
    if "Assessing" in table.name:
        assessing_table = table
    if "Condos" in table.name:
        condo_table = table

def rows_as_update_dicts(cursor):
    colnames = cursor.fields
    for row in cursor:
        row_object = dict(zip(colnames, row))
        yield row_object
        cursor.updateRow([row_object[colname] for colname in colnames])

class assignparceldata(object):
    """Implementation for building_footprints_Addin_addin.assignParcelData (Button)"""
    def __init__(self):
        self.enabled = True
        self.checked = False
    def onClick(self):
        parcelfields = ["PIN","PADDRESS"]
        with arcpy.da.SearchCursor(parcels_fc,parcelfields) as rows:
            for row in rows:
                new_pin = row[0]
                new_paddress = row[1]
        print "Assigning parcel: PIN is %s, Address is %s" % (new_pin,new_paddress)
        footprint_fields = ["BUILDINGID", "TAXID","BADDRESS"]
        with arcpy.da.UpdateCursor(footprints_fc,footprint_fields) as brows:
            for row in rows_as_update_dicts(brows):
                row['TAXID'] = new_pin
                row['BADDRESS'] = new_paddress
                print "Updating building footprint %d with parcel info: PIN is (%s), address is (%s)" % (row['BUILDINGID'], new_pin, new_paddress)

0 Kudos
JamesMcBroom1
New Contributor
I did not know about GetCount. That is exactly what I am looking for. Thanks for pointing that out to me!
0 Kudos