row, rows= None, None rows= arcpy.SearchCursor(inputFC) for row in rows: -- do work--- del row, rows
rowCount = 0 row, rows= None, None rows= arcpy.SearchCursor(inputFC) for row in rows: rowCount += 1 -- do work--- del row, rows
import types import arcpy as ap rows = ap.SearchCursor(myTable, sql_statement) row = rows.next() if type(row) != types.NoneType: # do a bunch of work
if arcpy.SearchCursor(myTable, sql_statement).next() == None: print "Empty cursor!"
I know I'm playing necromancer and raising this discussion from the dead but I was looking for an answer to this question and found my own solution that I thought I would post. Maybe someone else has come up with something better by now.
Thanks to Joshua Bixby for his blog post on cursors, here's what I came up with:
with arcpy.da.SearchCursor(in_table, "*") as s_cursor:
if sum(1 for row in s_cursor): ## Counts items in cursor, returns 0 if empty
s_cursor.reset() ## Return cursor back to the first row after counting
for row in s_cursor:
# Process rows
print(row)
else:
print("Cursor is empty!")
The check for rows will iterate through the cursor leaving nothing for the .next() item so you have to .reset() the cursor to start from the beginning again. In my case, I couldn't just count the rows with GetCount_management() in the original feature class because I was using a where clause in the search cursor.
To check if a applying a where clause returns no results can also be done with the GetCount tool. Just make a featurelayer and check the result. Below some examples including using the search cursor on empty results, which really is no problem at all.
def main():
import arcpy
fc1 = r'D:\Xander\GeoNet\Ellipse\data.gdb\Ellipses'
fc2 = r'D:\Xander\GeoNet\Ellipse\data.gdb\Ellipses_empty'
# get count on a featureclass
cnt1 = getCount(fc1)
cnt2 = getCount(fc2)
print "fc1 has {0} features".format(cnt1)
print "fc2 has {0} features".format(cnt2)
# Cursor on a featureclass with features
max_oid = None
with arcpy.da.SearchCursor(fc1, ('OID@')) as curs:
for row in curs:
oid = row[0]
if max_oid is None:
max_oid = oid
elif oid > max_oid:
max_oid = oid
print "max_oid for fc1:", max_oid
# Cursor on a featureclass without features
max_oid = None
with arcpy.da.SearchCursor(fc2, ('OID@')) as curs:
for row in curs:
oid = row[0]
if max_oid is None:
max_oid = oid
elif oid > max_oid:
max_oid = oid
print "max_oid for fc2:", max_oid
# get count on a feature layer (with where clause)
where = "Ellipse = 1"
fl1 = arcpy.MakeFeatureLayer_management(fc1, "flay1", where)
fl2 = arcpy.MakeFeatureLayer_management(fc2, "flay2", where)
cnt1 = getCount(fl1)
cnt2 = getCount(fl2)
print "fl1 has {0} features".format(cnt1)
print "fl2 has {0} features".format(cnt2)
# Cursor on a featurelayer (where clause) with features
max_oid = None
with arcpy.da.SearchCursor(fl1, ('OID@')) as curs:
for row in curs:
oid = row[0]
if max_oid is None:
max_oid = oid
elif oid > max_oid:
max_oid = oid
print "max_oid for fl1:", max_oid
# Cursor on a featureclass (where clause) with features, but without results
where = "Ellipse = -1" # there are no features witch match this where clause
max_oid = None
with arcpy.da.SearchCursor(fc1, ('OID@'), where) as curs:
for row in curs:
oid = row[0]
if max_oid is None:
max_oid = oid
elif oid > max_oid:
max_oid = oid
print "max_oid for fc1 (with where clause, no match):", max_oid
def getCount(fc):
return int(arcpy.GetCount_management(fc).getOutput(0))
if __name__ == '__main__':
main()
This will print:
fc1 has 722 features
fc2 has 0 features
max_oid for fc1: 722
max_oid for fc2: None
fl1 has 361 features
fl2 has 0 features
max_oid for fl1: 361
max_oid for fc1 (with where clause, no match): None
As Xander Bakker points out, the geoprocessing tool approach to addressing your issue involves creating a feature layer and counting that, and then passing the feature layer to the search cursor if there are results.
Looking at it from purely a Python perspective, i.e., not involving geoprocessing tools, the major issue with the code provided is that it completely consumes the iterable to determine if there is just one or more records. There are several ways in Python to check if an iterable is empty and then do one thing or another depending on the results.
One approach that doesn't fully consume the iterable to check for the existence of items uses next() with a sentinel value:
s_cursor = arcpy.da.SearchCursor(in_table, "*")
with s_cursor:
if next(s_cursor, None) is not None:
s_cursor.reset()
for row in s_cursor:
print row
else:
print "Cursor is empty!"
Another approach sets the variable for holding what is returned by the iterable to a sentinel value and then checks after processing the iterable to see if anything was processed:
row = None
with s_cursor:
for row in s_cursor:
print row
if row is None:
print "Cursor is empty!"
Another one is wrapping the cursor in a generator function and seeing if StopIteration is raised when you request a row.
Since the cursor itself will raise a StopIteration error if there isn't a row to request, I guess I don't understand the value of wrapping it in a generator function to raise a StopIteration error.
Using a generator function is a pattern I find useful so I thought I would mention it.
Handling StopIteration lets you automate returning something you design, like below I return a dictionary if the cursor is empty or not.
# Define row generator
def rowGenerator(table,fields,sortField=None):
if sortField is not None:
sql = [None,'ORDER BY ' + sortField]
cursor = arcpy.da.SearchCursor(table,fields,sql_clause=sql)
else:
cursor = arcpy.da.SearchCursor(table,fields)
with cursor:
for row in cursor:
yield row
# Create row generator
if postalField:
rowGen = rowGenerator(inTable,cursorFields,postalField)
else:
rowGen = rowGenerator(inTable,cursorFields)
# Define recordset builder
def recordsetBuilder(rowgen):
records = []
for i in range(0,1000):
try:
data = next(rowgen)
attributes = {'attributes':{recordFields:data
for i in range(len(data))}}
records.append(attributes)
except StopIteration:
break
return {'records':records}