replaceDataSource in layer file (not mxd)

3063
12
Jump to solution
05-08-2013 08:16 AM
BrianMaier
New Contributor II
My world: Win7, ArcGIS 10.0  SP1, Python 2.6.5

I am attempting to update a group layer file with new data source locations (FGDB moved from one location to another location). I get no errors running this code, but the new file locations are not updated in the layer file.  Most of the discussions in this forum (related to this issue) are related to using an mxd, but in my case, I want to update a layer file (*.lyr). 


  • Have verified that the paths are correct (via print statements).

  • Have verified that i am updating feature classes and that they support the DATASOURCE property

  • Have also tried saving the .lyr file using "arcpy.mapping.Layer(inLayerFile).saveACopy("newfilename")"

  • I have tried findAndReplaceWorkspacePath with no success.

  • Have tried converting newPath variable to unicode - again no success.


Any help greatly appreciated!

# xModifyDataLocationsInlayerFiles.py  import sys, os import arcpy  outFolder = r"C:\Projects\CoreData\GeoName" newFolder = r"C:\projects\testmove\test2\GeoName"  inLayerFile = r"C:\projects\testmove\test2\GeoName\LayerFiles\AG10\BaseInfo.lyr"  for lyr in arcpy.mapping.Layer(inLayerFile):   pout = lyr.isFeatureLayer   if pout == True:     if lyr.supports("DATASOURCE"):       currWSPath = str(lyr.workspacePath)       scol = str.upper(currWSPath).find('GEONAME')       scol = scol + len('GEONAME') + 1       newPath = newFolder + os.sep + currWSPath[scol:]       print lyr.name + " | Path: " + newPath + " | DSN: " + lyr.datasetName       lyr.replaceDataSource(unicode(newPath), 'FILEGDB_WORKSPACE', lyr.datasetName, True)     else:       print "Layer " + lyr.name + " does not support datasource changes"   else:     pass
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
BrianMaier
New Contributor II
Thank you Jeff. Your code references objects "lyr1" and "lyr2" but these are not defined in your script. At first I assumed these would be "fullLyr" and "relLyr", but the function ListLayers doesn't support layer files, it seems to only support map documents. I can get this to work inside a map document, but I was hoping to avoid using an MXD if possible.

However, I need to get moving beyond this, so my solution is simply to open a blank mxd, add my layer file, update the source using .findAndReplaceWorkspacePath, then save the top layer of the layers in the MXD. Since I control the creation of the  layer file to begin with I know that I can save this top layer and I get the expected result.  Then I just delete the temporary mxd file.

Thank you all for your help.  My final code (which works properly) is posted here, but sadly I did have to resort to using an MXD:

import arcpy  outFolder = r"C:\Projects\CoreData\GeoName" newFolder = r"\\silver\projects\SpatialData_Core\GeoName"  inLayerFile = r"C:\Projects\testmove\test2\GeoName\LayerFiles\AG10\BaseInfo.lyr" outLayerFile = r"\\silver\projects\SpatialData_Core\GeoName\LayerFiles\AG10\BaseInfo_updated.lyr" inMXDFile = r"C:\Projects\CoreData\GeoName\LayerFiles\AG10\BaseInfo.mxd" outMXDFile = r"\\silver\projects\SpatialData_Core\GeoName\LayerFiles\AG10\BaseInfo_updated.mxd"  if arcpy.Exists(outMXDFile):     arcpy.Delete_management(outMXDFile)      if arcpy.Exists(outLayerFile):     arcpy.Delete_management(outLayerFile)  mxd = arcpy.mapping.MapDocument(inMXDFile) mxd.findAndReplaceWorkspacePaths(outFolder,newFolder, False) mxd.saveACopy(outMXDFile)  del mxd mxd = arcpy.mapping.MapDocument(outMXDFile) df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0] lyr = arcpy.mapping.ListLayers(mxd, "", df)[0] lyr.saveACopy(outLayerFile)  if arcpy.Exists(outMXDFile):     arcpy.Delete_management(outMXDFile)  print "Finished creating new Layer file: " + outLayerFile

View solution in original post

0 Kudos
12 Replies
MichaelVolz
Esteemed Contributor
In the following line,

lyr.replaceDataSource(unicode(newPath), 'FILEGDB_WORKSPACE', lyr.datasetName, True)

can you remove unicode?

Is the lyr.datasetName changing?  If not, then leave this parameter blank (e.g. "").

Can you print out the variable newPath and post the result in your thread?
0 Kudos
MathewCoyle
Frequent Contributor
I believe you have to save the layer file to make the changes permanent.
0 Kudos
BrianMaier
New Contributor II
Thanks Matthew..as per my initial post I tried doing a saveAs but just got a copy of the original (un-changed) .lyr file
Thanks Michael .. removing unicode has no impact (tried that already).  Leaving lyr.datasetName blank has no impact.

Here is a summary of the first few lines of output (there are 40 some feature layers that get updated). Data below are:

  • lyr.name (layer name)

  • newPath (full path to location of data - these are all FGDBs)

  • lyr.datasetName: the data set name


