0
$\begingroup$

I'm trying to figure out how to generate a dynamic property group class, but I keep getting the annotations error: Warning: class PropBools contains a property which should be an annotation!. And following this error, I get the following printed line for each property: assign as a type annotation: PropBools.******.

Here is the code I have so far. I can show details about the list of data if it will help at all, but I don't think it will influence the error I'm getting.

PropBools = type(

        # typename
        'PropBools',

        # base class
        ( bpy.types.PropertyGroup , ),

        # dictionary of bool properties
        {
            ft.ID : bpy.props.BoolProperty(
                default         = False,
                name            = ft.Name,
                description     = ft.Desc,

                ) for ft in prop_list_data
        }
    )

Is it possible to do this without throwing the warning/error? Has anyone successfully generated a dynamic property group since the annotation requirement update?

Edit: I found Blender 2.8 - Field property declaration and dynamic class creation , which may be the only solution. Here is the same code, updated to define an annotations dictionary:

PropBools = type(

        # typename
        'PropBools',

        # base class
        ( bpy.types.PropertyGroup , ),

        # dictionary of bool properties
        {
            '__annotations__' :
            {
                ft.ID : ( BoolProperty,
                {
                    'default'       : False,
                    'name'          : ft.Name,
                    'description'   : ft.Desc

                } ) for ft in fuse.Type.Index
            }
        }
    )

You can even unpack dictionaries of extra parameters into it (this is a different dynamic class):

PropValues = type(

        # typename
        'PropValues',

        # base class
        ( bpy.types.PropertyGroup , ),

        # generate dictionary of override properties
        {
            '__annotations__' :
            {
                ft.ID : ( ft.Prop.Func,
                {
                    'default'       : ft.Default,
                    'name'          : ft.Name,
                    'description'   : ft.Desc,

                    # specify our property event function for updates
                    'update'        : ft.ValUpdate,

                    # unpack dictionary of keyword arguments to this property function
                    **ft.xop

                } ) for ft in fuse.Type.Index
            }
        }
    )

No warnings or errors using these yet, so seems promising.

Edit: This works great. The problems listed below were caused by an issue in the property list data, which was causing a silent error, which prevented ALL of the properties from registering, making the dynamic class appear empty. After finding and fixing the silent error, everything appears to be working.

However, the properties don't exist as they typically would in an instanced property group (of either dynamic class). Attempting to access a property using the syntax my_prop_group["id_name"] throws an error as if it doesn't exist. (A silent property error was causing this).

I'm not sure if I need to manually assign each one to default values (my_prop_group["id_name"] = DEFAULT).

Not sure if I need to include the entire dictionary of properties along with the __annotations__ dictionary of the same properties. Printing dir(*) of non-dynamic property groups seems to indicate that they should have both defined (silent error was causing properties to not register).

$\endgroup$
6
  • $\begingroup$ Using syntax my_prop_group.id_name gives me the error 'PropValues' object has no attribute 'id_name', even when I attempt to manually set its default value first (using my_prop_group.id_name = x). By comparing my dynamic class to non-dynamic classes (using dir()), it looks like there is still information missing. Non-dynamic classes have the properties listed in their primary members, where my dynamic class only has them listed inside of the annotations member. So it seems like something is still missing. I really appreciate the help, though. Please let me know if you have any ideas. $\endgroup$
    – Robert
    Oct 28 '19 at 11:39
  • $\begingroup$ I may have made a mistake when I said non-dynamic classes look like they have more information. After setting up a simpler test, they actually look identical. In addition, I can access the prop of the simpler dynamic class. So there may be some other issue with my more complex version. I will try to figure this out when I get back from work. Thanks again. $\endgroup$
    – Robert
    Oct 28 '19 at 12:16
  • $\begingroup$ It was actually being caused by a silent property error. I edited question to reflect. It appears to be working now. Is there any way to access or see these silent errors? There is nothing at all listed in the console. $\endgroup$
    – Robert
    Oct 28 '19 at 12:40
  • 2
    $\begingroup$ What I am using for dynamic annotations is, define the class, eg class Foo: give it an empty dictionary as the __annotations__ member. Then populate with Foo.__annotations__[propname] = bpy.props.SomeProperty(**kwargs) $\endgroup$
    – batFINGER
    Oct 28 '19 at 13:39
  • $\begingroup$ I didn't know that was possible. That would certainly make things simpler in many situations. Just out of curiosity, I wonder if this would work for classes that have at least one normal property defined? Assuming you would not have to manually define the annotations member, but it seems like everything else would work. $\endgroup$
    – Robert
    Oct 28 '19 at 21:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.