Hello, I am relatively new to Python scripting, and trying to automate a task at work. Basically, the script is supposed to copy a shape file [named 'backbone'] from the env.workspace into the specified file GDB. The script works fine, but I am trying to run this script numerous times by changing the env.workspace and re-running the script.
With that being said, if there was a feature class in the file GDB already named 'backbone', the original script would copy the new one over the original. I thought that arcpy.ValidateName() was the function used to prevent this from happening, and it would rename the new feature class so the original would not be written over; is this a misconception on my end?
After some trial and error, I was able to add a nested if statement that checked for a feature class named 'backbone', and if true, would add a '1' to the end of the new feature class's name. Here lies the problem: if I change the env.workspace to another file location, it will just restart my counter variable and overwrite 'backbone1'. I'm sure the solution is simple, just beyond my elementary knowledge base; any help would be greatly appreciated! I have copy and pasted the script below:
import arcpy
from arcpy import env
env.overwriteOutput = True
env.workspace = 'C:/Users/MWright/Downloads/YaleToSC/'
outputEnv = 'M:/Drafting/IECcoop/PhaseIII/PawneeToYale/PawneeToYales.gdb/'
x = 'backbone'
count = 1
fclist = arcpy.ListFeatureClasses()
print(fclist)
print('\n')
for fc in fclist:
fcdesc = arcpy.Describe(fc)
fcname = fcdesc.basename
if fcname == 'backbone':
if arcpy.Exists(x):
fcout = arcpy.ValidateTableName(fcname, outputEnv)
arcpy.CopyFeatures_management(fc, outputEnv + fcout + str(x))
print('\n' + fcname + ' has been copied to GDB.\n')
x += 1
else:
fcout = arcpy.ValidateTableName(fcname, outputEnv)
arcpy.CopyFeatures_management(fc, outputEnv + fcout + str(count))
else:
print(fcname + " feature class does not need to be copied to geodatabase.")
print('\nBackbone feature class copy process complete.')
Solved! Go to Solution.
You're really close, you just need to store the index in the feature names themselves:
import arcpy
from arcpy import env
env.overwriteOutput = True
env.workspace = 'C:/Users/MWright/Downloads/YaleToSC/'
outputEnv = 'M:/Drafting/IECcoop/PhaseIII/PawneeToYale/PawneeToYales.gdb/'
outName = 'backbone'
fclist = arcpy.ListFeatureClasses()
print(fclist)
print('\n')
# Iterate FCs in workspace (YaleToSC)
for fc in fclist:
fcdesc = arcpy.Describe(fc)
fcname = fcdesc.basename
# Check if the FC name contains the substring 'backbone'
if 'backbone' in fcname:
# Split the FC name into a list of substrings separated by '_', Use *_ to consume any additional substrings beyond the first 2
# Add None to end of list to prevent ValueError if the FC name does not contain '_' and the list has only 1 element
name, index, *_ = fcname.split('_') + [None]
# If the name is just 'backbone', initialize the index to 1
if name == 'backbone' and not index:
arcpy.CopyFeatures_management(fc, f"{outputEnv}{outName}_1")
# If the name is 'backbone' followed by a number, increment the number by 1
elif index and index.isdigit():
arcpy.CopyFeatures_management(fc, f"{outputEnv}{outName}_{int(index) + 1}")
# Ignore all non-backbone feature classes
else:
print(f'{fcname} is not a backbone feature class.')
print('\nBackbone feature class copy process complete.')
Here's a version that runs as a script and takes a list of workspaces:
import arcpy
from arcpy import env
# Iterate FCs in workspace (YaleToSC)
def copy_backbone(outputEnv, outName, fclist):
for fc in fclist:
fcdesc = arcpy.Describe(fc)
fcname = fcdesc.basename
# Check if the FC name contains the substring 'backbone'
if 'backbone' in fcname:
# Split the FC name into a list of substrings separated by '_', Use *_ to consume any additional substrings beyond the first 2
# Add None to end of list to prevent ValueError if the FC name does not contain '_' and the list has only 1 element
name, index, *_ = fcname.split('_') + [None]
# If the name is just 'backbone', initialize the index to 1
if name == 'backbone' and not index:
arcpy.CopyFeatures_management(fc, f"{outputEnv}{outName}_1")
# If the name is 'backbone' followed by a number, increment the number by 1
elif index and index.isdigit():
arcpy.CopyFeatures_management(fc, f"{outputEnv}{outName}_{int(index) + 1}")
# Ignore all non-backbone feature classes
else:
print(f'{fcname} is not a backbone feature class.')
def main():
env.overwriteOutput = True
outputEnv = 'M:/Drafting/IECcoop/PhaseIII/PawneeToYale/PawneeToYales.gdb/'
outName = 'backbone'
workspaces = ['C:/Users/MWright/Downloads/YaleToSC/', '<wsp1>', '<wsp2>', ...]
for workspace in workspaces:
env.workspace = workspace
fclist = arcpy.ListFeatureClasses()
print(f'Processing {workspace}...')
print(f'Feature classes in {workspace}: {fclist}')
copy_backbone(outputEnv, outName, fclist)
print('\nBackbone feature class copy process complete.')
if __name__ == '__main__':
main()
You're really close, you just need to store the index in the feature names themselves:
import arcpy
from arcpy import env
env.overwriteOutput = True
env.workspace = 'C:/Users/MWright/Downloads/YaleToSC/'
outputEnv = 'M:/Drafting/IECcoop/PhaseIII/PawneeToYale/PawneeToYales.gdb/'
outName = 'backbone'
fclist = arcpy.ListFeatureClasses()
print(fclist)
print('\n')
# Iterate FCs in workspace (YaleToSC)
for fc in fclist:
fcdesc = arcpy.Describe(fc)
fcname = fcdesc.basename
# Check if the FC name contains the substring 'backbone'
if 'backbone' in fcname:
# Split the FC name into a list of substrings separated by '_', Use *_ to consume any additional substrings beyond the first 2
# Add None to end of list to prevent ValueError if the FC name does not contain '_' and the list has only 1 element
name, index, *_ = fcname.split('_') + [None]
# If the name is just 'backbone', initialize the index to 1
if name == 'backbone' and not index:
arcpy.CopyFeatures_management(fc, f"{outputEnv}{outName}_1")
# If the name is 'backbone' followed by a number, increment the number by 1
elif index and index.isdigit():
arcpy.CopyFeatures_management(fc, f"{outputEnv}{outName}_{int(index) + 1}")
# Ignore all non-backbone feature classes
else:
print(f'{fcname} is not a backbone feature class.')
print('\nBackbone feature class copy process complete.')
Here's a version that runs as a script and takes a list of workspaces:
import arcpy
from arcpy import env
# Iterate FCs in workspace (YaleToSC)
def copy_backbone(outputEnv, outName, fclist):
for fc in fclist:
fcdesc = arcpy.Describe(fc)
fcname = fcdesc.basename
# Check if the FC name contains the substring 'backbone'
if 'backbone' in fcname:
# Split the FC name into a list of substrings separated by '_', Use *_ to consume any additional substrings beyond the first 2
# Add None to end of list to prevent ValueError if the FC name does not contain '_' and the list has only 1 element
name, index, *_ = fcname.split('_') + [None]
# If the name is just 'backbone', initialize the index to 1
if name == 'backbone' and not index:
arcpy.CopyFeatures_management(fc, f"{outputEnv}{outName}_1")
# If the name is 'backbone' followed by a number, increment the number by 1
elif index and index.isdigit():
arcpy.CopyFeatures_management(fc, f"{outputEnv}{outName}_{int(index) + 1}")
# Ignore all non-backbone feature classes
else:
print(f'{fcname} is not a backbone feature class.')
def main():
env.overwriteOutput = True
outputEnv = 'M:/Drafting/IECcoop/PhaseIII/PawneeToYale/PawneeToYales.gdb/'
outName = 'backbone'
workspaces = ['C:/Users/MWright/Downloads/YaleToSC/', '<wsp1>', '<wsp2>', ...]
for workspace in workspaces:
env.workspace = workspace
fclist = arcpy.ListFeatureClasses()
print(f'Processing {workspace}...')
print(f'Feature classes in {workspace}: {fclist}')
copy_backbone(outputEnv, outName, fclist)
print('\nBackbone feature class copy process complete.')
if __name__ == '__main__':
main()
This helps so much - thanks for pointing me in the right direction!