4

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.

batFINGER
  • 84,216
  • 10
  • 108
  • 233
zippy
  • 167
  • 2
  • 8
  • can you post the .blend file with the python script and your Empty to https://blend-exchange.giantcowfilms.com/ for us to have a look? – rob Jun 28 '19 at 12:25

3 Answers3

5

_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)
batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • 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 ? – zippy Jun 28 '19 at 18:59
  • 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. – zippy Jun 28 '19 at 22:28
  • 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. – zippy Jun 30 '19 at 02:58
  • Ok fixed it. My mistake logic error getting the dictionary ref. – batFINGER Jun 30 '19 at 06:11
  • 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. – zippy Jun 30 '19 at 07:15
  • Ok. Very nice. I'm using your corrected code without the redraw method, since the redraw will happen by the time I open the custom properties panel. Thanks very much for your attention and effort. I only wish I understood what is happening. The API documentation is too sparse to explain it in layman terms. I understand everything except the lines operating on the '_RNA_UI' and their syntax. – zippy Jun 30 '19 at 07:41
4

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) ```

Duarte Farrajota Ramos
  • 59,425
  • 39
  • 130
  • 187
rotoglup
  • 353
  • 2
  • 10
0

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
brockmann
  • 12,613
  • 4
  • 50
  • 93
zippy
  • 167
  • 2
  • 8