8 Replies Latest reply on Feb 4, 2013 7:09 AM by jbarrette-esristaff

    replaceDataSource OR findAndReplaceWorkspacePath for CAD files

    DrColgate
      I've been trying to update the links to CAD that have had their name changed and have been moved to a different location but have had no changes made to the data itself.

      Essentially the Original Path and the New Path are taken from an existing List and the data is updated as either:

      layer.replaceDataSource(unicode(DATA_PATH), FILE_TYPE, unicode(FILE_NAME))
      


      OR

      layer.findAndReplaceWorkspacePath(unicode(PREV_PATH), unicode(DATA_PATH))
      



      Either way I get the same error:

      <type 'exceptions.ValueError'>: Layer: Unexpected error
      Failed to execute (BatchMxdDataSourceUpdate).


      Where "BatchMxdDataSourceUpdate" is the routine that I am running to update that MXD data sources.

      I am using the same code to loop through and update from SHP to GDB, GDB to GDB and also replacing Raster so I am not sure why it is not working for CAD files.  Each has a different handler but is essentially the same syntax.  In this case the CAD files are DXF but I have other instances of DWG that will also need to be updated in the future.
        • Re: replaceDataSource OR findAndReplaceWorkspacePath for CAD files
          jbarrette-esristaff
          I'll do some testing with CAD files.  In the meantime, have you tried

          MXD.findAndReplaceWorkspacePaths?

          Jeff
          • Re: replaceDataSource OR findAndReplaceWorkspacePath for CAD files
            jbarrette-esristaff
            I tested several scenarios using DXF and DWG.  I reproduced the error once until I realized the mistake.

            1) CAD layers are often group layers but you can't change a data source on a group layer.
            2) Make sure you get the name correct.  The default layer name is not the same as the feature class name.  For example, the layer name may be "buildings.dxf Point".  You must use "Point" as the dataset_name value, not the whole string.

            Here are the tests that I did:

            import arcpy
            mxd = arcpy.mapping.MapDocument(r"C:\Temp\CAD.mxd")
            
            '''CAD files are being remapped from a folder called Drive_A to a
            folder called Drive_B.  Also, in the MXD, I renamed the layers to
            represent only the feature class name in the CAD file.'''
            
            #Test #1
            mxd.findAndReplaceWorkspacePaths("Drive_A", "Drive_B")
            mxd.saveACopy(r"C:\Temp\CAD_Test1.mxd")
            del mxd
            
            #Test #2
            mxd = arcpy.mapping.MapDocument(r"C:\Temp\CAD.mxd")
            for lyr in arcpy.mapping.ListLayers(mxd):
              lyr.findAndReplaceWorkspacePath("Drive_A", "Drive_B")
            mxd.saveACopy(r"C:\Temp\CAD_Test2.mxd")
            del mxd
            
            #Test #3
            mxd = arcpy.mapping.MapDocument(r"C:\Temp\CAD.mxd")
            for lyr in arcpy.mapping.ListLayers(mxd):
              if lyr.isGroupLayer == False:
                lyr.replaceDataSource(r"C:\Active\ArcPY\ScrumWorks\Data\Drive_B",
                                      "CAD_WORKSPACE", lyr.name)
            mxd.saveACopy(r"C:\Temp\CAD_Test3.mxd")
            • Re: replaceDataSource OR findAndReplaceWorkspacePath for CAD files
              DrColgate
              Thanks for your help.

              I have had a look at your code and I am still not able to figure out where I am going wrong but I am hoping if I explain what I am doing a little more clearly it will help you help me =D

              I have a CSV file from which I am reading four columns of which I will give an example below:

              ORIGINAL_NAME_COLUMN: "Polyline"
              ORIGINAL_PATH_COLUMN: "C:\CAD_Directory\CAD_File.dxf"
              NEW_NAME_COLUMN:      "Polyline"
              NEW_PATH_COLUMN:      "X:\New_CAD_Directory\CAD_File_1.dxf"

              I think it is important to note that I have changed the name of the CAD file which may be where I am falling down.

              For each layer to get rid of group layers etc I run:

              if layer.supports("DATASOURCE") and layer.supports("WORKSPACEPATH"):
              


              Then I loop through the rows in the CSV and compare it to the layer data source using the following code

              if os.path.join(row[1], row[0]) == layer.dataSource:
              


              which is equivalent to something like

              if "C:\CAD_Directory\CAD_File.dxf\Polyline" == layer.dataSource:
              


              If this succeeds I attempt to change the data source.  As the Data Source in 'layer.DataSource' goes to the full DXF path then I have assumed this would be the code for the 'ReplaceDataSource'

              Now from your code I understand that you are pointing to a directory rather than the DXF as the data source.  To continue using my example above

              Your code would be similar to:

              layer.replaceDataSource(r"X:\New_CAD_Directory", "CAD_WORKSPACE", layer.name)
              
              OR
              
              layer.findAndReplaceWorkspace(r"C:\CAD_Directory", r"X:\New_CAD_Directory")
              



              Where as my code looks like this:
              layer.replaceDataSource(r"X:\New_CAD_Directory\CAD_File_1.dxf", "CAD_WORKSPACE", layer.name)
              
              OR
              
              layer.findAndReplaceWorkspace(r"C:\CAD_Directory\CAD_File.dxf", r"X:\New_CAD_Directory\CAD_File_1.dxf")
              


              If the Data Source is only to the directory level then I am uncertain as to how to map to a new DXF name.  Particularly if there are several CAD files in there as I would assume that it automatically use the original CAD file name if pointing to a directory.  If the Data Source goes to the DXF level then I don't know why it is falling over.
              • Re: replaceDataSource OR findAndReplaceWorkspacePath for CAD files
                jbarrette-esristaff
                If the dataset name is different you must use lyr.replaceDataSource()

                A dataSource = workspace_path + dataset_name

                The syntax is lyr.replaceDataSource(workspace_path, workspace_type, dataset_name, {validate})

                You are setting the workspace_path=the entire dataSource.  No, break it  up and specify the workspacePath and datasetName as two separate parameters.

                So your code should be something like:
                layer.replaceDataSource(row[1], "CAD_WORKSPACE", row[0])
                



                Jeff
                • Re: replaceDataSource OR findAndReplaceWorkspacePath for CAD files
                  DrColgate
                  Okay, I think I have it right.  But unfortunately it is still failing so I must be doing someting wrong.

                  I have used exactly your code but replaced the old column numbers with the new ones ie 1 = 3, 0 = 2.  Which is what I think you were referring to.

                  layer.replaceDataSource(row[2], "CAD_WORKSPACE", row[3])
                  


                  This translates roughly to:

                  layer.replaceDataSource("X:\New_CAD_Directory\CAD_File_1.dxf", "CAD_WORKSPACE", "Polyline")
                  


                  I have checked the new dataset for any access issues but it works in ArcMap/ArcCatalog.  The script is still failing with the same error.
                  • Re: replaceDataSource OR findAndReplaceWorkspacePath for CAD files
                    hua17
                    Hello DrColgate and Jeff,
                    I was wondering if there were any solutions yet. I'm having the same issue (with 10.0 SP4).

                    This line works:
                    lyr.replaceDataSource("X:\\SiteA\\MappingData", "CAD_WORKSPACE", "Polyline")


                    However since there is no refference to a specific CAD file, it will connect to the first CAD file it finds in that directory (there are multiple CAD files in the directory, and I don't want the first one).

                    The line of code that would be perfect is:
                    lyr.replaceDataSource("X:\\SiteA\\MappingData\\Sheet3.dwg", "CAD_WORKSPACE", "Polyline")

                    Unfortunately, this produces the error: "ValueError: Layer: Unexpected error"

                    I've tried many variations of line above, but can't seem to get it to work.
                    Any ideas? Could this be a bug?

                    Thank you,
                    ~Josh
                    • Re: replaceDataSource OR findAndReplaceWorkspacePath for CAD files
                      DrColgate
                      No solution as yet.

                      Bug #NIM078454

                      The work around provided doesn't work so I wouldn't bother with that either.
                      • Re: replaceDataSource OR findAndReplaceWorkspacePath for CAD files
                        jbarrette-esristaff
                        This issue was addressed with 10.1 SP1.  The same problem occured with changing data sources for Coverages.  The issue was that the feature class name was "Polygon" not CAD name\Polygon or Coverage Name \ Polygon.

                        Here is some test code that is used to verify the fix.  Notice the dataset name parameter syntax.

                        import arcpy, os, sys
                        relpath = os.path.dirname(sys.argv[0])
                        mxd = arcpy.mapping.MapDocument(relpath + "\\CoverageAndCAD_DataSources.mxd")
                        covLyr = arcpy.mapping.ListLayers(mxd)[0]
                        cadLyr = arcpy.mapping.ListLayers(mxd)[1]
                        
                        covLyr.replaceDataSource(covLyr.workspacePath, "ARCINFO_WORKSPACE", "basin_utmcopy/Polygon")
                        if "utmcopy" in covLyr.dataSource:
                            print "COVERAGE: PASSED"
                        else:
                            print "COVERAGE: FAILED"
                            
                        cadLyr.replaceDataSource(cadLyr.workspacePath, "CAD_WORKSPACE", "ParcelsCopy.dwg/Polygon")
                        if "ParcelsCopy" in cadLyr.dataSource:
                            print "CAD PASSED"
                        else:
                            print "CAD: FAILED"
                        


                        Please confirm that this helps you,
                        Jeff