Select to view content in your preferred language

Unable to change data source path for group layer file

6738
13
Jump to solution
06-01-2012 07:02 AM
jayshukla
Regular Contributor
Hi There,
I am having some difficulty changing the data source for a grooup layer. Below is the code that i am using. It processes LYR file successfully that has single data source but if LYR file has more than one data layers, it doesn't do it. Appreciate any feedback.

Thanks
Jay  



import arcpy, datetime, os, io, sys

try:

    #Read input parameters from GP dialog
   
 
    # Prod Setting...
    folderPath = arcpy.GetParameterAsText(0)
    output = arcpy.GetParameterAsText(1)
    sourceString = r"P:\Temp" #
    replacmentString = r"Z:\Temp" #
   
    #Create an output file
    outFile = open(output, "w")

    #Loop through each "LYR" file
    count = 0
    for path, dires, files in os.walk(folderPath):
        #for filename in os.listdir(folderPath):
        for filename in files:
            #fullpath = os.path.join(folderPath, filename)
            fullpath = os.path.join(path, filename)

            if os.path.isfile(fullpath):
                if filename.lower().endswith(".lyr"):
                    groupLayerName = ""
                    #Reference LYR
                    layerFile = arcpy.mapping.Layer(fullpath)

                    #Reference each layer in a layer file
                    count = 1
                    for lyr in arcpy.mapping.ListLayers(layerFile):
                        if lyr.isGroupLayer:
                            groupLayerName = lyr.name

                        if lyr.supports("DATASOURCE"):
                            dataSourceOrig = str(lyr.dataSource)
                            if dataSourceOrig.find(sourceString) >= 0:
                               
                                dataSourceNew = dataSourceOrig.replace(sourceString, replacmentString)

                                if groupLayerName:
                                    outFile.write(fullpath + "\t" + groupLayerName + "\t" +lyr.name + "\t"  + dataSourceOrig + "\t" + dataSourceNew + "\t" + "GROUP LAYER SOURCE" "\n")
                                    lyr.findAndReplaceWorkspacePath(sourceString, replacmentString, True)
                                    lyr.save()
                                else:
                                    outFile.write(fullpath + "\t" + "Non Group Layer" + "\t" + lyr.name + "\t" + dataSourceOrig + "\t" + dataSourceNew + "\t" + "SINGLE LAYER SOURCE" "\n")
                                    lyr.findAndReplaceWorkspacePath(sourceString, replacmentString, True)
                                    lyr.save()
                    del layerFile

    outFile.close()

    #Open the resulting text file
    os.startfile(output)

    #Delete variables that reference data on disk
    del outFile
   
except Exception, e:
  import traceback
  map(arcpy.AddError, traceback.format_exc().split("\n"))
  arcpy.AddError(str(e))
0 Kudos
13 Replies
ciarandoyle1
Deactivated User

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

0 Kudos
User35489
Frequent Contributor

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

"

0 Kudos
AnnStark2
Occasional Contributor

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")
TrevorBurgan
Occasional Contributor

This was just what I was looking for.  Well commented too.  Great work!

0 Kudos