What causes EnumProperty to do this? UI BUG?

Why can I not expand a dynamic EnumProperty in UI. How do I solve this issue?

def my_items(scene, context):

    my_folders = []
    items = []

    for folders in bpy.context.scene.objects:
        if folders.type == 'MESH':
            my_folders.append(folders.name)
    print(my_folders)
                
    for i, name in enumerate(my_folders):
#>>>>>>>        
        #Uppercase for enum identifier
        name_upper = name.upper()
        
        #Remove underscore and capitalize for enum name
        remove_underscore = name_upper.replace("_", " ")
        cap_words = string.capwords(remove_underscore)
#>>>>>>>
        #Insert items                                                          
        items.insert(i, (name_upper, cap_words, ""))
        
    print(items)
    return items

Prints in console. This is what I want.

[('SUZANNE_MONKEY', 'Suzanne Monkey', ''), ('CUBE', 'Cube', ''), ('CYLINDER', 'Cylinder', '')]

You can see the UI goes nuts when trying to correct the “identifier” and “name” for EnumProperty and drawing like this layout.prop(mytool, "transform", expand=True).

If doing layout.prop(mytool, "transform", text='') it’s correct and causes no issues.

Can you post the whole code for the panel and how you’re using my_items with it please? It doesn’t look like you’re using my_items as the get= method for the EnumProperty so it might be something in the way you’re using my_items to update the property.

Gets weirder, LOL. The tooltip is correct. Seems it’s maybe a bug with the text when you use expand=True .

Here’s code.

import bpy, string


from bpy.props import (EnumProperty,
                       PointerProperty,
                       )
from bpy.types import (Panel,
                       Operator,
                       PropertyGroup,
                       )

def my_items(scene, context):

    my_folders = []
    items = []

    for folders in bpy.context.scene.objects:
        if folders.type == 'MESH':
            my_folders.append(folders.name)
    print(my_folders)
                
    for i, name in enumerate(my_folders):
#>>>>>>>        
        #Uppercase for enum identifier
        name_upper = name.upper()
        
        #Remove underscore and capitalize for enum name
        remove_underscore = name_upper.replace("_", " ")
        cap_words = string.capwords(remove_underscore)
#>>>>>>>
        #Insert items                                                          
        items.insert(i, (name_upper, cap_words, ''))
        
    print(items)
    return items

class MySettings(PropertyGroup):

    transform: EnumProperty(
        name="Apply Data to:",
        description="Apply Data to attribute.",
        items=my_items
        )

class OBJECT_PT_my_panel(Panel):
    bl_idname = "OBJECT_PT_my_panel"
    bl_label = "My Panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Tools"
    bl_context = "objectmode"

    @classmethod
    def poll(self,context):
        return context.object is not None

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool
        
        grid = layout.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True)
        grid.prop(mytool, "transform", expand=True)


classes = (
    MySettings,
    OBJECT_PT_my_panel,
                   
)

def register():

    from bpy.utils import register_class
    for cls in classes:
        register_class(cls) 

    bpy.types.Scene.my_tool = PointerProperty(type=MySettings)
            
def unregister():

    from bpy.utils import unregister_class
    for cls in classes:
        unregister_class(cls)

    del bpy.types.Scene.my_tool
            
if __name__ == "__main__":
    register()

Could part of it be this warning referenced in the docs for EnumProperty?

Warning

There is a known bug with using a callback, Python must keep a reference to the strings returned by the callback or Blender will misbehave or even crash.

But it still acts up, even when you put items outside of the callback.

Check out what happens if you try to specify the number as the 4th item in the tuple too. Something seems real broken.

I forgot to add import string to code. Did you figure that out?

Try changing these 2 lines and see results for each one.

Issue

items.insert(i, (name_upper, cap_words, ''))
grid.prop(mytool, "transform", expand=True)

No Issue ,but it’s not expanded

items.insert(i, (name_upper, cap_words, ''))
grid.prop(mytool, "transform", expand=False)

No Issue, but doesn’t have the changes to identifier and name

items.insert(i, (name, name, ''))
grid.prop(mytool, "transform", expand=True)

Yeah, the import fix was easy.

Check out this one, doesn’t work at all so I still think it’s all related to that warning in the docs:

items.insert(i, (name.upper(), string.capwords(name.upper().replace("_", " "), '')))

regardless of expand setting.

Hey, sorry to revive a dead topic, but this problem is driving me crazy right now…
I have an enum where the labels go weird:

which is from this code:

_at_tree_previews = []
def get_items(self, context):
    _at_tree_preiviews.clear()
    for index, path in enumerate(img_paths):
        name = path.name
        icon = pcoll.load_safe(name, str(path), "IMAGE")
        _at_tree_previews.append((name, str(index), name, icon.icon_id, index))
    return _at_tree_previews

where _at_tree_previews is the return value of the EnumProperty items callback, and the labels should just be the index of each preview.

I have tried just about everything under the sun to get this to work, including trying to follow the frustratingly vague warning in the docs to the letter, and copying this code provided by one of the developers themselves.

And even after all that, blender still refuses to display the labels correctly.

The only slight solution that I’ve found is that if you remove the line:

_at_tree_previews.clear()

the labels display perfectly! It just comes with the small downside that icons continue to be loaded every time the enum callback activates until blender crashes…

Does anyone have a proper solution to this???

Ok, just in case anyone else has the same problem, I eventually found a solution thanks to @core-process :