Annotation Feature Class subtypes not supporting "VISIBLE", "NAME", other standard layer attributes in Pro

1286
6
04-25-2022 11:32 AM
MarkDrosnes
New Contributor II

I am working on a script tool to be run inside of an ArcGIS Pro project. Part of the script is meant to check/set the visibility of layers in a map by comparing to a pre-existing list of layer names which should be present and visible in the map. The code is meant to look something like this:

 

import arcpy
aprx = arcpy.mp.ArcGISProject("CURRENT")
map0 = aprx.listMaps()[0]
layers = map0.listLayers()
for lyr in layers:
    if lyr.name in listBase:
        lyr.visible = True

 

listBase is a Python list object containing strings representing the names of layers which should be present in the map. Pretty simple stuff: just check to see if a layer's name is in the list, and if so make the layer visible.

The issue that I am encountering is that the code fails on certain annotation subtype layers (annotation classes), resulting in the following error message when run in the Python window: 

 

Traceback (most recent call last):
  File "C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\arcobjects\_base.py", line 90, in _get
    return convertArcObjectToPythonObject(getattr(self._arc_object, attr_name))
AttributeError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 6, in <module>
  File "C:\Program Files\ArcGIS\Pro\Resources\ArcPy\arcpy\arcobjects\_base.py", line 96, in _get
    (attr_name, self.__class__.__name__))
NameError: The attribute 'name' is not supported on this instance of Layer.

 

The code is able to iterate through the first few annotation classes without issue, but tells me that the 'name' attribute is not supported on others. Using layer.supports(attribute) statements, I can see that these layers also do not support "VISIBLE", "MAXTHRESHOLD" or "MINTHRESHOLD". This is really strange for a number of reasons that I will do my best to articulate now:

1. All of the layers which raise the above error are subtypes within an annotation feature class (called Transportation_MainMap). Each subtype represents a different annotation class. All of these classes appear in the TOC with their proper names, and visibility can be toggled from the TOC as well. Min/max thresholds can be set from the layer properties dialogue. The code runs fine on some, fails on others. EDIT: upon some further examination of where the loop fails, I figured out that the code works only for the first 10 iterations of the for-loop. If an annotation feature class has less than 10 subclasses no errors are raised, and every annotation layer beyond the 10th raises an error. There appears to be more than just this one issue at play here, as some annotation sublayers raise an error even if they are in the first 10 iterations.

2. If I use the Python window in Pro to print the longName attribute (i.e. <for lyr in layers: print (lyr.longName)>) the layers which do not support 'name' print a blank string rather than failing. Additionally, some of the layers which DO support 'name' have a mismatch with the layer's longName. For example the layer with 'name' == "Landing Strip" has longName == "Transportation_MainMap\County Line Road".

3. If I use the Python window in ArcMap no error occurs and there is no mismatch between the 'name' and 'longName' attributes for any layers. Seems buggy to me.

If anyone knows what it going on here I'd really appreciate some help! I'm also happy to provide more info if I haven't covered everything relevant in this post.

 

0 Kudos
6 Replies
MarkDrosnes
New Contributor II

If anyone has been checking back on this post for updates, I have found a workaround for this particular issue, but I have not been able to figure out the cause of the bug described above. I probably would have done well also to mention that I am running Pro 2.8.3 and all of my Python packages are up-to-date.

In order for Python to be able to read the correct attributes from the annotation sublayers in question I had to check the CIM definition for the main annotation layer. 

https://pro.arcgis.com/en/pro-app/2.8/arcpy/mapping/python-cim-access.htm

Code to accomplish this for the above example might look like the following:

import arcpy
aprx = arcpy.mp.ArcGISProject("CURRENT")
map0 = aprx.listMaps()[0]
transMain = map0.listLayers()[0]
anno_CIM = transMain.getDefinition("V2")
annoLayers = anno_CIM.subLayers

This yields a Python list object (annoLayers) containing CIMAnnotationSublayer objects from which we can successfully read and write the desired layer attributes (i.e. 'name' and 'visibility'). Updates to items in annoLayers can then be pushed back out to the CIM Definition for the main annotation layer (transMain). 

