How to pass value to layout.menu() instance?

layout.operator() returns the operator but layout.menu() returns ‘NoneType’

Is there an effective way to pass a value to the Menu instance created by layout.menu()?

Ran into this limitation myself recently, and the only way around it seems to be to create a lot of menus on-the-fly:

import bpy


class SimpleCustomMenu(bpy.types.Menu):
    bl_label = "Simple Custom Menu"
    bl_idname = "OBJECT_MT_simple_custom_menu"

    def draw(self, context):
        layout = self.layout
        for i in range(3):
            layout.menu("OBJECT_MT_dyn_%d" % i)
            

def register():
    bpy.utils.register_class(SimpleCustomMenu)


def unregister():
    bpy.utils.unregister_class(SimpleCustomMenu)

if __name__ == "__main__":
    register()


    for i in range(3):
        idname = "OBJECT_MT_dyn_%d" % i
        
        def func(self, context):
            self.layout.label("Parent: " + self.bl_label)
       
    
        opclass = type("OBJECT_MT_dyn_%d" % i,
                       (bpy.types.Menu, ),
                       {"bl_idname": idname, "bl_label": "Test %i" % i, "draw": func},
                       )
        bpy.utils.register_class(opclass)
        
    # The menu can also be called from scripts
    bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname)


Thanks a bunch! I was thinking I might have to solve it with dynamic class creation of some sort.

I am using strings that could become quite long and register_class has a bl_idname limit of 64 characters. I got around that by doing the MT prefix followed by a sha1 hash of the string. Works great!

It would be nice if they made layout.menu() behave similar to layout.operator() with regards of passing a value specific to that instance. If that were the case I could simply just pass the string instead of creating and registering a Menu class containing that string.

Hate to res this, but on demand dynamic class registration is failing to work for me in 2.70 RC1.

2.70 RC1 results in:
RuntimeError: register_class(…): can’t run in readonly state

This was working in 2.69 perfectly.

I guess the question now is what changed?

Ideasman told me that this error occurs if loading or drawing is in progress. But I also wonder why it worked in 2.69 so far, RestrictedContext change was in 2.67. If you register the menus in an operator’s execute() method, then it should work. Still, register_class() can be used in register(), that’s for sure, can’t see a reason why classes created via type() wouldn’t.

Well it works in 2.69, in a draw method no less.

I am still wondering if there is another way around this whole thing. This entire workaround seems ridiculous just to get a single string to an instance of layout.menu().