Select to view content in your preferred language

How to access Layer properties from a GPFeatureLayer / MappingLayerObject?

1224
0
07-08-2022 02:50 PM
SamSzotkowski
New Contributor III

When writing a python script tool, I often have GPFeatureLayer as the parameter type.  These are great because then Parameter.value gives you access to most of the properties and methods of a layer as accessed through arcpy.Map.listLayers(), but infuriating because you can't access some properties.  The difference is that Parameter.value is a MappingLayerObject, whatever that means, and arcpy.Map.listLayers() returns a list of arcpy.Layer objects.

So, let's say I have a python script toolbox set up something like this:

 

def getParameterInfo(self):
    param0 = arcpy.Parameter(
        name='layers',
        displayName='Layers',
        direction='Input',
        datatype='GPFeatureLayer',
        parameterType='Required',
        enabled=True
    )
    return [param0]


def execute(self, parameters, messages):
    gp_layer = parameters[0].value
    layer_name = gp_layer.name
    
    aprx = arcpy.mp.ArcGISProject('current')
    active_map = aprx.activeMap
    arcpy_layer = get_arcpy_layer()  # ????????
    sd_draft = active_map.getWebLayerSharingDraft(
        'HOSTING_SERVER', 'FEATURE', layer_name, [arcpy_layer]
    )

 

Now the context I was interested in was writing a tool to publish a bunch of layers as web layers, one by one.  So that means I had to use the method arcpy.Map.getWebLayerSharingDraft(), which as one of its parameters requires an arcpy.Layer object (trying to use gp_layer will throw an error).  But how do I get the right one?  It's possible to give two layers the same name, so arcpy.Map.listLayers() is useless to me.

In ArcGIS Pro, in the map properties > general tab, there's a checkbox called "Allow assignment of unique numeric IDs for sharing web layers" and it seems like it's there to solve this exact problem.  When you check that box, go into a layer's properties > general > LayerID, and you'll see indeed the layers have unique IDs.

How do we access those unique IDs, and thereby link every MappingLayerObject to the correct Layer?  For a Layer object, you hop inside the CIM and read the property called serviceLayerID:

 

aprx = arcpy.mp.ArcGISProject('current')
m = aprx.activeMap
for layer in m.listLayers():
    cim = layer.getDefinition('V3')
    layer_id = cim.serviceLayerID

 

If you run dir() on a MappingLayerObject, you'll see it shares many properties and methods with a Layer object, but getDefinition() is among the missing.  Instead, there is a method called GetCimJSONString(), which gives you basically the same thing as getDefinition(), but as a string.

So finally, I would write a function like the following, and call it on line 19 of my first snippet.

 

import json
def get_arcpy_layer(gp_feature_layer, pro_map):
    gp_cim = json.loads(gp_feature_layer.GetCimJSONString())
    gp_layer_id = gp_cim['serviceLayerID']

    for layer in pro_map.listLayers():
        cim = layer.getDefinition('V3')
        layer_id = cim.serviceLayerID
        if layer_id == gp_layer_id:
            return layer

 

Thanks for reading, I hope this is helpful to somebody someday.  I have struggled with this concept in many more contexts beyond just publishing web layers.

0 Replies