Understanding How to Use Blender Python Properties

To code in Blender, it is essential to understand Blender Python Properties. However, when I started working with Blender, I found properties to be confusing. From the way that properties were declared to the types of properties (specifically enum) to the UI display of properties. Therefore, I put together this deep dive guide to properties. Please let me know in the comments if there is anything that I left out.

What are Properties?

Almost every setting in Blender is a property. In fact, the default section on the bottom right of the window is labeled “Properties”.

Blender Property Panel in lower right corner of Blender window.
Blender Property Window

Access to any of the properties in Blender is easy. You can simply right click on the property and click either copy full data path (which copies the data path for the currently selected object), or click copy data path (which just copies the name of the property).

To access the full data path of a property, right click on the property
Accessing the Full Data Path

However, there are circumstances where we may want to add our own property. For example, we may want to add a speed property that controls how fast an object moves in an animation or we may want to add a tag to objects that allows us to categorize and filter objects in a complex scene. We can do this through the Blender Python API, specifically Blender Python Properties, which, according to the API reference, “extend Blender’s internal data.”

RNA vs DNA

Before we dive into how to use Blender Python Properties, as I researched for this post, I came across RNA and DNA multiple times. I felt like it was worth quickly mentioning, 

RNA vs DNA.

DNA is Blender’s internal data structure. RNA is a wrapper that provides API access to the internal data structure. The source code for RNA is interesting, because it is autogenerated. If a property is added in the correct source files, the process to make Blender generates the necessary code to make the property effective. This is beyond the scope of this post but still fascinating.

The Basics: How to use Blender Python Properties

Now back to properties. In basic cases, Blender Python properties are easy to use. You can create them as part of an operator or as part of another datablock (like and object or a scene). 

Creating a Property in an Operator

Below is the code from the Blender API reference.

class OBJECT_OT_property_example(bpy.types.Operator):
    bl_idname = "object.property_example"
    bl_label = "Property Example"
    bl_options = {'REGISTER', 'UNDO'}

    my_float: bpy.props.FloatProperty(name="Some Floating Point")
    my_bool: bpy.props.BoolProperty(name="Toggle Option")
    my_string: bpy.props.StringProperty(name="String Value")

    def execute(self, context):
        self.report(
            {'INFO'}, 'F: %.2f  B: %s  S: %r' %
            (self.my_float, self.my_bool, self.my_string)
        )
        print('My float:', self.my_float)
        print('My bool:', self.my_bool)
        print('My string:', self.my_string)
        return {'FINISHED'}

In this example, we define the properties:

my_float: bpy.props.FloatProperty(name=”Some Floating Point”)

We can then access it using self.my_float to either set the value or get the value.

I found the structure to define the property to be interesting. As I noted in previous post the structure is actually a type annotation based on PEP 526.

Add Property to an Object

The example above adds the properties to an operator. You can also add them to an existing datablock in Blender. For example, to add a custom float to objects, you can add:

bpy.types.Object.myProp = bpy.props.FloatProperty(default=7)

This adds a float property to every object with a default value of 7.

One thing that I think is strange about adding a property is you do not see it in the UI. It would be nice if it was automatically added to the UI (or at least in the assignment you had the ability to enable it in the UI). You can add with the following code:

import bpy

class UIListPanelExample1(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "My Properties Panel"
    bl_idname = "OBJECT_PT_ui_list_example_1"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        self.layout.prop(bpy.context.object,"my_float")

def register():
    bpy.types.Object.my_float = bpy.props.FloatProperty(default=0)
    bpy.utils.register_class(UIListPanelExample1)

if __name__ == '__main__':
    register()

Types of Properties

Now that we know how to create properties, let’s discuss the types of properties. There are 10 types of properties. We will not cover all of them in detail here because several are self explanatory.

Bool, Float, Int, String

The first properties that we will discuss are the float, int, and string. These are the same as the Python variable types float, int, and string. Defining is relatively straightforward:

bpy.types.Object.boolTest = bpy.props.BoolProperty()
bpy.types.Object.floatTest = bpy.props.FloatProperty(default=7.2)
bpy.types.Object. intTest = bpy.props.IntProperty(default=7)
bpy.types.Object.stringTest = bpy.props.StringProperty(default="this is only a test")

There are many options for these properties. For example, for both int and float properties, you can set the min and max for the properties. You can also define whether the property can be animatable. In addition, each of these properties has an update parameter that can be set to a callback function that is called whenever the property is changed.

def changeFunc(self, context):
    print("The value changed")

bpy.types.Object.testValue = bpy.props.FloatProperty(default=0, update=changeFunc)
Example of running the prior code to call a function when the value changes in the Python Console

Vectors 

There are also vector properties that correspond to bool, float, and int. You can set the size of the vector from 1 to 32.

bpy.types.Object.vectorTest = bpy.props.FloatVectorProperty(size=3, default=(0,0,0))

Enum Property

The Enum Property is useful for making a static list of items. For example, if you are making a UI panel, and you want to offer a dropdown where the user can pick an option. To create a Enum property:

bpy.types.Object.enumTest = bpy.props.EnumProperty(items=[('option1','test1','the first option'),('option2','test2','the second option')])clear

The enum property that is created returns the string of the currently selected item.

If you want a dynamic list of items, you can set the items parameter to a callback function that returns a list of tuples.

def GetItems(self, context):
    if "Cube" in bpy.context.object.name:
        itemList = [('option1','cube','equal sides'),('option2','rectangle','non equal sides')]
    else:
        itemList = [('option3','triangle','not a cube'),('option4','hexagon','6 sides')]

    return itemList

bpy.types.Object.testEnum = bpy.props.EnumProperty(items=GetItems)

Note that there are some potential challenges to using a callback described in the Blender Python Gotchas.

Property Group

The last two items we will talk about, Property Groups and Collections, are different from the other properties. The Property Group allows you to create a custom property that is composed of the underlying types. For example, you can create a group that includes a string name and a float value. To do this, we will create a subclass of PropertyGroup and then assign it to objects (bpy.types.Object).

class TestPropGroup(bpy.types.PropertyGroup):
    name: bpy.props.StringProperty(name="name", default="")
    value: bpy.props.IntProperty(name="value", default=0)

bpy.utils.register_class(TestPropGroup)
bpy.types.Object.test_prop = bpy.props.PointerProperty(type=TestPropGroup)

To set the properties in the property group:

bpy.context.object.test_prop.name = "Marvin"
bpy.context.object.test_prop.value = 42

And to access the properties:

print(bpy.context.object.test_prop.name)
print(bpy.context.object.test_prop.value)

The property group is useful to keep properties organized. You can place all of your properties together. The property group is even more powerful when paired with a collection. With a collection, we can create a list of property group items.

Collection Property

The collection is an array or list of properties. To create a collection:

class MyFloatProp(bpy.types.PropertyGroup):
    name: bpy.props.StringProperty(default="")
    value: bpy.props.FloatProperty(default=0)
    
bpy.utils.register_class(MyFloatProp)
bpy.types.Object.my_settings = bpy.props.CollectionProperty(type=MyFloatProp)

You can add and remove elements from the collection:

bpy.context.object.my_settings.add()

This returns a reference to the item we just added. We can access through bpy.context.object.my_settings[0] or we could instead write:

newItem = bpy.context.object.my_settings.add()

We can now set the new item with:

newItem.name = "first"
newItem.value = 42

Inherited Properties and Functions

In the Blender Python API reference, the properties include sections on inherited properties and inherited functions. However, I struggled to get these to work. In particular, I wanted to access the list of items in EnumProperty. However, if I tried to use items inherited function, it did not work. It gave the following error:

Error from calling the inherited functions from the property directly.

I realized that the property is actually stored elsewhere. To access a property attached to an object, you need to use the following.

bpy.context.object.bl_rna.properties["PropertyName"]

This will allow you to access the underlying inherited properties. For example, if we have the following enum property:

bpy.types.Object.testEnum = bpy.props.EnumProperty(items=[('option1','first',''),('option2','second','')])

We can access the items with:

for item in bpy.context.object.bl_rna.properties["testEnum"].enum_items:
    print(item.name)

Although this works for the inherited properties, it does not appear to work for the inherited functions. When I try to access the inherited functions, I get the following error:

I am still trying to identify the solution to this. If you know, please post in the comments.

Conclusion

This post provides an overview to Blender Python properties. With this foundation, we can add properties to operators or to datablocks to customize the operation of Blender.