I have a script processing several geodatabases and, at the end, creating some shapefiles. During this process, an intemediary (local) GDB is created and some selected datasets/feature classes are exported. Then a bunch of more processing is done, including deleting some unneccessary fields or creating some new ones. Some times, the script just runs perfectly fine and, some other times, it just stops with an exception. The 'where and when' seems to be totally random. The different exceptions I've got are:
ERROR 000210: Cannot create output C:\some_path\temp.gdb\dataset_name
Failed to execute (FeatureClassToFeatureClass)
ExecuteError: ERROR 000229: Cannot open C:\some_path\temp.gdb\dataset_name
Failed to execute (DeleteField)
These errors occur at different points on the script, with exactly the same input GDB and data and it seems to be totally random when and where they occur.
I'm 99% sure, that the names of the feature classes, datasets and paths are not the cause of this random errors, because they only occur sometimes and most of the time on different feature classes with the sources being each time exactly the same. While debugging I've got 5 times consecutive errors, but I also ran the script 20 consecutive times without any error. Normally though, the errors happen approx. 1 from 3 times.
I'm including some code (modified it, trying to keep only the necessary) and a lot of comments.
This is the starting point of the script:
# 'tools.py' contains some common methods that we use in our scripts import tools as tls from tools import CustomException import arcpy # ... etc. ''' An Item tuple contains: - dataset: name of the dataset on the input sources, - fclass: fclass item (a NameAlias tuple to be used on the target) - fields: a list of field items for the "keep fields" (fields NOT on this list will be removed). Each field item is also a NameAlias tuple. Example: Item(dataset='region1', fclass=NameAlias(name='Buildings', alias=None), fields=[NameAlias(name='BdgNumber', alias='Nr'), ...]) ''' Item = namedtuple('Item', 'dataset fclass fields') def main(options=None, args=None): prog = 'export.py' usage = ("Usage: %prog gdb_txt fc_list_txt out_dir") # gdb_txt: text file with the path to an SDE or file GDB per line # fc_list_txt: text file containing the datasets and feature classes # we want to process. # out_dir: the output directory parser = OptionParser(usage) if not options and not args: (options, args) = parser.parse_args() if len(args) != 3: parser.error("Incorrect number of arguments") parser = OptionParser(usage) if not options and not args: (options, args) = parser.parse_args() gdb_txt = args gdb_lst = tls.parse_gdb_lst(gdb_txt) # get and check layers file fc_list_txt = args err_msg = tls.check_file_exists(fc_list_txt) if err_msg: parser.error(err_msg) # ... parse file an get the list of items to export and a set of the # the datasets (to group items by datasets if we want to) items, ds_set = init_data(fc_list_txt) # create output dir (if it doesn't exist yet) out_dir = args out_dir = tls.create_dir(out_dir) # Do the work! for in_gdb in gdb_lst: process_gdb(in_gdb, out_dir, ds_set, items)
Here is where each gdb gets processed in a loop:
def process_gdb(in_gdb, out_dir, ds_set, items): # Get the fully-qualified prefix from the in_gdb (this would matter # on e.g. an SDE GDB, on a file GDB there is no prefix) pfx = tls.get_full_fclass_name_pfx(in_gdb) out_gdb = tls.create_gdb_in_dir(in_gdb, out_dir) try: # Export our feature classes to our temp gdb export_feature_classes(in_gdb, out_gdb, ds_set, items, pfx) except CustomException as err: # CustomException is being used to to catch exceptions at specific # points and try to continue with the next GDB. return # Check and repair geometry on exported fclasses... uses: # arcpy.CheckGeometry_management # arcpy.RepairGeometry_management try: check_and_repair_geometries(out_gdb, out_dir) except CustomException as err: # do something return # Here we check if everything on items got exported and update items # accordingly env.workspace = out_gdb exported = arcpy.ListFeatureClasses() items = get_exported_list(exported, items) try: remove_non_keep_fields(in_gdb, out_gdb, items, stage) except CustomException as err: # do something return # ... Some more steps on the processing which are not giving trouble ... tls.print_msg('\n>>> ready! <<<')
Here is the export part:
def export_feature_classes(in_gdb, out_gdb, ds_set, export_lst, pfx): env.workspace = in_gdb datasets = arcpy.ListDatasets() for ds in ds_set: ds_full = tls.prepend_prefix(pfx, ds) # Make sure this dataset exists if not ds_full in datasets: tls.print_msg("... !! dataset '%s' not found, skipping... " % ds_full) continue items = [it for it in export_lst if it.dataset == ds] ds_workspace = os.path.join(in_gdb, ds_full) export_feature_classes_in_ds(in_gdb, out_gdb, ds_workspace, items, pfx) def export_feature_classes_in_ds(in_gdb, out_gdb, workspace, items, pfx): # Set the workspace to the dataset env.workspace = workspace # Get a list of existing feature classes to make sure the fc we're # trying to export exists in the first place fc_existing = arcpy.ListFeatureClasses() for it in items: name = it.fclass.name # this returns the fully qualified name for the feature class fc_full = tls.prepend_prefix(pfx, name) if not fc_full in fc_existing: # feature class does not exist in dataset, so skip it continue fc_path = os.path.join(workspace, fc_full) #first check that the fclass is not empty cnt = int(arcpy.GetCount_management(fc_path).getOutput(0)) if not cnt: # feature class is empty, so skip it continue """ Here is where Error 1) occurs: ERROR 000210: Cannot create output C:\some_path\temp.gdb\dataset_name Failed to execute (FeatureClassToFeatureClass)` """ try: arcpy.FeatureClassToFeatureClass_conversion(fc_path, out_gdb, name) except Exception as e: # do something raise CustomException(msg)
And here is where the non-required fields are being removed from each feature class:
def remove_non_keep_fields(in_gdb, out_gdb, items): # get the names of the feature classes to process for it in items: fc = it.fclass.name keep_fields = [f.name for f in it.fields] try: rm_fields_from_list(out_gdb, fc, keep_fields) except Exception as error: # Try something desperate ... show some nice messages... # etc. def rm_fields_from_list(workspace, fclass, lst): # set env to the out_gdb arcpy.env.workspace = workspace arcpy.env.overwriteOutput = True # only remove non-required fields, so check lst first and exclude # required ones to_delete = function_that_returns_a_list_of_names(lst) """ Here is where Error 2) occurs: `ExecuteError: ERROR 000229: Cannot open C:\some_path\temp.gdb\dataset_name Failed to execute (DeleteField)` """ arcpy.DeleteField_management(fclass, to_delete)
I'm assuming that the errors are caused by a lock that sometimes is not released and sometimes it is. But why? How can I avoid it, or at least make a workaround?
I already made a function that will retry for 3 or more times the operations if an exception occurs before it finally gives up, but it didn't help.
I also tried removing any left locks by doing, as proposed on this answer, an
arcpy.Exists followed by an
arcpy.Compact_management by calling the
clearWSLocks function 'StacyR' posted on his comment. This
clearWSLocks is called before each retry in the function I mentioned above, and every time the function returns a message with "Workspace clear to continue" ... but the delete in
rm_fields_from_lst keeps raising the same exception sigh
Q: Most commonly locks are left by insert/update cursors, are you using these? if so can you expand on how you're managing them.
A: On this script I'm not using any insert/update cursors. But normally I would put them on a block with
with arcpy.da.<Insert/Update>Cursor as csr: to avoid any locks.
If feature class to feature class is giving you problems try CopyFeatures_management resources.arcgis.com/en/help/main/10.2/index.html#//… instead."
Ok. I will try that. But actually most of the random errors happen on #2, when trying to delete the fields that we don't want to keep. But as I said, there is absolutely no pattern for when and why is this happening. Not the number of fields, or if the feature class has many/few features inside... absolutely no pattern that I can recognize.
Ok, I think I've finally got a workaround which will probably work. I'm tracking progress of all items, and if at some stage an exception for that item is caught, then I save the failed state to the
Item and continue with the others.... when I'm done with
process_gdb, then I try again to process all failed items. Let's say that a max. of 3 tries for each item should avoid ending in an endless loop. That should probably work. But finding the cause of the random errors and avoiding them on the first place would still be really nice.
I'll definitely keep trying to find the cause and post any more hints (if any) here.