replaceDataSource for layers within a group layer

3259
5
Jump to solution
11-11-2013 12:48 PM
TimBarnes
Occasional Contributor III
I've written a script to support a move to file geodatabases- It basically updates standard layer files (.lyr) to point to the .gdb database instead of the .mdb database. It works for simple layers but I can't get it to update layers within a group layer.

Here's the relevant code- The tool fails at the lyrObj.save() with a 'AssertionError: No filename set'

for layerFile in arcpy.ListFiles("*.lyr"): # find the actual layer files in the folder     arcpy.AddMessage("Found layer file: " + str(layerFile))     lyr = arcpy.mapping.Layer(folder + "\\" + layerFile) # make layer object from layer file      for lyrObj in arcpy.mapping.ListLayers(lyr):# a layer file may have multiple layers within it so work through those...         if lyrObj.isGroupLayer == 1: # if it is a group layer             arcpy.AddMessage("This layer file contains grouped items")             for item in lyrObj:                 arcpy.AddMessage("It contains a layer object named: " + item.name)                 newWS = item.workspacePath.replace(".mdb", ".gdb")                 newSource = item.dataSource.replace(".mdb", ".gdb")                 arcpy.AddMessage("dataSource: " + newWS)                 if arcpy.Exists(newSource):                     arcpy.AddMessage("I've found a replacement GDB for this so I'll update this layer.")                     item.replaceDataSource (newWS, "FILEGDB_WORKSPACE")                  else:                     arcpy.AddMessage(newSource + " DOES NOT exist. Will not update this layer.")             lyrObj.save()


The same method works for saving a non-grouped layer and I've tried saving the 'item' as well....Any ideas?
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
TimBarnes
Occasional Contributor III
OK got it working now...its just a real pain to distinguish between a group layer 'container', a layer within that container and just a simple layer. Since the group layer 'container' doesn't support the workspacePath, I've had to split it out....perhaps just putting it inside a try block would work....
Anyway, here's the working code.
import arcpy import arcpy.mapping import os, sys, string, logging from arcpy import env  # Folder- the folder where you want to search for the layer files folder = arcpy.GetParameterAsText(0)  arcpy.env.workspace = folder arcpy.AddMessage("Searching the input folder for layer files: " + folder)  for layerFile in arcpy.ListFiles("*.lyr"): # find the actual layer files in the folder     lyr = arcpy.mapping.Layer(folder + "\\" + layerFile) # make layer object from layer file      for lyrObj in arcpy.mapping.ListLayers(lyr):# a layer file may have multiple layers within it so work through those...         if lyr.isGroupLayer:             #arcpy.AddMessage(layerFile + " is a group layer.")             if lyrObj.longName != str(lyr.name): # just update the layers within the group layer                 arcpy.AddMessage(layerFile + " contains a layer object named: " + lyrObj.name)                 newWS = lyrObj.workspacePath.replace(".mdb", ".gdb")                 newSource = lyrObj.dataSource.replace(".mdb", ".gdb")                 if arcpy.Exists(newSource):                     arcpy.AddMessage("Updating " + lyrObj.name + " with replacement GDB.")                     lyrObj.replaceDataSource (newWS, "FILEGDB_WORKSPACE")                     lyr.save()                 else:                     arcpy.AddMessage(newSource + " DOES NOT exist. Will not update this layer.")          elif lyr.isGroupLayer == 0:             newWS = lyr.workspacePath.replace(".mdb", ".gdb")             newSource = lyr.dataSource.replace(".mdb", ".gdb")             if arcpy.Exists(newSource):                 arcpy.AddMessage("Updating " + lyr.name + " with replacement GDB.")                 lyr.replaceDataSource (newWS, "FILEGDB_WORKSPACE")                 lyr.save()             else:                 arcpy.AddMessage(newSource + " DOES NOT exist. Will not update this layer.")  del arcpy, os, sys, lyr


thanks for your help 🙂

View solution in original post

0 Kudos
5 Replies
T__WayneWhitley
Frequent Contributor
Shouldn't you be using the SaveToLayerFile_management command?
The following is the 10.0 webhelp ref:

Save To Layer File (Data Management)
Resource Center » Professional Library » Geoprocessing » Geoprocessing tool reference » Data Management toolbox » Layers and Table Views toolset
http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//001700000070000000

Also, I think you'll need to save at the uppermost 'level' (the outer loop where you first accessed the group), although I did not test this.

Enjoy,
Wayne
0 Kudos
T__WayneWhitley
Frequent Contributor
...also, if this helps, I think you should be able to feed lyr file objs directly into the ListLayers function -- that is to say the result is a Layer object so to preprocess by creating a Layer obj out of your ListFiles result may be redundant.  (and, if so, tends to make your code a little harder to read)

http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//00s30000002n000000

