Hello,
Where in arcpy for ArcGIS Pro can you obtain the workspaces from the map or layers? I cannot find this property in documentation? Specially I am looking for the name and path of the SDE connection file. This was very helpful when resourcing maps as we use standardize SDE connection names so we migrate maps to other environments we easily find and replace the workspace connection locations & names.
In arcpy.mapping for layers in MXDs there is a property which returns the workspacePaths for the layer. The reference is below.
https://desktop.arcgis.com/en/arcmap/latest/analyze/arcpy-mapping/layer-class.htm
In the ArcGIS Pro this help has an example of using the updateConnectionProperties method. For Enterprise Geodatabases, how does one obtain this connection string so this can be achieved?
https://pro.arcgis.com/en/pro-app/latest/arcpy/mapping/updatingandfixingdatasources.htm
There is an info tip in the Layer help stating there is no reference to the .sde connection file.
https://pro.arcgis.com/en/pro-app/latest/arcpy/mapping/layer-class.htm
Tip:
Enterprise geodatabase layers in an ArcGIS Pro project
do not retain the path to the database connection file (.sde)
that was used to create the layer.
Without the original workspacePath/connection string how is it possible to read the .SDE connections from the map and update them programmatically using updateConnectionProperties?
Solved! Go to Solution.
I used Describe
import arcpy
import os
def getWorkspaceInfo(map_layer):
"""Takes an input map layer object and returns a dictionary with workspace information.
"""
try:
# Get workspace of input map layer
workspace_path = arcpy.Describe(map_layer).catalogPath
# Walk up the catalogPath until it's at the connection file.
while not workspace_path.endswith('.sde'):
if workspace_path == os.path.dirname(workspace_path):
# You've reached the end (beginning) of the path.
raise OSError("This catalogPath does not have an sde connection file.")
workspace_path = os.path.dirname(workspace_path)
workspace_desc = arcpy.Describe(workspace_path)
workspace_instance = workspace_desc.connectionProperties.instance
workspace_version = workspace_desc.connectionProperties.version
# Get only the portion of the instance after the last colon character.
# This might not be necessary depending on your rdbms.
workspace_instance = workspace_instance.rsplit(":", 1)[1]
if workspace_instance and workspace_version:
return {
"workspace_path": workspace_path,
"workspace_instance": workspace_instance,
"workspace_version": workspace_version
}
else:
# workspace_instance or workspace_version is missing.
raise AttributeError(f"workspace_instance is {workspace_instance}; workspace_version is {workspace_version}")
except Exception as e:
raise arcpy.ExecuteError(
f"Unable to get workspace instance and version from map_layer {map_layer.name}"
) from e
# Get workspace path to .sde file
workspace_info = getWorkspaceInfo(my_map_layer_obj)
workspace_path = workspace_info["workspace_path"]
I used Describe
import arcpy
import os
def getWorkspaceInfo(map_layer):
"""Takes an input map layer object and returns a dictionary with workspace information.
"""
try:
# Get workspace of input map layer
workspace_path = arcpy.Describe(map_layer).catalogPath
# Walk up the catalogPath until it's at the connection file.
while not workspace_path.endswith('.sde'):
if workspace_path == os.path.dirname(workspace_path):
# You've reached the end (beginning) of the path.
raise OSError("This catalogPath does not have an sde connection file.")
workspace_path = os.path.dirname(workspace_path)
workspace_desc = arcpy.Describe(workspace_path)
workspace_instance = workspace_desc.connectionProperties.instance
workspace_version = workspace_desc.connectionProperties.version
# Get only the portion of the instance after the last colon character.
# This might not be necessary depending on your rdbms.
workspace_instance = workspace_instance.rsplit(":", 1)[1]
if workspace_instance and workspace_version:
return {
"workspace_path": workspace_path,
"workspace_instance": workspace_instance,
"workspace_version": workspace_version
}
else:
# workspace_instance or workspace_version is missing.
raise AttributeError(f"workspace_instance is {workspace_instance}; workspace_version is {workspace_version}")
except Exception as e:
raise arcpy.ExecuteError(
f"Unable to get workspace instance and version from map_layer {map_layer.name}"
) from e
# Get workspace path to .sde file
workspace_info = getWorkspaceInfo(my_map_layer_obj)
workspace_path = workspace_info["workspace_path"]
Thank you @BlakeTerhune that was very quick and this is perfect!
I'll have to test but does describe work on broken data sources as well?
I haven't tested it with broken data sources. I'm not sure how it would handle that.
For some reason this Describe catalog path does not return the original SDE Connection used. The map document was authored using a UNC path with standardized names and a temporary .sde connection was returned. Does it return the expected .sde connection file name and path in your situation?
The map was authored with data from: \\servername\publish\readuser@prodDB_web_sde.sde\web_sde.GIS.COUNTY_BOUNDARY
The describe returns: C:\Users\username\AppData\Local\Temp\1\a2190f00b0450b088ca7cd2e92f9f4b5.sde\web_sde.GIS.COUNTY_BOUNDARY
This might be what that little tip was indicating in the layer help but this is not at all helpful if the sde connections are always in the local profile with the orignal naming destroyed.
That is my observation as well. It seems ArcGIS Pro makes some kind of temporary copy of the connection file while the app is open. However, I've been able to do everything I need with this connection file (short of knowing where the original sde file is).
Thanks for the confirmation @BlakeTerhune ! Your solution is perfect to obtain a path to a .sde workspace. ArcGIS Pro seems to copy or create the sde connection into the local profile. It's unfortunate the original path was not preserved but maybe this was removed due to security or other issues if source connections are exposed.
On this end, we will proceed with resourcing data on what exists in the connection properties. Thanks for your response to this