1
$\begingroup$

I'm trying to write my operator that will simulate the local view (Because I need to create new meshes, and some other functionalities that are not supported in blender's local view). Script acts as expected, but when I try to run some other custom operator that I wrote (for example, one that adds some custom properties on an object), blender crashes from time to time without warning. Crash doesn't happen every time, but at random, maybe one in ten times. I tried running blender from windows console, and I get an error: EXCEPTION_ACCESS_VIOLATION. I'm pretty much lost here.

Here is script for local view:

bpy.types.Scene.hidden_objects = []
bpy.types.Scene.is_isolation_mode = bpy.props.BoolProperty(default=False)
bpy.types.Scene.is_isolation_mode = False

class IsolationMode(bpy.types.Operator):
bl_idname = "my_operator.isolation_mode"
bl_label = "Enter/Exit Isolation"

def execute(self, context):
    if bpy.types.Scene.is_isolation_mode:
        for hidden_obj in bpy.types.Scene.hidden_objects:
            hidden_obj.hide = False
        bpy.ops.view3d.view_all()
        bpy.types.Scene.hidden_objects = []
    else:
        for obj in bpy.context.scene.objects:
            if obj.select == False and obj.hide == False:
                bpy.types.Scene.hidden_objects.append(obj)
                obj.hide = True
        bpy.ops.view3d.view_selected()
    bpy.types.Scene.is_isolation_mode = not bpy.types.Scene.is_isolation_mode
    return {"FINISHED"}

def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)

And custom script that crashes Blender (this is just one example, there are several scripts, and they all tend to crash Blender:

bpy.types.Object.material_type = bpy.props.EnumProperty(items=
                                                    (('0', 'Normal', 'Normal layer'),
                                                     ('1', 'Additive', 'Additive Layer'),
                                                     ('2', 'Subtractive', 'Subtractive')),
                                                    name="")
class SetLayerType(bpy.types.Operator):

bl_idname = "my_operator.set_object_type"
bl_label = "Set Layer Type"
bl_options = {'REGISTER', 'UNDO'}

layer_type = bpy.props.EnumProperty(items=(('0', 'Normal', 'Normal layer'),
                                         ('1', 'Additive', 'Additive Layer'),
                                         ('2', 'Substractive', 'Substractive layer')),
                                  name="Mode")

def __init__(self):
    self.update_properties()

def draw(self, context):
    layout = self.layout
    layout.label(text="Layer Type")
    layout.prop(self, 'layer_type')

def invoke(self, context, event):
    if len(bpy.context.selected_objects) == 0:
        self.report({'ERROR'}, "At least one object must be selected.")
        return {'CANCELLED'}
    return {"FINISHED"}

def execute(self, context):
    for obj in bpy.context.selected_objects:
        obj.material_type = self.layer_type
    return {"FINISHED"}

def update_properties(self):
    if len(bpy.context.selected_objects):
        obj = bpy.context.selected_objects[0]
        self.layer_type = obj.material_type


def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)
$\endgroup$
  • $\begingroup$ Just as a note, you should only be accessing bpy.types.Scene.property_name when first creating your custom property, after that you should access with bpy.context.scene.property_name. I don't know if that is causing your issues. $\endgroup$ – Ray Mairlot Jan 27 '17 at 11:27
  • $\begingroup$ In addition to above (think @RayMairlot has hit your major issue on the head) , consider changing question title to something like "Emulating Local View". Can be achieved by an update method on the scene.is_isolation_mode property. $\endgroup$ – batFINGER Jan 27 '17 at 16:40
1
$\begingroup$

Kinda hard to answer this q in it's given format. As pointed out by @RayMairlot you are using property definitions incorrectly which is very a likely cause of your woes, possibly with the list bpy.types.Scene.hidden_objects, especially if you have removed (deleted) an object that is in the list prior to accessing it again.

When using bpy.props to assign properties to classes registered with Blender for example you assign the is_isolation_mode property to the Scene class.

bpy.types.Scene.is_isolation_mode = bpy.props.BoolProperty(default=False)

And access on each instance of the class, eg bpy.context.scene , bpy.data.scenes["Scene"] etc.

And definitely NOT by doing this

bpy.types.Scene.is_isolation_mode = False

which assigns false to is_isolation_mode for all instances and cannot be altered from the instance. Toggling above to true makes it true for all instances, which is not what you want. Example code below from the console.

>>> C.scene.is_isolation_mode
False

>>> C.scene.is_isolation_mode = True
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
AttributeError: 'Scene' object attribute 'is_isolation_mode' is read-only

Suggested Alternative Method

A suggested solution to having a pseudo-local mode is using an update method on the is_isolation_mode property assigned to the scene object.

Example code: when in isolation mode all visible objects, except the context object, are hidden and given an "isolation_mode" ID property. They are unhidden and the prop is removed when not in iso mode.

import bpy
from bpy.props import BoolProperty

def hide_mode(scene, context): # standard to use self here to show it's a prop
    if scene.is_isolation_mode: # scene is also context.scene
        obs = [o for o in scene.objects if not o.hide and o != scene.objects.active]
        for o in obs:
            o["isolation_mode"] = 1 # could be anything (bool, int, float, string)
            o.hide = True
    else:
        obs = [o for o in scene.objects if o.get("isolation_mode")]
        for o in obs:
            del(o["isolation_mode"])
            o.hide = False
    return None

bpy.types.Scene.is_isolation_mode = BoolProperty(default=False,
                                                 name="Isolation Mode",
                                                 description="Blah Blah",
                                                 update=hide_mode)

# prepend a toggle button on 3Dview header

def draw_toggle(self, context):
    scene = context.scene
    layout = self.layout
    layout.prop(scene,
                "is_isolation_mode",
                toggle=True)

bpy.types.VIEW3D_HT_header.prepend(draw_toggle)

Toggle button on 3D header enter image description here Set via script in python console. enter image description here

$\endgroup$

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.