This is the command syntax, which of course for group layer files the df param is ignored:
ListLayers (map_document_or_layer, {wildcard}, {data_frame})

I did no further testing, but you may be right about using the Layer command first - I'd be interested to know if this is necessary.

Hope that helps,
Wayne
0 Kudos
TimBarnes
Occasional Contributor III
Shouldn't you be using the SaveToLayerFile_management command?
The following is the 10.0 webhelp ref:

Save To Layer File (Data Management)
Resource Center » Professional Library » Geoprocessing » Geoprocessing tool reference » Data Management toolbox » Layers and Table Views toolset
http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//001700000070000000

Also, I think you'll need to save at the uppermost 'level' (the outer loop where you first accessed the group), although I did not test this.

Enjoy,
Wayne


Thanks for the response Wayne, however, the save to layer file does something slightly different to what I'm after.

I've also tried saving the top most 'lyr' and other variations but to no avail....it always reports that I haven't set the filename.
0 Kudos
T__WayneWhitley
Frequent Contributor
I noticed this note on the save() command - I bold-typed the portion I thought relevant in your case:

save ()

There is a subtle difference between a layer (.lyr) file and a map layer (a layer in a map document). The save method only works when a variable references a layer file and will not work with a map layer. When a layer is loaded from a layer file it will remember the file name and use that when the save method is called. If a map layer is being referenced, a file name is not initially set, so you will need to use the saveACopy method instead.


So I think you need the actual obj handle for the file - so maybe this (I did not test it), notice the layerFile.save() at the end:
for layerFile in arcpy.ListFiles("*.lyr"): # find the actual layer files in the folder
    arcpy.AddMessage("Found layer file: " + str(layerFile))
    lyr = arcpy.mapping.Layer(folder + "\\" + layerFile) # make layer object from layer file

    for lyrObj in arcpy.mapping.ListLayers(lyr):
        if lyrObj.isGroupLayer == 1: # if it is a group layer
            arcpy.AddMessage("This layer file contains grouped items")
            for item in lyrObj:
                arcpy.AddMessage("It contains a layer object named: " + item.name)
                newWS = item.workspacePath.replace(".mdb", ".gdb")
                newSource = item.dataSource.replace(".mdb", ".gdb")
                arcpy.AddMessage("dataSource: " + newWS)
                if arcpy.Exists(newSource):
                    arcpy.AddMessage("I've found a replacement GDB for this so I'll update this layer.")
                    item.replaceDataSource (newWS, "FILEGDB_WORKSPACE")

                else:
                    arcpy.AddMessage(newSource + " DOES NOT exist. Will not update this layer.")
             layerFile.save()
0 Kudos
TimBarnes
Occasional Contributor III
OK got it working now...its just a real pain to distinguish between a group layer 'container', a layer within that container and just a simple layer. Since the group layer 'container' doesn't support the workspacePath, I've had to split it out....perhaps just putting it inside a try block would work....
Anyway, here's the working code.
import arcpy import arcpy.mapping import os, sys, string, logging from arcpy import env  # Folder- the folder where you want to search for the layer files folder = arcpy.GetParameterAsText(0)  arcpy.env.workspace = folder arcpy.AddMessage("Searching the input folder for layer files: " + folder)  for layerFile in arcpy.ListFiles("*.lyr"): # find the actual layer files in the folder     lyr = arcpy.mapping.Layer(folder + "\\" + layerFile) # make layer object from layer file      for lyrObj in arcpy.mapping.ListLayers(lyr):# a layer file may have multiple layers within it so work through those...         if lyr.isGroupLayer:             #arcpy.AddMessage(layerFile + " is a group layer.")             if lyrObj.longName != str(lyr.name): # just update the layers within the group layer                 arcpy.AddMessage(layerFile + " contains a layer object named: " + lyrObj.name)                 newWS = lyrObj.workspacePath.replace(".mdb", ".gdb")                 newSource = lyrObj.dataSource.replace(".mdb", ".gdb")                 if arcpy.Exists(newSource):                     arcpy.AddMessage("Updating " + lyrObj.name + " with replacement GDB.")                     lyrObj.replaceDataSource (newWS, "FILEGDB_WORKSPACE")                     lyr.save()                 else:                     arcpy.AddMessage(newSource + " DOES NOT exist. Will not update this layer.")          elif lyr.isGroupLayer == 0:             newWS = lyr.workspacePath.replace(".mdb", ".gdb")             newSource = lyr.dataSource.replace(".mdb", ".gdb")             if arcpy.Exists(newSource):                 arcpy.AddMessage("Updating " + lyr.name + " with replacement GDB.")                 lyr.replaceDataSource (newWS, "FILEGDB_WORKSPACE")                 lyr.save()             else:                 arcpy.AddMessage(newSource + " DOES NOT exist. Will not update this layer.")  del arcpy, os, sys, lyr


thanks for your help 🙂
0 Kudos