Select to view content in your preferred language

Layer cannot be added to Group Layer when Group Layer is object from script tool

553
2
08-17-2023 10:02 AM
SzymAdamowski
Occasional Contributor

I created a tool in  ArcGISPro 3.1.2 which intends to copy layers to already existing Group Layer:

SzymAdamowski_0-1692290503637.png

(Layers FC1 and FC2 should be copied to GL1).

Script tools has one paramter (Data Type = Group Layer obviously);

SzymAdamowski_1-1692290582315.png

The script code is as following:

 

import arcpy

def script_tool(gl):
    """Script code goes below"""
    m = arcpy.mp.ArcGISProject("current").activeMap
    arcpy.AddMessage(f"I'm an object: {type(gl)}") #<class 'arcpy._mp.Layer'>
    #gl=m.listLayers("GL1")[0] #if uncommented script will work well
    #arcpy.AddMessage(f"I'm an object: {type(gl)}")
    for l in m.listLayers():
        if l.isFeatureLayer:
            arcpy.AddMessage(f"Adding {l.name} to {gl.name}")
            m.addLayerToGroup(gl,l,"BOTTOM")

if __name__ == "__main__":
    param0 = arcpy.GetParameter(0) #read as object, not value
     script_tool(param0)

 

 

 The script fails with following information:

 

 File "E:\GIS_DATA\ArcGIS\WIW\WIW.atbx#MoveLayers_WIWatbx.py", line 23, in script_tool
  File "C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\utils.py", line 191, in fn_
    return fn(*args, **kw)
  File "C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\_mp.py", line 2593, in addLayerToGroup
    return convertArcObjectToPythonObject(self._arc_object.addLayerToGroup(*gp_fixargs((target_group_layer, add_layer_or_layerfile, add_position), True)))
ValueError: <MappingLayerObject object at 0x0000019CBBEBB270>

 

If I uncomment line 7 and get GroupLayer object "manually" the script will work ok.

So why it doesn't work when GroupLayer object is taken from parameter?

BTW - I'm aware that I could do some workaround like

 

new_gl=m.listLayers(gl.name)[0] #gl is object from script tool parameter

 

which would work as long as there are no duplicate names of Group Layers in TOC. Still I'd be greatful if someone can explain to me what going on behind the scenes.

0 Kudos
2 Replies
StaticK
MVP

Not sure why the addlayerToGroup doesnt know what to do with the Layer object since that is what it is expecting as input but the addlayerToGroup method doesn't know what to do with it. Maybe GetParameter overrides things and it isnt a true Layer Object.

Edit- just saw the statement about uncommenting. So disregard this:

Uncommenting the line 7 and pass in the gl's name property and it works like you said.

 

def script_tool(glayer):
...
gl = m.listLayers(glayer.name)[0]

 

The issue is there isn't a lot to get from describing the selected group layer:

 

I'm an object: <class 'arcpy._mp.Layer'> Group 1
areaOfInterest:	-157.834681122836 19.7086074727567 -67.8299529846581 64.8231249486575 NaN NaN NaN NaN
children:	[<geoprocessing describe data object object at 0x00000234B9B9D4B0>, <geoprocessing describe data object object at 0x00000234B9B9D830>]
dataElement:	None
dataType:	GroupLayer
nameString:	Group 1
DSID:	-1
FIDSet:	0;

 

Trying to get another group with the same doesn't seem to work. since 1:2 changes back to 1:1.

---

This will duplicate layers in the group if the layer is already part of the group.  I added some checks to stop from adding them if they are part of the group and added a line to remove the layers once moved into the group so they are not loose in the TOC. There was a longName method for arcmap, but that seems to have gone away so the only way I could tell if the layer is in a group or not was to count the layers children. If it had more than 0, it is a group and you can use list comp to get the names of the items in the group. Rasters had a child so that is why I excluded it by dataType on line 9.  You can probably improve the logic here.

 

 

def script_tool(glayer):
    """Script code goes below"""
    m = arcpy.mp.ArcGISProject('current').activeMap
    gl = m.listLayers(glayer.name)[0]  # if uncommented script will work well
    arcpy.AddMessage(f"I'm an object: {type(glayer)} {gl.longName}") #<class 'arcpy._mp.Layer'>
    lyrs_in_group = []
    for lyr in m.listLayers():
        desc = arcpy.Describe(lyr)
        if len(desc.children) > 0 and desc.dataType != 'RasterLayer':
            lyrs_in_group = [l.baseName for l in desc.children]
            arcpy.AddMessage(lyrs_in_group)

        elif all([lyr.name not in lyrs_in_group, not lyr.isGroupLayer, lyr.isFeatureLayer, desc.dataType != 'RasterLayer']):
            arcpy.AddMessage(f"Adding {lyr.name} to {gl.name}")
            m.addLayerToGroup(gl, lyr, "BOTTOM")
            m.removeLayer(lyr)
        else:
            arcpy.AddMessage(f"Nope {lyr.name}")

 

 

 

SzymAdamowski
Occasional Contributor

Thanks again for your time.

1) The code I used in example doesn't necessary make any valid things because I created it only to highlight the issue. My real challenge was to find empty layers (or more strictly speaking layers representing empty feature classes) and move them to exsiting Group Layer.  I designed a tool with Group Layer parameter and spent some time thinking why it doesn't move the empty layers to that Group Layer even though Group Layer paramter returns an object (in ArcGIS Pro 2.8 it didn't even crashed -it just silently did nothing. Fortunately ArcGIS Pro 3.1 explicitly crashes). And since I found a workaround I only hoped here for an explanation of this rather strange behaviour (just another bug or I am missing something). So once again to make it clear - my question can be shortened to "why Group Layer object returned from tool parameter isn't valid object"

2) I do agree with you that my code would duplicate Layers if they were already in Group Layer. My real script works  better but it's also much more complicated and would be more difficult to read.

3) I have trouble understading part of your post quoted below:


@StaticK wrote:

The issue is there isn't a lot to get from describing the selected group layer:

 

 

 

I'm an object: <class 'arcpy._mp.Layer'> Group 1
areaOfInterest:	-157.834681122836 19.7086074727567 -67.8299529846581 64.8231249486575 NaN NaN NaN NaN
children:	[<geoprocessing describe data object object at 0x00000234B9B9D4B0>, <geoprocessing describe data object object at 0x00000234B9B9D830>]
dataElement:	None
dataType:	GroupLayer
nameString:	Group 1
DSID:	-1
FIDSet:	0;

 

 

 

Trying to get another group with the same doesn't seem to work. since 1:2 changes back to 1:1.


4) Your code is a nice and elegant way to avoid duplicating layers but it has funny issue. If there is empty destination Group Layer  on top of TOC or any other empty Group Layer anywhere in TOC then arcpy.Describe(EmptyTopGroupLayer).children will crash. hasattr(desc, 'children') check has to be added.

Also IMHO FeatureLayer cannot be GroupLayer so I guess that condition "not lyr.isGroupLayer" is redundant in line 13.


0 Kudos