Solved! Go to Solution.
i am pretty sure you are getting that error because you are trying to save layer when in fact the object you have at the point is not a layer - but is in fact a layer within a group layer. You need to be saving the group layer
the below change might work.........
#This comparison test for layers in a group layer vs those not in. The .longName property includes all group layers as part of path
if singlelayer.name != singlelayer.longName:
outputFile.write(pathfull + "\t" + singlelayer.longName + "\t" + singlelayer.name + "\t" + dataSourceOrig + "\t" + dataSourceNew + "\t" + "GROUP LAYER SOURCE" "\n")
singlelayer.findAndReplaceWorkspacePath(sourceString, replacementString, True)
print "%s group source changed" % singlelayer
#singlelayer.save()
layer.save()
print "%s saved" % singlelayer
Thanks Ciaran, i tried your suggestion
As soon as it hits Group Layer, it prints below and exits.
"
MainLayer.lyr is a group layer
"Layer1" is a layer inside MainLayer.lyr
name: Layer1
long name: Layer1
Layer1 is a single layer
Error: Layer: Unexpected error
"
Hi
I am publishing this example script even though the question is marked answered because as a novice python programmer I needed the full complete picture to help me understand what is happening. It's true that the issue above is that the group layer file cannot be treated as the individual layer files. The answers above addressed that issue - I just had a hard time understanding how to handle it differently. In this script, the group layer file is identified and then the layers inside it are handled as a new layer object.
This is the script I used to process a directory of folders and layer files numbering over 700 when we switched SDE servers.
The script fails on some things (it doesn't like representations, and a few other odd ducks) but it processed well over 90% just fine, and that was good enough for us. The remaining will be dealt with individually.
This script also incorporates logging which reports actions to the screen and to a log file, so that you have a record of what was processed and what failed. I then wrote another script which read the log file and pull out into a summary page what failed. That is optional obviously.
I do not take credit for coming up with this myself. I found another post at gis.stackexchange.com that got me quite far by Tim Barnes, also located here: replaceDataSource for layers within a group layer
The zip file attached contains the logging config file referenced in the script below. "Logging" is a standard python module.
#!/usr/bin/env python #******************************************************************************************************************** # Name: FixLayerFileSourcePaths.py # Created: 3/10/2016 # Version: ArcGIS 10.4 # Author: Ann Stark, City of Bellingham # Modifications: # Dependencies: logging config file # Description: Reads a directory and all sub directories, replacing the source data path for layer files. # In the example below an SDE connection was being moved from one server to another server. # Richmond # Called by: # Arguments: None #********************************************************************************************************************* # to use this script # 1. copy this script and the logging config file to a location # 2. modify the logging file config path to point to your config file. # 3. modify the "sourceString" and "replacementString" variables to be the old and new paths you want to replace. # 4. modify the "folder" variable to be the highest level folder that you want to search for .lyr files. This script runs through the folder listed and all folders within it. #********************************************************************************************************************* import time tic = time.clock() import os, sys, string, logging import arcpy import arcpy.mapping from arcpy import env import logging import logging.config # Where is the logging config file. logging.config.fileConfig(r"N:\scripts\arcgis\speedsongPathFixes\logging\logging.conf", disable_existing_loggers=False) #modify this path to point to your config file. logging.info('--> STARTED Script') # Folder- the folder where you want to search for the layer files folder = r"N:\LayerFiles_Speedsong\water utilities" #directory to search for lyr files logging.info('PROCESSING {}'.format(folder)) #folder = arcpy.GetParameterAsText(0) sourceString = r"Richmond_" #oldpath replacementString = r"Speedsong_" #newpath logging.info("Replacing {} with {}".format(sourceString, replacementString)) for path, dirs, files in os.walk(folder): #walk through all sub folders logging.info(" Now processing {}".format(path)) arcpy.env.workspace = path try: for layerFile in arcpy.ListFiles("*.lyr"): try: # find the actual layer files in the folder lyr = arcpy.mapping.Layer(path + "\\" + layerFile) # make layer object from layer file for lyrObj in arcpy.mapping.ListLayers(lyr): try: # a layer file may have multiple layers within it so work through those... if lyr.isGroupLayer: #logging.info(layerFile + " is a group layer.") #arcpy.AddMessage(layerFile + " is a group layer.") #arcpy.AddMessage(lyrObj.longName +":"+ lyrObj.name) if lyrObj.name.find('Build') >= 0: pass #this skips our buildings representation elif lyrObj.longName !=str(lyr.name): # just update the layers within the group layer #arcpy.AddMessage(layerFile + " contains a layer object named: " + lyrObj.name) logging.info(layerFile + " contains a layer object named: " + lyrObj.name) newWS = lyrObj.workspacePath.replace(sourceString, replacementString) newSource =lyrObj.dataSource.replace(sourceString, replacementString) if arcpy.Exists(newSource): #arcpy.AddMessage("Updating " + lyrObj.name + " with replacement GDB.") #lyrObj.replaceDataSource(newWS, "FILEGDB_WORKSPACE") lyrObj.findAndReplaceWorkspacePath(sourceString, replacementString, True) lyr.save() logging.info(" Updated " + lyrObj.name) else: logging.info(newSource + " DOES NOT exist. Will not update this layer.") elif lyr.isGroupLayer == 0: newWS = lyr.workspacePath.replace(sourceString, replacementString) newSource = lyr.dataSource.replace(sourceString, replacementString) if arcpy.Exists(newSource): logging.info("Updating {} with replacement source path.".format(lyr.name)) #lyr.replaceDataSource (newWS, "FILEGDB_WORKSPACE") #use this when changing source types (shp to fgdb for example.) lyrObj.findAndReplaceWorkspacePath(sourceString, replacementString, True) lyr.save() else: logging.info(newSource + " DOES NOT exist. Will not update this layer.") except Exception as e: logging.error(str(e)) except Exception as e: logging.error(str(e)) except Exception as e: import traceback map(arcpy.AddError, traceback.format_exc().split("\n")) arcpy.AddError(str(e)) logging.error(str(e)) del arcpy, os, sys, lyr logging.info("--> FINISHED script") toc = time.clock() ElapsedTime = round((toc - tic)/60, 2) logging.info(" ElapsedTime is {0} minutes\n\n".format(ElapsedTime)) # uncomment the last two lines if you want to open the log file automatically after the script runs. # change the path to your log file. #import webbrowser #webbrowser.open(r"c:\your\path\to\the\SpeedsongPathFix.log")
This was just what I was looking for. Well commented too. Great work!