Can't access actually used values of macro operator properties from Python
Closed, ResolvedPublic

Description

System Information
Windows 7, 64bit

Blender Version
Broken: 2.71 RC2

Short description of error
Logged operators in WindowManager.operators also include Macros, but if their arguments are retrieved, they are all at their default values.

Exact steps for others to reproduce the error

  • Go to Scripting view
  • Shift + D to duplicate linked
  • Paste and Run script:
import bpy
from collections import Iterable
from mathutils import Vector, Matrix
from _bpy import StructMetaPropGroup

def main():
    for op in bpy.context.window_manager.operators:
        cmd = format_logged_op(op)
        print(cmd)

def format_logged_op(op):
    tmp = []
    for k in op.properties.keys():
        p = getattr(op.properties, k)
        if isinstance(type(p), StructMetaPropGroup):
            props = format_macro_props(p, p.bl_rna.properties.keys())
            tmp.append("%s={%s}" % (p.bl_rna.identifier, props))
        else:
            tmp.append(format_key_value(k, p))

    return "bpy.ops.%s(%s)" % (format_idname(op), ", ".join(tmp))

def format_macro_props(prop, keys):
    tmp = []
    for k in keys:
        if k == "rna_type":
            continue
        p = getattr(prop, k)
        tmp.append(format_key_value(k, p, fmt='"%s": %r'))
    return ", ".join(tmp)
    
def format_key_value(k, p, fmt="%s=%r"):
    if isinstance(p, Vector):
        p = p.to_tuple()
    elif isinstance(p, Matrix):
        p = "(%s)" % ", ".join(repr(vec.to_tuple()) for vec in p)
    elif not isinstance(p, str) and isinstance(p, Iterable):
        p = p[:]
    return fmt % (k, p)


def format_idname(op):
    return ".".join(op.bl_idname.split("_OT_", maxsplit=1)).lower()
    
main()

It will print

bpy.ops.mesh.duplicate_move(MESH_OT_duplicate={"mode":1}, TRANSFORM_OT_translate
={"value":(0.0, 0.0, 0.0), "constraint_axis":(False, False, False), "constraint_
orientation":'GLOBAL', "mirror":False, "proportional":'DISABLED', "proportional_
edit_falloff":'SMOOTH', "proportional_size":1.0, "snap":False, "snap_target":'CL
OSEST', "snap_point":(0.0, 0.0, 0.0), "snap_align":False, "snap_normal":(0.0, 0.
0, 0.0), "texture_space":False, "remove_on_cancel":False, "release_confirm":Fals
e})

so everything False, 0.0 or whatever is default...

codemanx created this task.Jun 23 2014, 2:22 AM
codemanx updated the task description. (Show Details)
codemanx raised the priority of this task from to Needs Triage.
codemanx added projects: BF Blender, Python.
codemanx set Type to Bug.
codemanx added a subscriber: codemanx.

I may be wrong, but IIRC macro operators in fact don't have properties of their own (or at least they don't inherit properties from nested operators by default). Including nested operator properties in the macro's dict would be dangerous. How would you handle name conflicts etc.?

If anything, the nested operators' properties should be accessible as a collection inside the macro (something like window_manager.operators[-1].macro[0].properties). This is actually how properties are stored for macros and how the redo panel accesses and displays them. I don't know why these are not exposed already in the RNA, maybe @Campbell Barton (campbellbarton) can say?

About dynamic enums: Yes, this is annoying ... In principle dynamic enums can depend on context even, but in most cases they're just used to select a fixed list based on some other property. There are classmethods in UILayout which could be used for resolving enum names, descriptions and icons, but not for mapping index <-> identifier. Something like this would be very handy (if it doesn't exist somewhere else already?).

Use attributes instead of dictionary keys.

bpy.context.window_manager.operators[-1].properties['constraint_orientation']
->
bpy.context.window_manager.operators[-1].properties.constraint_orientation

The dict keys() can be used to getattr()

Lukas Toenne (lukastoenne) claimed this task.

Ah yes, @Morshidul Chowdhury (iPLEOMAX) is right. The nested operator properties can be accessed as attributes. To get all their properties you could use the RNA type info:

props = bpy.context.window_manager.operators[-1].properties.OBJECT_OT_duplicate.bl_rna.properties.keys()

Closing this report.

codemanx renamed this task from WindowManager.operators does not resolve macro properties to Can't access actually used values of macro operator properties from Python.Jun 24 2014, 9:31 PM
codemanx updated the task description. (Show Details)
codemanx reopened this task as Open.
Bastien Montagne (mont29) triaged this task as Normal priority.Jul 2 2014, 2:12 PM

Yeah… I had to fight that issue in C as well, to allow the log/info window to show valid parameters in this case too, some time ago… Sounds more like a TODO to me, tbh.

IDK what the problem here is actually ...

Campbell Barton (campbellbarton) raised the priority of this task from Normal to Confirmed.Sep 3 2014, 2:21 PM

Confirmed. but changing Py/RNA API right before release is too risky (unless its obvious fix for mistake)

Expose via operator.macros, a list of macros whos properties you can access.

This is a bit awkward but its how the data is stored internally.

Better silly than sorry ;-)