getting runtime error using arcpy

3817
18
09-18-2017 01:58 PM
DanMacDonald
New Contributor

Hi all
I am trying to write a arcpy script that will turn off all NULL and empty fields. The script runs for a while and then gives a run time error at fields.append(row.getValue(f)). Below is the script.

import arcpy
from arcpy import env
arcpy.env.overwriteOutput = True
arcpy.env.addOutputsToMap = False
arcpy.env.workspace = "C:/temp"
out_layer = "temp.lyr"

mxd = arcpy.mapping.MapDocument('CURRENT')
df = arcpy.mapping.ListDataFrames(mxd, '*')[0] # need to find way to get list of layers there can be more than one data frame
listfields = []
thebadlist = []
for LayerNeedsFieldsTurnedOff in arcpy.mapping.ListLayers(mxd):
if LayerNeedsFieldsTurnedOff.isGroupLayer:
print "group print"
elif LayerNeedsFieldsTurnedOff.isFeatureLayer:
fields = dict((f.name, []) for f in arcpy.ListFields(LayerNeedsFieldsTurnedOff) if not f.required)

rows = arcpy.SearchCursor(LayerNeedsFieldsTurnedOff,"","","","")
for row in rows:
for f in fields.keys():
fields.append(row.getValue(f)) #**the error happens here**
#print row.getValue(f)

for field, values in fields.iteritems():
#print field

if field == "Shape":
listfields.append(field)
elif all(map(lambda s: s is None or not str(s).strip(), values)):
thebadlist.append(field)
else:
listfields.append(field)

# LayerNeedsFieldsTurnedOff = arcpy.mapping.ListLayers(mxd, 'exampledata', df)[0]
# fill in your desired fields to remain visible

desiredFields = listfields

field_info = arcpy.Describe(LayerNeedsFieldsTurnedOff).fieldInfo # I need this for field count


for i in range(field_info.count):
if field_info.getfieldname(i) not in desiredFields:
if field_info.getfieldname(i) == "SHAPE":
field_info.setvisible(i, 'VISIBLE')
elif field_info.getfieldname(i) == "Shape":
field_info.setvisible(i, 'VISIBLE')
else:
field_info.setvisible(i, 'HIDDEN')


arcpy.SaveToLayerFile_management(LayerNeedsFieldsTurnedOff, out_layer)
arcpy.MakeFeatureLayer_management(LayerNeedsFieldsTurnedOff, 'temp_layer', '', '', field_info)
refLyr = arcpy.mapping.Layer('temp_layer')
# rename the ref layer the same as your target layer
refLyr.name = LayerNeedsFieldsTurnedOff.name
lyrfile = "C:/temp/temp.lyr"
print LayerNeedsFieldsTurnedOff.name
arcpy.ApplySymbologyFromLayer_management(refLyr, lyrfile)
arcpy.mapping.UpdateLayer(df, LayerNeedsFieldsTurnedOff, refLyr, False)
# mxd.save()
print 'cleaning up-'
if arcpy.Exists('temp_layer'):
print '\'temp_layer\' still in memory...deleting now...'
arcpy.Delete_management('temp_layer')
print 'deleting obj refs...'
del LayerNeedsFieldsTurnedOff, refLyr, fields
print 'done.'

0 Kudos
18 Replies
DanMacDonald
New Contributor

I am trying print statements

0 Kudos
RandyBurton
MVP Alum

Regarding the comment in your code around line 8:

# need to find way to get list of layers there can be more than one data frame‍

Consider the following:

>>> mxd = arcpy.mapping.MapDocument('CURRENT')
>>> for df in arcpy.mapping.ListDataFrames(mxd):
...     print df.name
...     for layer in arcpy.mapping.ListLayers(mxd, data_frame=df):
...         print layer.name
...         
DataFrame1
LayerInDF1
DataFrame2
LayerInDF2
>>> for layer in arcpy.mapping.ListLayers(mxd):
...     print layer.name
...     
LayerInDF1
LayerInDF2
>>> ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Your use of ListLayers without specifying a data_frame should process all layers in all data frames.  You may need to activate the data frames as you loop through them.

RandyBurton
MVP Alum

Dan, are you using multiple data frames in your map document?  I think your code might be making it through the active data frame and getting hung up in an inactive data frame.  It seems that some elements of a layer don't exist (or can't be accessed) if they are in an inactive data frame.  I've been testing the following code in 10.5 without error.  But the map document becomes a bit unstable until I manually activate the first data frame.

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

for df in arcpy.mapping.ListDataFrames(mxd):
    mxd.activeView = df.name # data frames should have unique names
    print df.name
    for layer in arcpy.mapping.ListLayers(mxd, data_frame=df):
        if layer.isGroupLayer: 
            print "Group Layer: {}".format(layer.name)
        elif layer.isFeatureLayer:
            print "Feature Layer: {}".format(layer.name)
            fields = dict((f.name, []) for f in arcpy.ListFields(layer) if not f.required)

            for row in arcpy.SearchCursor(layer):
                for f in fields.keys():
                    fields[f].append(row.getValue(f))
            del row
        print fields
    del layer
del df
del mxd‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Part of what this does is specify a data frame in ListLayers (line 6).  Since this active view is set by using a data frame name, it is important that all data frames have unique names.  When fields is printed (line 17) it appears as I would expect.  The code above may not be switching active views in the most efficient manner, but I have not seen any examples where it is done differently.

I had previously thought that the problem might have been with SearchCursor needing a field list, but it appears that it defaults to a list of all fields (with some exceptions).

0 Kudos
DanMacDonald
New Contributor

The script is still failing at line 21  the more than two data frame is just incase.  I will try that and see if it helps.sc

0 Kudos
RandyBurton
MVP Alum

If you print the "fields" variable between lines 17 and 18, what do you get?  Something like:

{u'Field1': [], u'Field2': [], u'Field3': [], u'Field4': []}
0 Kudos
DanPatterson_Retired
MVP Emeritus

your commented out print statement should be before line 21 if it is failing on line 21

DanMacDonald
New Contributor

thank you

0 Kudos
RandyBurton
MVP Alum

I was able to generate the exact same error as the one you mentioned in a previous post by adding a nonexistent field to the fields dictionary:

fields = dict((f.name, []) for f in arcpy.ListFields(layer) if not f.required) # your line 17

fields['bull'] = [] # nonexistant field‍‍‍‍

When using a wild card for the field list in SearchCursor (or not specifying a field list), SearchCursor will return all fields with a few exceptions (raster and BLOB fields are excluded).  You will need to exclude these fields when you create your dictionary.  This code might work to exclude rasters and blobs from the fields dictionary:

fields = dict((f.name, []) for f in arcpy.ListFields(layer) if not (f.required or f.type == "Blob" or f.type=="Raster"))

Another option would be to create a try/except block around lines 20-21, perhaps:

for f in fields.keys():
    try:
        fields.append(row.getValue(f))
    except:
        print "{} not in field list".format(f)

If these suggestions fail, you should print the fields dictionary and compare it to field list in your feature.

DanMacDonald
New Contributor

Thank you I will try this

0 Kudos