4
$\begingroup$

I am creating a custom property on an Empty in a script, and then editing the property's data such as the name, limits, and Tooltip description. I am using the commands echo'ed from the info panel when I perform these operations in the Blender UI. While the object is selected and active I get these commands...

bpy.ops.wm.properties_add(data_path="object")
bpy.ops.wm.properties_edit(data_path="object", property="Scale", value="1.0", default="1.0", min=0, max=10, use_soft_limits=False, is_overridable_library=False, soft_min=0, soft_max=10, description="")

When using these commands in the script or Python console, the first "add" command succeeds, but the edit command fails. I get this error message...

Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
  File "/private/var/folders/z4/pm8ygsf16f1_kw3dsfpttthm0000gn/T/AppTranslocation/66464DE9-7039-455C-8E08-0581D47CFD84/d/Blender.app/Contents/Resources/2.80/scripts/modules/bpy/ops.py", line 201, in __call__
    ret = op_call(self.idname_py(), None, kw)
RuntimeError: Error: Direct execution not supported

Is it possible to edit a custom property from a script, and what is the proper command, please. Thanks.

$\endgroup$
1
  • $\begingroup$ can you post the .blend file with the python script and your Empty to blend-exchange.giantcowfilms.com for us to have a look? $\endgroup$
    – rob
    Commented Jun 28, 2019 at 12:25

3 Answers 3

5
$\begingroup$

_RNA_UI dictionary

As descibed here https://blender.stackexchange.com/a/43786/15543

import bpy

context = bpy.context
obj = context.object

if not obj.get('_RNA_UI'):
    obj['_RNA_UI'] = {}

# set it
obj["scale_factor"] = 1.0

# property attributes.for UI 
obj['_RNA_UI']["scale_factor"] = {"description":"Scale Factor",
                  "default": 1.0,
                  "min":0.0,
                  "max":10.0,
                  "soft_min":0.0,
                  "soft_max":10.0,
                  "is_overridable_library":0,
                  }

# test UI in text editor footer

def draw(self, context):
    ob = context.object
    self.layout.prop(ob, '["scale_factor"]')

bpy.types.TEXT_HT_footer.append(draw)
$\endgroup$
6
  • $\begingroup$ Thanks, but its not working. The code only creates the custom property from the #set it line, but the code for editing the property attributes does nothing. Does it matter that I am running v2.80 ? $\endgroup$
    – zippy
    Commented Jun 28, 2019 at 18:59
  • $\begingroup$ Ok, after some tinkering I can make it work, but I have to run the script twice in succession. The first time the script runs it only creates the custom property, but does not edit the attributes - except that the min and max are -10000.0 and 10000.0. If I run the script immediately again, the attributes will change. Not a complete solution, but its some progress. $\endgroup$
    – zippy
    Commented Jun 28, 2019 at 22:28
  • $\begingroup$ Sorry, I'm simply running your script as is on the Cube in a fresh default Blender scene. I'm not a software engineer, so I don't know what "a tag redraw" is. I'll have to search it out in the docs to get acquainted. I get the concept of it, but I don't know how to properly implement it. $\endgroup$
    – zippy
    Commented Jun 30, 2019 at 2:58
  • $\begingroup$ Ok fixed it. My mistake logic error getting the dictionary ref. $\endgroup$
    – batFINGER
    Commented Jun 30, 2019 at 6:11
  • $\begingroup$ Thanks. I also got the other version working with just one extra line of code, besides the redraw for loop. I repeated your rna_ui = obj.get('_RNA_UI'). I'll edit my code post below to show. $\endgroup$
    – zippy
    Commented Jun 30, 2019 at 7:15
5
$\begingroup$

Since Blender 3.0 (relevant commit)

The UI for a custom property is described by a IDPropertyUIManager that can be retrieved by the id_properties_ui method.

import bpy

context = bpy.context
obj = context.object

# create the property, set it the initial value
if "scale_factor" not in obj:
    obj["scale_factor"] = 1.0

# get or create the UI object for the property
ui = obj.id_properties_ui("scale_factor")
ui.update(description = "Scale factor")
ui.update(default = 1.0)
ui.update(min=0.0, soft_min=0.0)
ui.update(max=10.0, soft_max=10.0)

# test UI in text editor footer

def draw(self, context):
    ob = context.object
    self.layout.prop(ob, '["scale_factor"]')

bpy.types.TEXT_HT_footer.append(draw)

Before Blender 3.0

The UI for a custom property is described by a dict object, stored in a special/hidden _RNA_UI property.

The internal blender addons tend not to access _RNA_UI directly, but use the rna_prop_ui.rna_idprop_ui_prop_get function to get or create the relevent "ui" object.

import bpy

context = bpy.context
obj = context.object

from rna_prop_ui import rna_idprop_ui_prop_get

# create the property, set it the initial value
obj["scale_factor"] = 1.0

# get or create the UI object for the property
ui = rna_idprop_ui_prop_get(obj, "scale_factor", create=True)
ui['description'] = "Scale factor"
ui['default'] = 1.0
ui['min'] = ui['soft_min'] = 0.0
ui['max'] = ui['soft_max'] = 10.0

# test UI in text editor footer

def draw(self, context):
    ob = context.object
    self.layout.prop(ob, '["scale_factor"]')

bpy.types.TEXT_HT_footer.append(draw)
```
$\endgroup$
0
$\begingroup$

So I added some tag_redraw code straight from Blender's API documentation, with changes to focus on the Properties window. It does the job of redrawing the UI, but that has no affect on the outcome of the above code. The code that makes it work is the repeated obj.get just above the creation of the property.

import bpy

context = bpy.context
obj = context.object

rna_ui = obj.get('_RNA_UI')
if rna_ui is None:
    rna_ui = obj['_RNA_UI'] = {}

rna_ui = obj.get('_RNA_UI')

# set it
obj["Scale_Factor"] = 1.0

# property attributes.for UI 
rna_ui["Scale_Factor"] = {"description":"Multiplier for Scale",
                  "default": 1.0,
                  "min":0.0,
                  "max":10.0,
                  "soft_min":0.0,
                  "soft_max":10.0,
                  "is_overridable_library":False
                  }
# redraw Properties panel
for window in bpy.context.window_manager.windows:
    screen = window.screen

    for area in screen.areas:
        if area.type == 'PROPERTIES':
            area.tag_redraw()
            break
$\endgroup$
1
  • $\begingroup$ The stack exchange reformatted my code block all screwy. I have no control over it. $\endgroup$
    – zippy
    Commented Jun 30, 2019 at 5:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .