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



7 Comments

  1. aditiavfx(3 years ago)

    You just save my day…thank you.

    1. Diego Gangl(3 years ago)

      Glad to hear!

  2. Rombout Versluijs(3 years ago)

    Do you have per­haps info where i should look for get­ting into PropertyGroups and PointerProperty. I want to add this to a cou­ple adds im doing. Im real­ly con­fused of the cor­rect approach to this

    1. Diego Gangl(3 years ago)

      The best place to start is the API docs:
      https://docs.blender.org/api/current/bpy.props.html#propertygroup-example
      Basically cre­ate a prop­er­ty­group with all your props in it. Then reg­is­ter the class, and make a PointerProperty in bpy.types.Scene or bpy.types.Object to hold it (for example).

      1. Rombout Versluijs(2 years ago)

        Came back again as i was search­ing for a sim­ply method of read­ing dict items. I find get­ting the data is more com­pli­cat­ed vs cus­tom lists.

        Ill try this code on a dict i have see if it works and i can deci­pher it better

  3. Lisa(3 years ago)

    Thanks for that, it was real­ly help­ful. I just had to change some­thing because a PointerProperty isn’t nec­es­sar­i­ly anoth­er prop­er­ty group.

    I changed the con­di­tion to
    if prop_type == bpy.props.PointerProperty:
    if isinstance(getattr(group, key), bpy.types.PropertyGroup):
    prop_dict[key] = group_as_dict(getattr(group, key))
    else:
    prop_dict[key] = getattr(group, key).name

    Of course it would be pos­si­ble to also some­how make any object into a dic­tio­nary but that real­ly depends on what you use it for. This is most like­ly some­thing you would put in the exclude.

  4. Rombout Versluijs(2 years ago)

    @lisa,

    Doesn’t your method go over all point­er groups or do tar­get a spe­cif­ic group when call­ing it?

    I saw this nice sin­gle line to make a new list for changed items

    Item = [item for item in dir(props) is not exclude: item
    I believe this should be able to get the keys but I guess we need anoth­er loop then check items

Leave a Reply

Your email address will not be published.