How to register a group of properties? (for upping to 2.8)

why

For various reasons, I don’t like assigning properties to contextual items like object/scene/window/etc.
I store my properties in the Addon Preferences, locally in the script, or in those context items when it’s truly relevant.

I have a system already setup and working so that I can easily add properties to be found for the ui/scripts used elsewhere.
My addon is a omni-functional, meaning the items are spread around everywhere in Blender and are generally completely unrelated to one another. As such, the properties really need to be sectioned off from one another to avoid mixing/overwriting each other.

I want to register my addons’ properties into the Addon Preferences, and I want to split them into sub levels.
For example:

class Addon_Preferences(bpy.types.AddonPreferences):
    bl_idname = __package__

    enabled = BoolProperty()
    class main:
        sub1 = BoolProperty()
        sub2 = StringProperty()
        class sub_main:
            name = StringProperty()

    class registered_main(bpy.types.PropertyGroup):
        sub1 = IntProperty()
        sub2 = FloatProperty()
        class sub_main(bpy.types.PropertyGroup):
            sub_sub = EnumProperty()
        sub_main = PoinerProperty(type=sub_main)
    registered_main = PointerProperty(type=registered_main)

In this example, [main] would be the preferred setup but since the properties don’t get registered to be actually used, I was using [registered_main]

The problem is without using bpy.utils.register_module(__name__), the addon’s propgroup doesn’t register the sub-properties, or the propgroup itself,making only the first ungrouped levels registered.

Which would mean the only way to get all the properties registered, is to set them all on the same level, and rename them all to have globally unique names, which is highly undesired.

I would also like to “append” props to the AddonPreferences but getting them registered in the first place is far more important.

I guess the problem is that you’re overwriting the class definition with a class instance so you loose reference to that class that must be registered to be instanced as a PointerProperty.
try to create a global list of all classes in your file lets call it register_classes = [] then each class you define, you append to this list before overwriting with , then you iterate over the list and register each class idepentently,

register_classes = []

class registered_main(bpy.types.PropertyGroup):

    class sub_main(bpy.types.PropertyGroup):
        sub_sub = EnumProperty()
     #keep track of the class
    register_classes.append(sub_main)
    
    sub_main = PoinerProperty(type=sub_main)
#keep track again
register_classes.append(registered_main )
registered_main = PointerProperty(type=registered_main)

#register all classes
for cls in register_classes:
    bpy.utils.register_class(cls)
1 Like

Like @anon18120698 said you need to use a PointerProperty. You need to register each class separately (extending PropertyGroup) then you can add a pointer to the subclass in the main class.


class subclass(bpy.types.PropertyGroup):
    sub_data = FloatProperty()

class Addon_Preferences(bpy.types.AddonPreferences):
    bl_idname = __package__

    sub_stuff = PointerProperty(type=subclass)

# Then you can do
addon_prefs.sub_stuff.sub_data

I recommend you also follow his advice on registering a list of classes since register_module is gone on 2.8.

@Januz I don’t know what you’re telling me; you generalize the code too much with shorthand, and seemingly requiring to backreference backreferences.

edit

I’m under the impression that my issue with it is you’re trying to tell me to use a different code layout; one that tries to use as few sub-sections as possible.

I very much hate this style of code.
This one addon I love has a lot of operators, and the Execute function of every one of them, calls a def function placed outside of the class, often right next to it, which then often calls several other def functions scattered around in the file and other files.

Too much referencing, making it very hard to manage things.

I like to organize like a folder, where everything is tabbed under it’s related parent.
Only placing things separate and referencing them when the bulk of the function is to be re-used for multiple unrelated tasks.

@anon18120698
Thanks, that works.
I’m going to look into the auto_load.py script from Jacques Lucke, again and see if I can re-arrange my code to make it work with that. I was already aware of the storing a class list method, I’d just rather not, and have it automated.

note: the issue was I needed to register the Property Groups before the Addon_Prefs, whereas I only tried registering the Addon_Prefs, or registering the groups but from the wrong locations

@Edtion Actually I had never seen nested classes in an addon before, so I assumed that’s why Blender was failing to register them. My advice was to put them as module-level classes, above or below their parents.
Good to know it works though.

Oh, by the way, you could implement a decorator for registering the classes.

register_classes = []
def register(cls):
    register_classes.append(cls)
    return cls

@register
class registered_main(bpy.types.PropertyGroup):
    
    @register
    class sub_main(bpy.types.PropertyGroup):
        sub_sub = EnumProperty()
    
    sub_main = PoinerProperty(type=sub_main)

registered_main = PointerProperty(type=registered_main)

for cls in register_classes:
    bpy.utils.register_class(cls)
1 Like