---------------------------------  output : ------------------------------------------------------------
Provincial_Boundary | New Path: C:\projects\testmove\test2\GeoName\GEOADMIN\GEOADMIN.gdb | DSN: Provincial_Boundary
Forest Management Units | New Path: C:\projects\testmove\test2\GeoName\FMU\FMU.gdb | DSN: FMU
Forest Management Agreement Areas | New Path: C:\projects\testmove\test2\GeoName\FMA\FMA.gdb | DSN: FMA
ESRD_Regions | New Path: C:\projects\testmove\test2\GeoName\GEOADMIN\GEOADMIN.gdb | DSN: ESRD_Regions
Fish_Management_Zone | New Path: C:\projects\testmove\test2\GeoName\GEOADMIN\GEOADMIN.gdb | DSN: Fish_Management_Zone
Fish_Watershed_Unit | New Path: C:\projects\testmove\test2\GeoName\GEOADMIN\GEOADMIN.gdb | DSN: Fish_Watershed_Unit
Wildlife_Management_Unit | New Path: C:\projects\testmove\test2\GeoName\GEOADMIN\GEOADMIN.gdb | DSN: Wildlife_Management_Unit
Green/White Area | New Path: C:\projects\testmove\test2\GeoName\GEOADMIN\GEOADMIN.gdb | DSN: Green_White_Area
------------------------------------------------------------------------------------------------------
The attached snapshot (from ArcCatalog shows that the FGDB and feature class exist.

[ATTACH=CONFIG]24133[/ATTACH]

Any other ideas greatly welcomed!
0 Kudos
MichaelVolz
Esteemed Contributor
How about changing True to False in the following line?

lyr.replaceDataSource(unicode(newPath), 'FILEGDB_WORKSPACE', lyr.datasetName, True)
0 Kudos
BrianMaier
New Contributor II
How about changing True to False in the following line?

lyr.replaceDataSource(unicode(newPath), 'FILEGDB_WORKSPACE', lyr.datasetName, True)


Sadly, no impact whether i use True or False.
Thanks for the suggestions, tho.  Appreciate it.
0 Kudos
BrianMaier
New Contributor II
Update:  I can get the layer references to update if I run this through an MXD. However, that does not update the .lyr file.  I also cannot save the group layer file from this mxd (well, I can save the individual layers to individual layer files, but I want one layer file with all the group layer structures intact).

This code works and the new mxd has all the updated paths.  But the updates are in the mxd and I still cannot get the replaceDataSource to work on the actual .lyr file.

import arcpy

outFolder = r"C:\Projects\CoreData\GeoName"
newFolder = r"C:\projects\testmove\test2\GeoName"

inMXDFile = r"C:\projects\testmove\test2\GeoName\LayerFiles\AG10\BaseInfo.mxd"
outMXDFile = r"C:\projects\testmove\test2\GeoName\LayerFiles\AG10\BaseInfo_updated.mxd"

mxd = arcpy.mapping.MapDocument(inMXDFile)
mxd.findAndReplaceWorkspacePaths(outFolder,newFolder, False)
mxd.saveACopy(outMXDFile)
0 Kudos
MichaelVolz
Esteemed Contributor
You will need to replacedatasource for the individual layer files in the group layer and then do a save of the group layer that holds the individual layers.

Try either one of these lines of code:

lyr.save() - I think you would put in inLayerFile in () but I'm not sure that will work as the ESRI documentation just shows it blank

lyr.saveACopy(inLayerFile)

The documentation for this is found at:

http://resources.arcgis.com/en/help/main/10.1/index.html#/Layer/00s300000008000000/
0 Kudos
BrianMaier
New Contributor II
You will need to replacedatasource for the individual layer files in the group layer and then do a save of the group layer that holds the individual layers.

Try either one of these lines of code:

lyr.save() - I think you would put in inLayerFile in () but I'm not sure that will work as the ESRI documentation just shows it blank

lyr.saveACopy(inLayerFile)

The documentation for this is found at:

http://resources.arcgis.com/en/help/main/10.1/index.html#/Layer/00s300000008000000/


Thanks Michael.  I have tried the lyr.save INSIDE the lyr loop (as it processes the individual feature layers) and that did not help
Also tried "arcpy.mapping.Layer(inLayerFile).saveACopy(outLayerFile)" (after the lyr loop is finished) also to no avail.
I have submitted this to the ESRI Canada support team as an incident, so will see how they respond.
Thank you ... appreciate all your help and ideas. Will keep the thread posted with ESRI Canada results.
0 Kudos
JeffBarrette
Esri Regular Contributor
I thought one possibility was how the layer file was created: from an MXD with or without relative paths.  I tested changeing data sources on group layers both ways and it is working for me.

import arcpy
fullLyr = arcpy.mapping.Layer(r"C:\Temp\FullPath.lyr")
lyrs = arcpy.mapping.ListLayers(lyr1)
for lyr in lyrs:
  if lyr.supports("DATASOURCE"):
    lyr.findAndReplaceWorkspacePath(r"C:\Temp", r"C:\Active\ArcPY\ScrumWorks\Data")
fullLyr.saveACopy(r"C:\Temp\FullPath2.lyr")

relLyr = arcpy.mapping.Layer(r"C:\Temp\RelPath.lyr")
lyrs = arcpy.mapping.ListLayers(lyr2)
for lyr in lyrs:
  if lyr.supports("DATASOURCE"):
    lyr.findAndReplaceWorkspacePath(r"C:\Temp", r"C:\Active\ArcPY\ScrumWorks\Data")
relLyr.saveACopy(r"C:\Temp\RelPath2.lyr")


Jeff
0 Kudos