0

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("---" )

Psyonic
  • 2,319
  • 8
  • 13
user70587
  • 23
  • 1
  • 4

2 Answers2

1
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 )
Psyonic
  • 2,319
  • 8
  • 13
  • 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. – user70587 Jan 24 '21 at 20:34
1

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

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • 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! – user70587 Jan 24 '21 at 19:54
  • 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")

    – user70587 Jan 24 '21 at 20:26
  • Another aproach using what I understand of your code. It work... but with the warning. – user70587 Jan 24 '21 at 20:27
  • #illegal target for annotations : "annotations" : setattr( Class, "other_non_dinamic" , bpy.props.FloatProperty() ) – user70587 Jan 24 '21 at 20:59
  • Class.annotations[k] = bpy.props.FloatProperty() That work with no warning. – user70587 Jan 24 '21 at 21:10