0
$\begingroup$

Not sure why this simple code does not work. I tried several things... but it only works if the values are statics . In this example I put one dinamic value (does not work) and another that works but is burned.

Code:

import bpy

#create prop_group
props = {
    "name" : [],
    "type" : [],
}

#add props 
props["name"].append( "fl_prop" )
props["type"].append( "float" )

print("---" )
class CustomPropGr(bpy.types.PropertyGroup):
    
    global props
    
    for name in props[ "name"] :
        for type in props[ "type" ] :
            
            if type == "float" :
                print("debug:: name : ", name, " type: " ,type )
                name : bpy.props.FloatProperty( name = name )
            # end if
            
        # end for
    # end for
    
    no_dinamic_prop : bpy.props.FloatProperty( name = "test" )
    
# end CustomPropGr
bpy.utils.register_class( CustomPropGr )


#make it enable and discovery for all objects
bpy.types.Object.custom_prop_gr = bpy.props.PointerProperty(type=CustomPropGr)


so = bpy.context.active_object

so.custom_prop_gr.no_dinamic_prop = 5.90
so.custom_prop_gr.fl_prop         = 90.5
print( "no_dinamic_prop    : ", so.custom_prop_gr.no_dinamic_prop )
#comment the below line to see the outputs
print( "dina prop (fl_prop): ", so.custom_prop_gr.fl_prop )
print("---" )
$\endgroup$

2 Answers 2

1
$\begingroup$

Use Python's type method for dynamic props

Recommend using python's type for dynamically creating classes.

Here is an example.

  • Set up two float properties "foo" and "bar" in our props dictionary. Both are given "float" as a type. Have converted to bpy prop by simply making it title case "Float" and tacking "Property" to the end, then grabbing that type via get attribute from bpy.props.

  • For the non dynamic members have set up some class to define these.

  • Then using type create a class, give it the name we wish to define, the inherited classes, lastly PropertyGroup.

  • Finally The annotations, ie our dynamic props are added in the last argument.

Test script.

import bpy
from bpy.props import (
        PointerProperty,
        FloatProperty,
        )
from bpy.types import PropertyGroup

props = {"foo" : "float",
         "bar" : "float",
         }

class NonDynamic:
    test : FloatProperty(name="Bar")
         
Group = type(
        "CustomPropGr",
        (NonDynamic, PropertyGroup,),
        {'__annotations__' :
            {
                
                k : getattr(bpy.props, f"{v.title()}Property")(name=k)
                for k, v in props.items()
            }
        }
    )
    
bpy.utils.register_class(Group)

bpy.types.Object.foobar = PointerProperty(type=Group)

Test run python console.

>>> C.object
bpy.data.objects['Cube']

>>> C.object.foobar
bpy.data.objects['Cube'].foobar

>>> str(C.object.foobar)
'<bpy_struct, CustomPropGr("") at 0x7f5b1a793f68>'

>>> C.object.foobar.foo
0.0

>>> C.object.foobar.bar
0.0

>>> C.object.foobar.test
0.0

Notes: can see from this can extend this quite simply to create a method that dynamically creates classes. I often use this to create AddonPreferences class from the addons underlying modules.

Have used a dictionary instead of the two separate lists for name and type, if using the two lists suggest using zip

for k, v in zip(props["name"], props["type"]):
    ...

Related:

Blender 2.8 - Field property declaration and dynamic class creation

$\endgroup$
5
  • $\begingroup$ I can't read some little thinks of the code... Why the for is down and not in top? what is "annotations" and... in what moment you put the name foobar ? how i can change it? zip is very usefull !!! and the dictionary is better aproach. Thanks friend! $\endgroup$
    – user70587
    Commented Jan 24, 2021 at 19:54
  • $\begingroup$ import bpy class Class (bpy.types.PropertyGroup) : non_dinamic : bpy.props.FloatProperty() props = { "dinamic1" : "Float", "dinamic2" : "Float" } setattr( Class, "other_non" , bpy.props.FloatProperty() ) #this for ask for annotation for k, v in props.items() : print("key:", k, "value", v ) setattr( Class, k , bpy.props.FloatProperty() ) bpy.utils.register_class ( Class ) bpy.types.Object.propgr = bpy.props.PointerProperty( type = Class ) so = bpy.context.active_object so.propgr.non_dinamic = 15.5 so.propgr.dinamic1 = 90.5 print("done") $\endgroup$
    – user70587
    Commented Jan 24, 2021 at 20:26
  • $\begingroup$ Another aproach using what I understand of your code. It work... but with the warning. $\endgroup$
    – user70587
    Commented Jan 24, 2021 at 20:27
  • $\begingroup$ #illegal target for annotations : "annotations" : setattr( Class, "other_non_dinamic" , bpy.props.FloatProperty() ) $\endgroup$
    – user70587
    Commented Jan 24, 2021 at 20:59
  • $\begingroup$ Class.__annotations__[k] = bpy.props.FloatProperty() That work with no warning. $\endgroup$
    – user70587
    Commented Jan 24, 2021 at 21:10
1
$\begingroup$
name : bpy.props.FloatProperty( name = name )

is assigning bpy.props.FloatProperty( name = name ) to the variable called name ( the name before the : )

Then you try to assign a value to so.custom_prop_gr.fl_prop which does not exist, because you used the variable name to create the custom property.

Then in your print command at the end:

print( "dina prop (fl_prop): ", so.custom_prop_gr.fl_prop )

is also trying to call so.custom_prop_gr.fl_prop which does not exist.

Change:

so.custom_prop_gr.fl_prop         = 90.5
print( "dina prop (fl_prop): ", so.custom_prop_gr.fl_prop )

to:

so.custom_prop_gr.name         = 90.5
print( "dina prop (fl_prop): ", so.custom_prop_gr.name )
$\endgroup$
1
  • $\begingroup$ Try to change: name : bpy.props.FloatProperty() for a dinamic name not work for me. f"{name}" : FloatProperty or something like that can't get it work. However help me a lot for discovery what it happen. Thanks. $\endgroup$
    – user70587
    Commented Jan 24, 2021 at 20:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .