2
$\begingroup$

I'm trying to combine Render-Presets with Camera-Presets. Why is this script causing an Error? What does it mean: "Python: Traceback (most recent call last): File "C:\Program Files\Blender Foundation\Blender 2.91\2.91\scripts\startup\bl_operators\presets.py", line 166, in execute exec(rna_path) File "", line 1, in AttributeError: 'NoneType' object has no attribute 'data'

location: :-1 " ?

This Error is coming also if a Camera is selected.

How can I make it work?

Here is the script:

import bpy
from bpy.types import Operator, Menu
from bl_operators.presets import AddPresetBase


class OBJECT_MT_display_presets(Menu):
    bl_label = "Object Display Presets"
    preset_subdir = "object/display"
    preset_operator = "script.execute_preset"
    draw = Menu.draw_preset


class AddPresetObjectDisplay(AddPresetBase, Operator):
    '''Add a Object Display Preset'''
    bl_idname = "camera.object_display_preset_add"
    bl_label = "Add Object Display Preset"
    preset_menu = "OBJECT_MT_display_presets"

    # variable used for all preset values
    preset_defines = [
        "render  = bpy.context.scene.render",
        "data = bpy.context.object.data"
    ]

    # properties to store in the preset
    preset_values = [
        "render.engine",
        "render.use_stamp",
        "data.cycles.fisheye_lens",
        "data.cycles.fisheye_fov",
        "data.shift_x",
        "data.shift_y"

    ]

    # where to store the preset
    preset_subdir = "Test_Folder"


# Display into an existing panel
def panel_func(self, context):
    layout = self.layout

    row = layout.row(align=True)
    row.menu(OBJECT_MT_display_presets.__name__, text=OBJECT_MT_display_presets.bl_label)
    row.operator(AddPresetObjectDisplay.bl_idname, text="", icon='ZOOM_IN')
    row.operator(AddPresetObjectDisplay.bl_idname, text="", icon='ZOOM_OUT').remove_active = True


classes = (
    OBJECT_MT_display_presets,
    AddPresetObjectDisplay,
)


def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.RENDER_PT_context.prepend(panel_func)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    bpy.types.RENDER_PT_context.remove(panel_func)


if __name__ == "__main__":
    register()
$\endgroup$
2
$\begingroup$

Use context.active_object

The issue, re that error message in question, is with the preset operator in question is it is recognizing only context.active_object rather than context.object, which it sees as None. Perhaps context.object is used for the pinid object if set, where there is a pin object. Test

context.scene.camera

Anyhow, for the context members being set we can instead look at the scene camera. Have added a poll method to the operator to have it only poll when the render engine is cycles and the scene has a camera.

Otherwise change poll such that, in addition to being cycles render engine

ob = context.object
return ob and ob.type == 'CAMERA' and ...

and in preset

"camera = bpy.context.active_object.data"

Made the preset_subdir same in menu and operator. Another mixin class could be used for this.

Wrapped the base class menu draw method into draw. This way can append prepend a menu item.

Only enabled preset row when it polls to avoid trying to save / set when not polling.

import bpy
from bpy.types import Operator, Menu
from bl_operators.presets import AddPresetBase


class OBJECT_MT_display_presets(Menu):
    bl_label = "Object Display Presets"
    preset_subdir = "Test_Folder"
    preset_operator = "script.execute_preset"
    #draw = Menu.draw_preset
    def draw(self, context):
        self.draw_preset(context)
        


class AddPresetObjectDisplay(AddPresetBase, Operator):
    '''Add a Object Display Preset'''
    bl_idname = "camera.object_display_preset_add"
    bl_label = "Add Object Display Preset"
    preset_menu = "OBJECT_MT_display_presets"

    # variable used for all preset values
    preset_defines = [
        "scene  = bpy.context.scene",
        "render = scene.render",
        "camera = scene.camera.data",
    ]

    # properties to store in the preset
    preset_values = [
        "render.engine",
        "render.use_stamp",
        "camera.cycles.fisheye_lens",
        "camera.cycles.fisheye_fov",
        "camera.shift_x",
        "camera.shift_y"

    ]

    # where to store the preset
    preset_subdir = "Test_Folder"
    @classmethod
    def poll(cls, context):
        scene = context.scene
        return (
                scene.camera
                and scene.render.engine == 'CYCLES'
                )

# Display into an existing panel
def panel_func(self, context):
    layout = self.layout
    
    
    row = layout.row(align=True)
    row.enabled =  bpy.ops.camera.object_display_preset_add.poll()
    
    row.menu(OBJECT_MT_display_presets.__name__, text=OBJECT_MT_display_presets.bl_label)
    
    row.operator(AddPresetObjectDisplay.bl_idname, text="", icon='ZOOM_IN')
    row.operator(AddPresetObjectDisplay.bl_idname, text="", icon='ZOOM_OUT').remove_active = True


classes = (
    OBJECT_MT_display_presets,
    AddPresetObjectDisplay,
)


def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.RENDER_PT_context.prepend(panel_func)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    bpy.types.RENDER_PT_context.remove(panel_func)


if __name__ == "__main__":
    register()

Can Python Operator Presets be shared between Operators?

$\endgroup$
1
  • $\begingroup$ Thank you so much batFINGER! Now it works everything fine. And finally I can release my first Addon. Hurray :D $\endgroup$ – Andi Jan 29 at 15:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.