Getting Property groups as dictionaries

I recent­ly reworked Mirage’s live mode to be more effi­cient. One of the things I want­ed to improve was detect­ing changes in ter­rain set­tings. I fig­ured the best way to do it was get­ting a dic­tio­nary of the set­tings and find­ing what changed in it.

So I wrote a lit­tle func­tion to get all the prop­er­ties inside a PropertyGroup as a dic­tio­nary. I fig­ure this could be use­ful for every­one, so here it is.

# Don't forget:
from typing import Dict
from bpy.types import PropertyGroup

def group_as_dict(group: PropertyGroup) -> Dict:
    """Get values from a property group as a dict."""

    EXCLUDE = {'a_prop_I_dont_want', 'another'}
    prop_dict = {}

    for key in group.__annotations__.keys():

        # Avoid properties we don't want
        if key in EXCLUDE:
            continue

        # Each item in __annotations__ is a tuple 
        # containing the type and a dictionary
        prop_type = group.__annotations__[key][0]

        # Pointers to other property groups
        if prop_type == PointerProperty:
            prop_dict[key] = group_as_dict(getattr(settings, key))

        # Store collection properties as lists
        elif prop_type == CollectionProperty:
            prop_dict[key] = [group_as_dict(i) 
                              for i in getattr(settings, key)]

        # BUG? IntVectorProperties don't return the Vector value on
        # getattr(). Looks like we have to get it ourselves for now.
        elif prop_type == IntVectorProperty:
            prop_dict[key] = [i for i in getattr(settings, key)]

        # Get everything else as a value
        else:
            prop_dict[key] = getattr(settings, key)

    return prop_dict

This func­tion is recur­sive. It will take nest­ed PropertyGroups as well as CollectionProperties, which are returned as lists. I also added a fix for IntVectorProperties, where getattr() returns the point­er instead of the actu­al val­ues. You could also copy that line and extend it to the oth­er vec­tor prop­er­ties. Depending on what you would like to do with this dict, you might want a tuple or list of val­ues instead of a Vector object.

You can also exclude prop­er­ties by adding their names to the exclude set. This is great for UI prop­er­ties that you don’t want to store, like using enums for tabs.

Did you find it use­ful? Let me know in the comments!

All the posts you can read
TutorialsBlender, Python22.04.2020