To achieve the original objective of comparing layer names to a preexisting list we could use the following code to check and modify visibility of sublayers, and then write the modified layer properties out to JSON using setDefinition() :

for lyr in annoLayers:
    if lyr.name in listBase:
        lyr.visibility = True
    else:
        lyr.visibility = False

transMain.setDefinition(anno_CIM)

Unfortunately, these changes are not immediately visible upon successful completion of the code. In order for the changes to persist and be shown visually on the map you must then save, close, and reopen the project (or at least that is what I figured out. If you know another way please share!).

0 Kudos
JeffBarrette
Esri Regular Contributor

We provided a fix in the ArcGIS Pro 2.9.2 patch that addressed issues with > 10 anno subclasses.  Can you confirm that you are on 2.9.2?  If you are could you provide a screen shot of your problem anno subclass properties?

Capture.PNG

Thanks,

Jeff - Layout and arcpy.mp teams

0 Kudos
MarkDrosnes
New Contributor II

Hi Jeff,

As I mentioned in my comment above I am using 2.8.3, but I am glad to hear that this issue has been addressed in the current patch. I will be upgrading as soon as possible!

0 Kudos
MarkDrosnes
New Contributor II

Jeff,


I was able to upgrade to ArcGIS Pro 2.9.3 two weeks ago. While it did solve some of the problems described above, some problems persist. Two annotation subclass layers are still raising the same error as before when attempting to access their "NAME" attribute. I have attached screenshots of both of their properties as you requested.

Screenshot 2022-06-13 134258.jpgScreenshot 2022-06-13 134406.jpg


Additionally, all layers are able to print their longName (previously layers not supporting "NAME" were printing a blank string for longName), but the issue of mismatched name and longName on some annotation subclasses persists. It appears that the longName property is the more accurate of the two, as looping through map layers and printing both name and longName reveals that longName prints in the order expected based on the TOC / the order of sublayers in the CIM definition for the annotation feature class, but name prints in an unexpected order.


Specifically, when Python attempts to read the name of the fourth sublayer it is returning the name of the sixth sublayer. This offset then persists (name returned is that of sublayer two below what we would expect) for the remaining sublayers until it reaches the second-to-last and last sublayers, which are the two that raise errors. The first three sublayers behave normally. This only appears to be an issue for one annotation feature class.
By manipulating visibility in the TOC and using the Python window to print each layer's name and visibility (boolean), I can see that the visibility returned matches that of the layer name returned by the print statement, not that of the layer we would expect based on the order in the TOC.


Despite the issues detailed above, I was able to arrive at a suitable solution for my script by using try-except statements and pulling the layer name from longName as in the example below:

for lyr in layers:
                        try:
                            name = lyr.longName[lyr.longName.rindex("\\")+1:]
                            if name in listBase:
                                lyr.visible = True
                            else:
                                lyr.visible = False
                        except:
                            name = lyr.longName
                            if name in listBase:
                                lyr.visible = True
                            else:
                                lyr.visible = False

The except statement here accounts for the case where a layer in the map is not a sublayer nested in a group layer, and we would expect a layer's name and longName to be identical. There may be exceptions where this strategy would not account for all layers in the map, but for my purposes this affords me the functionality needed by the script.

0 Kudos
JeffBarrette
Esri Regular Contributor

@MarkDrosnes, I can NOT reproduce this issue.  Would it be possible to send me an email with a layer package to jbarrette@esri.com.

Jeff - Layout and arcpy.mp teams

0 Kudos
JasonHoward
New Contributor II

I'm on ArcGIS Pro 3.1.2 here... I'm getting a similar issue.  I just needed to loop through a folder tree to list all the lyr files and their data sources.

for root, dirs, files in os.walk(baseFilePath):
    for name in files:
        lyrFileName = os.path.join(root,name)
        lyrFile = arcpy.mp.LayerFile(lyrFileName)
        for lyr in lyrFile.listLayers():
            print(lyr.name + ", " + lyr.dataSource)

 

Works until it comes to an lyr file referencing an annotation feature class. Fails with this...

AttributeError.png

Replacing lyr.name with lyr.longName works but it still fails on dataSource.

0 Kudos