2

I've got a Python script that "cleans up" a feature class by renaming fields to something more legible -- add a new field (e.g. "DistrictName"), copy data from old field (e.g. "DISTNAM") to new field, and delete the old field. This is done for a lot of fields, so I built functions:

def delete_field(tbl, fieldName):
    arcpy.DeleteField_management(tbl, fieldName)
def replace_field(tbl, newFieldName, oldFieldName, dataType):
    arcpy.AddField_management(tbl, newFieldName, dataType)
    with arcpy.da.UpdateCursor(tbl, [newFieldName, oldFieldName]) as cursor:
        for row in cursor:
            row[0] = row[1]
            cursor.updateRow(row)
    delete_field(tbl, oldFieldName)

But there's a subsequent step in the Python script that is exporting this feature class to an Excel spreadsheet, and part of the process builds a list of the fields to be used to create a header row of column names.

data_description = arcpy.Describe(dataset_name)
fieldnames = [f.name for f in data_description.fields if f.type not in ["Geometry", "Raster", "Blob"]]

When I look at the resulting feature class in ArcMap, all the old field names have been deleted, which is exactly what I would expect. When Python does that Describe step, it sees both the new AND the old field names -- but it breaks when attempting to copy an old field, since the data does not actually exist.

What step can I add between deleting and listing to "update" the feature class fields so it only lists the existing fields, and not any fields which were recently deleted?


EDIT: I pulled the Describe portion out of its function and put it directly after the sequence of replace_field operations. Also tried using arcpy.ListFields instead of the Describe method.

replace_field(tableName, "District_Name", "DISTRICTNAME", "TEXT")
replace_field(tableName, "District_Number", "DISTRICT", "LONG")
replace_field(tableName, "LocalOffice_Name", "LOCALOFFICENAME", "TEXT")
replace_field(tableName, "Substation_Number", "SUBSTATIONID", "LONG")
replace_field(tableName, "FeederID", "CIRCUITID", "LONG")
replace_field(tableName, "OH_SinglePhase_CircuitMiles", "OH_SINGLEPHASE", "DOUBLE")
replace_field(tableName, "OH_TwoPhase_CircuitMiles", "OH_TWOPHASE", "DOUBLE")
replace_field(tableName, "OH_ThreePhase_CircuitMiles", "OH_THREEPHASE", "DOUBLE")
replace_field(tableName, "OH_Total_CircuitMiles", "OH_TOTALCIR", "DOUBLE")
replace_field(tableName, "UG_SinglePhase_CircuitMiles", "UG_SINGLEPHASE", "DOUBLE")
replace_field(tableName, "UG_TwoPhase_CircuitMiles", "UG_TWOPHASE", "DOUBLE")
replace_field(tableName, "UG_ThreePhase_CircuitMiles", "UG_THREEPHASE", "DOUBLE")
replace_field(tableName, "UG_Total_CircuitMiles", "UG_TOTALCIR", "DOUBLE")

data_description = arcpy.Describe(tableName)
fieldnames = [f.name for f in data_description.fields if f.type not in ["Geometry", "Raster", "Blob"]]
print fieldnames

apyListFields = arcpy.ListFields(tableName)
print apyListFields

The resulting list of fields from both Describe and ListFields is the same -- and all the field names in caps (e.g. DISTRICTNAME) are deleted, but still showing up as field names.

[u'OBJECTID', u'District_Name', u'District_Number', u'LocalOffice_Name', u'Substation_Number', u'FeederID', u'OH_SinglePhase_CircuitMiles', u'OH_TwoPhase_CircuitMiles', u'OH_ThreePhase_CircuitMiles', u'OH_Total_CircuitMiles', u'UG_SinglePhase_CircuitMiles', u'UG_TwoPhase_CircuitMiles', u'UG_ThreePhase_CircuitMiles', u'UG_Total_CircuitMiles', u'UG_TOTALCIR', u'UG_THREEPHASE', u'UG_TWOPHASE', u'UG_SINGLEPHASE', u'OH_TOTALCIR', u'OH_THREEPHASE', u'OH_TWOPHASE', u'OH_SINGLEPHASE', u'CIRCUITID', u'SUBSTATIONID', u'LOCALOFFICENAME', u'DISTRICT', u'DISTRICTNAME']

[u'OBJECTID', u'District_Name', u'District_Number', u'LocalOffice_Name', u'Substation_Number', u'FeederID', u'OH_SinglePhase_CircuitMiles', u'OH_TwoPhase_CircuitMiles', u'OH_ThreePhase_CircuitMiles', u'OH_Total_CircuitMiles', u'UG_SinglePhase_CircuitMiles', u'UG_TwoPhase_CircuitMiles', u'UG_ThreePhase_CircuitMiles', u'UG_Total_CircuitMiles', u'UG_TOTALCIR', u'UG_THREEPHASE', u'UG_TWOPHASE', u'UG_SINGLEPHASE', u'OH_TOTALCIR', u'OH_THREEPHASE', u'OH_TWOPHASE', u'OH_SINGLEPHASE', u'CIRCUITID', u'SUBSTATIONID', u'LOCALOFFICENAME', u'DISTRICT', u'DISTRICTNAME']

  • 1
    Hey Erica - This is a guess, but perhaps something adverse and schema-lock related is happening between the closing of your with statement's frame, and the call to delete_field() immediately after it. Have you tried issuing the call to delete_field() outside of the replace_field() definition in this case? Otherwise, the code reads fine in my opinion, there is no obvious reason why it should not work as-is; in other words, something is happening that is not immediately the script's fault. – Jim Aug 10 '16 at 16:59
  • @Jim It's likely some sort of very weird lock. I tried calling delete_field() without involving the replace_field() function, and ArcPy still sees the "deleted" field... – Erica Aug 10 '16 at 18:51
  • 1
    That is... such odd behavior for ArcPy and probably outright frustrating for the user. I hope a solution appears soon. – Jim Aug 10 '16 at 18:55
  • Yes, it's within another function to which you pass a feature class as dataset_name. It would also be called tbl except I didn't write it, it's from somebody else's module. – Erica Aug 10 '16 at 21:19
  • So one doesn't refer to an in-memory copy, a layer, or anything else? They both refer to the same feature class path/name? – Tom Aug 10 '16 at 21:24
1

As a workaround, copying the "cleaned" feature class to a new feature class before attempting to list fields avoids the issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.