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$
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
    Jan 24 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
    Jan 24 at 20:26
  • $\begingroup$ Another aproach using what I understand of your code. It work... but with the warning. $\endgroup$
    – user70587
    Jan 24 at 20:27
  • $\begingroup$ #illegal target for annotations : "annotations" : setattr( Class, "other_non_dinamic" , bpy.props.FloatProperty() ) $\endgroup$
    – user70587
    Jan 24 at 20:59
  • $\begingroup$ Class.__annotations__[k] = bpy.props.FloatProperty() That work with no warning. $\endgroup$
    – user70587
    Jan 24 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
    Jan 24 at 20:34

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.