I'm running ArcGIS 10.3 and have a geodatabase with multiple feature datasets each containing multiple feature classes. Each feature class has multiple string type fields containing <Null> values. I want to change the <Null> values to "TBD" (without the quotation marks).
I feel I'm very close, but at 'for row in cursor:' I'm receiving the error "Too few parameters. Expected 1." I guess the cursor isn't actually returning any rows at all? Below is what I currently have; I haven't added any documentation or messaging yet. Any help would be greatly appreciated.
import arcpy from arcpy import env import os #Set variables inputgdb = sys.argv[1] nullCount = 0 #Set workspace arcpy.env.workspace = inputgdb #Populate Nulls with TBD datasetList = arcpy.ListDatasets(feature_type = 'feature') datasetList = [''] + datasetList if datasetList is not None else [] for dataset in datasetList: env.workspace = inputgdb + "\\" + dataset dataset = dataset + "\\" fcList = arcpy.ListFeatureClasses() for fc in fcList: fc = fc +"\\" fieldList = arcpy.ListFields(fc,["String"]) for field in fieldList: with arcpy.da.UpdateCursor (fc, 'fieldList') as cursor: for row in cursor: if row[0] == None: row[0] = 'TBD' cursor.updateRow(row)
Solved! Go to Solution.
Ah, I assumed ListFields returned a list of field names, but it returns field objects. See Joshua's answer or the final example here for creating a list of field names from ListFields.
Through in some print statements
I would recommend:
print datasetList
print fc
print fieldList
after each has been assigned I don't think you are getting the values you are expecting
You create a list called fieldList, but then try to call a single field (string) called 'fieldList'. Remove the quotes to access the variable fieldList, rather than the string 'fieldList'.
edit: actually, if you mean to loop through individual fields in fieldList, then you should direct the cursor to look for field (no quotes).
edit 2: rather than cursoring through your feature classes for each string field, you should cursor through each feature class once and inspect the values in row.
Darren,
I think he is trying to get field type string
field_names = [f.name for f in arcpy.ListFields(fc,'','String')]
Edit:
Sorry just looked at your edit 2
Darren and Wes,
Thanks for the suggestions. I did add some messaging and it is at least returning the feature datasets, feature classes and fields as I was anticipating.
If I understand Darren's edit 2, I don't need to cursor through a list of fields, just the list of feature classes?
Thanks again.
Right, I believe creating cursors is an expensive operation, so the fewer the better.
for dataset in datasetList:
env.workspace = inputgdb + "\\" + dataset
dataset = dataset + "\\"
fcList = arcpy.ListFeatureClasses()
for fc in fcList:
fc = fc +"\\"
fieldList = arcpy.ListFields(fc,["String"])
with arcpy.da.UpdateCursor (fc, fieldList) as cursor:
for row in cursor: # for each row in the feature class
for i in len(row): # for each value in row (i.e. field values)
if row == None:
row = 'TBD'
cursor.updateRow(row)
I think I'm getting closer, but it does not like the fieldList in cursor.
import arcpy from arcpy import env import os #Set variables inputgdb = sys.argv[1] nullCount = 0 #Set workspace arcpy.env.workspace = inputgdb #Populate Nulls with TBD datasetList = arcpy.ListDatasets(feature_type = 'feature') datasetList = [''] + datasetList if datasetList is not None else [] print "Getting Feature Datasets..." arcpy.AddMessage ("Getting Feature Datasets...") print datasetList arcpy.AddMessage (datasetList) for dataset in datasetList: env.workspace = inputgdb + "\\" + dataset dataset = dataset + "\\" fcList = arcpy.ListFeatureClasses() print "Getting Feature Classes..." arcpy.AddMessage ("Getting Feature Classes...") print fcList arcpy.AddMessage (fcList) for fc in fcList: fc = fc +"\\" fieldList = arcpy.ListFields(fc,["String"]) with arcpy.da.UpdateCursor (fc, fieldList) as cursor: for row in cursor: #for each row in the feature class for i in len(row): #for each value in row (i.e., field values) if row == None: row = 'TBD' cursor.updateRow(row) print "Updating value..." arcpy.AddMessage ("Updating value...") print fieldList arcpy.AddMessage (fieldList)
Ah, I assumed ListFields returned a list of field names, but it returns field objects. See Joshua's answer or the final example here for creating a list of field names from ListFields.
Thank you so much to everyone; it's working.
import arcpy from arcpy import env import os #Set variables inputgdb = sys.argv[1] nullCount = 0 #Set workspace arcpy.env.workspace = inputgdb #Populate Nulls with TBD datasetList = arcpy.ListDatasets(feature_type = 'feature') datasetList = [''] + datasetList if datasetList is not None else [] print "Getting Feature Datasets..." arcpy.AddMessage ("Getting Feature Datasets...") print datasetList arcpy.AddMessage (datasetList) for dataset in datasetList: env.workspace = inputgdb + "\\" + dataset dataset = dataset + "\\" fcList = arcpy.ListFeatureClasses() print "Getting Feature Classes..." arcpy.AddMessage ("Getting Feature Classes...") print fcList arcpy.AddMessage (fcList) for fc in fcList: fc = fc +"\\" fieldList = [f.name for f in arcpy.ListFields(fc, "*", "STRING")] with arcpy.da.UpdateCursor (fc, fieldList) as cursor: for row in cursor: row = [(fld if fld is not None else 'TBD') for fld in row] cursor.updateRow(row) print "Updating value..." arcpy.AddMessage ("Updating value...") print fieldList arcpy.AddMessage (fieldList)
Correct. As a side note, you should really consider using the os.path module to create file system paths (like feature classes in feature datasets).
Starting at the fieldList statement towards the bottom of your script:
fieldList = [f.name for f in arcpy.ListFields(fc, "*", "STRING")] with arcpy.da.UpdateCursor (fc, fieldList) as cursor: for row in cursor: row = [(fld if fld is not None else 'TBD') for fld in row] # row = [(fld if fld else 'TBD') for fld in row] # this would capture empty strings too and not just NULL cursor.updateRow(row)