Change layer source

2021
5
06-17-2014 10:08 AM
New Contributor III
I am working on a script that will walk a directory and change the source for a layer. This way when we move data I can just set this script to go update everyone's maps. In my own folder I can get it to run down to printing the layer source, I just can't get the replaceDataSource function to work. Any help? This is in 10.1

Also will I be able to replace a source to something that is loaded from a group or basemap layer?

#import site-packages, modules and set enviroment
import arcpy, os

#initialize variables
extList = ["mxd"]
mappaths = []

targetDir = r"Z:\Working\MXDs"
oldPath = r"Z:\Working\MXDs\Export_Output.shp"
newPath = r"Z:\Working\Export_Output.shp"


#Loop through each MXD in the folder and writes path to a list
for root, dirs, files in os.walk(targetDir):
    for filename in files:
        splitFilename = filename.split(".")
        if splitFilename[-1] in extList:
            fullpath = os.path.join(root, filename)
            mappaths.append(fullpath)

#prints list
for maps in mappaths:
    print maps
    mxd = arcpy.mapping.MapDocument(maps)
    for layer in arcpy.mapping.ListLayers(mxd):
        if layer.supports("DATASOURCE"):
            if layer.dataSource == oldPath:
                print "Layer: " + layer.name + "\n  Source: " + layer.dataSource
##                layer.replaceDataSource(newPath, "NONE")

print "End Script"


Results when running the code:
>>>
Z:\Working\MXDs\BrkLyr_Map_2.mxd
Layer: Export_Output
Source: \Working\MXDs\Export_Output.shp
Traceback (most recent call last):
File "Z:\Utilities\Python\Wes PYSCRIPTS\Tests\FindBrokenLayers_2for.py", line 41, in <module>
layer.replaceDataSource(newPath, "NONE")
File "C:\Program Files (x86)\ArcGIS\Desktop10.1\arcpy\arcpy\utils.py", line 181, in fn_
return fn(*args, **kw)
File "C:\Program Files (x86)\ArcGIS\Desktop10.1\arcpy\arcpy\_mapping.py", line 680, in replaceDataSource
return convertArcObjectToPythonObject(self._arc_object.replaceDataSource(*gp_fixargs((workspace_path, workspace_type, dataset_name, validate), True)))
ValueError: Layer: Unexpected error
Tags (2)
Reply
0 Kudos
5 Replies
Frequent Contributor
Its likely because you need to specify the workspace path(the folder the file is in, not the file) with the first parameter, and then the workspace type (optional) then dataset name(optional) then validate(optional).  If you give the workspace in the first parameter, and not the file itself, it will probably work.

So it would be

newpath =  r"Z:\Working"
layer.replaceDataSource(newPath, "None")
Reply
0 Kudos
Occasional Contributor
It looks like your new path:
newPath = r"Z:\Working\Export_Output.shp" 

is the full path, while the workspace_path parameter of the replaceDataSource method requires directory name (not the file name too).

The data source method requires the following:

replaceDataSource (workspace_path, workspace_type, {dataset_name}, {validate})

Maybe try this:

layer.replaceDataSource(os.path.dirname(newPath), "SHAPEFILE_WORKSPACE", os.path.basename(newpath))
Reply
0 Kudos
New Contributor III
I tired iamuarry's and it ran with no error but didn't fix the layer source.

I tried eibemn's solution and I am getting the same error.
Reply
0 Kudos
Occasional Contributor II
May be worth trying mxd.findAndReplaceWorkspacePaths (find_workspace_path, replace_workspace_path, {validate}) .  Then you wouldn't have to loop through the layers either.  Also, for your walking code, you could save a couple of steps and use the string.endswith() method.

#Loop through each MXD in the folder and writes path to a list
for root, dirs, files in os.walk(targetDir):
    for filename in files:
        if filename.endswith(".mxd")
            #append to list
Reply
0 Kudos
New Contributor III
Well most of my code was correct.  It was the maps that were somehow messed up.  I don't know if my process of building and correcting this script corrupted the maps or what.  I made 3 new test maps and it ran fine using replaceDataSource and findAndReplaceWorkspacePath.  Also I forgot the mxd.save() and del mxd at the end of my for loop.
Reply
0 Kudos