# removing/applying modifiers in a script seems to work wrong when inside addon

I've asked this question but couldn't get any answer, so I decided I'll post it again, trying to be more specific.

Let’s assume I have an active object in the scene. The object itself is just a couple of vertical faces but it has a solidify modifier, a hook modifier attached to some of its vertices and a boolean modifier (subtracting part of it with another object). It looks like this: The script is supposed to:
- Make a copy of selected object with its modifiers
- In that copy apply some modifiers and remove others
- Remove most of the object leaving only some edges (namely the lower ones) and extrude them
- Name the modified copy
The script looks like this:

import bpy
import bmesh
from mathutils import Vector

context = bpy.context
ob = context.object

src_verts =[]
bottom_verts =[]
ext_edges =[]

for obj in [o for o in bpy.context.scene.objects if o.type == 'MESH' and o.name == ob.name + ' kondygnacje_podziemne']:

count_ob = float(len(ob.data.vertices))
center_ob = (1.0 / count_ob) * sum([v.co for v in ob.data.vertices], Vector())

#getting lower vertices of object:
for v in [v for v in ob.data.vertices if v.co[2] < center_ob[2]]:

src_verts.append(v.index)

#make a copy of object to alter it after applying and removing certain modifiers:
podz = ob.copy()
podz.data = ob.data.copy()
ob.select_set(False)

context.view_layer.objects.active = podz

#before creating bmesh, apply existing hook and solidify modifiers and remove boolean modifiers:
for mod in [m for m in podz.modifiers if m.type == 'HOOK']:
#print(podz.name)
bpy.ops.object.modifier_apply( modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'BOOLEAN']:
bpy.ops.object.modifier_remove( modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'SOLIDIFY']:
bpy.ops.object.modifier_apply( modifier = mod.name )
#create bmesh from 'podz' after removing/applying modifiers:
bm_podz = bmesh.new()
dg = context.evaluated_depsgraph_get()

bm_podz.from_object(podz, dg)

#make a list of verts to delete
wyk=[]
for v in [v for v in bm_podz.verts if v.index not in src_verts]:

wyk.append(v)

bmesh.ops.delete(bm_podz, geom = wyk, context = 'VERTS')

# get the remaining edges to extrude:
bm_podz.edges.ensure_lookup_table()
for e in bm_podz.edges:
ext_edges.append(e)

#extrude edges:

added_e = bmesh.ops.extrude_edge_only(bm_podz, edges = ext_edges)

print(len([e for e in bm_podz.edges if isinstance(e, bmesh.types.BMEdge)]))
extruded = [v for v in added_e['geom'] if isinstance(v, bmesh.types.BMVert)]
# move extruded vertices to desired position:
bmesh.ops.translate(bm_podz, verts=extruded, vec=(0.0, 0.0,-3.0))

#update mesh:
bm_podz.to_mesh(podz.data)

name = ob.name + 'spam'
podz.name = name

bm_podz.free()

del src_verts
del ext_edges
del bottom_verts
del wyk


when it is run from blender text editor it works as intended, creating this (a "belt" along lower edges of object): however when I use exactly the same script as a function in addon (to simplify here I paste a simple "addon" with just that one function triggered with boolean switch in object properties panel):

import bpy
import bmesh
from mathutils import Vector

def cz_podz(self, context):
context = bpy.context
ob = context.object

src_verts =[]
bottom_verts =[]
ext_edges =[]

for obj in [o for o in bpy.context.scene.objects if o.type == 'MESH' and o.name == ob.name + ' kondygnacje_podziemne']:

count_ob = float(len(ob.data.vertices))
center_ob = (1.0 / count_ob) * sum([v.co for v in ob.data.vertices], Vector())

#getting lower vertices of object:
for v in [v for v in ob.data.vertices if v.co[2] < center_ob[2]]:

src_verts.append(v.index)

#make a copy of object to alter it after applying and removing certain modifiers:
podz = ob.copy()
podz.data = ob.data.copy()
ob.select_set(False)

context.view_layer.objects.active = podz

#before creating bmesh, apply existing hook and solidify modifiers and remove boolean   modifiers:
for mod in [m for m in podz.modifiers if m.type == 'HOOK']:
#print(podz.name)
bpy.ops.object.modifier_apply( modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'BOOLEAN']:
bpy.ops.object.modifier_remove( modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'SOLIDIFY']:
bpy.ops.object.modifier_apply( modifier = mod.name )
#create bmesh from 'podz' after removing/applying modifiers:
bm_podz = bmesh.new()
dg = context.evaluated_depsgraph_get()

bm_podz.from_object(podz, dg)

#make a list of verts to delete
wyk=[]
for v in [v for v in bm_podz.verts if v.index not in src_verts]:

wyk.append(v)

bmesh.ops.delete(bm_podz, geom = wyk, context = 'VERTS')

# get the remaining edges to extrude:
bm_podz.edges.ensure_lookup_table()
for e in bm_podz.edges:
ext_edges.append(e)

#extrude edges:

added_e = bmesh.ops.extrude_edge_only(bm_podz, edges = ext_edges)

print(len([e for e in bm_podz.edges if isinstance(e, bmesh.types.BMEdge)]))
extruded = [v for v in added_e['geom'] if isinstance(v, bmesh.types.BMVert)]
# move extruded vertices to desired position:
bmesh.ops.translate(bm_podz, verts=extruded, vec=(0.0, 0.0,-3.0))

#update mesh:
bm_podz.to_mesh(podz.data)

name = ob.name + 'spam'
podz.name = name

bm_podz.free()

del src_verts
del ext_edges
del bottom_verts
del wyk

bpy.types.Object.myBool4 = bpy.props.BoolProperty(name="boolean_switch", default=False, update=cz_podz)

class ParametryZab_Panel(bpy.types.Panel):
"""Creates a Panel in the Object properties window"""
bl_label = "Spam"
bl_idname = "OBJECT_PT_"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"

def draw(self, context):
layout = self.layout
scene = context.scene
obj = context.object

row = layout.row()
row.prop(obj, "myBool4", toggle = True)

def register():
bpy.utils.register_class(ParametryZab_Panel)

def unregister():
bpy.utils.unregister_class(ParametryZab_Panel)

if __name__ == "__main__":
register()


the result is entirely different: It seems like when the script is run from the "addon", it applies/removes modifiers of the original object, not its copy, while when running standalone from text editor it works ok. It's possibly something embarrassingly obvious but I have no idea why that happens.
I'd appreciate if someone could explain that.
Thank You.

• maybe remove the line context=bpy.context and use the given context. Whats in that context can be controlled somehow, you would need to google though Aug 29, 2019 at 22:02
• hmmm, thank you for taking the time to answer. I'll look into that although TBH it's not really clear why would that be a reason considering the context is exactly the same when script is run as a standalone script, and works fine ?
– MatH
Aug 30, 2019 at 5:16
• Possible issue: using vert indices from a mesh and compare them with the indices of another one. Also, I don't get why your are applying the modifiers as finally bm_podz.from_object(podz, dg) does it automatically (using dg)? And also, the order you apply the modifiers does not match the ones shown in the picture. Aug 30, 2019 at 9:12
• Hi, lemon, thank you for taking a look. As for Indices - i'll investigate but that issue would appear also when the script is run directly from text editor, wouldn't it? I didn't go with bm.from_object method, because I wanted to feed bmesh with a copy having some modifiers applied and some removed. As for the order - frankly I didn't realise that matters but again, shouldn't it work wrong way also in the script itself when it is not embedded in add-on? What happens is - when the script is standalone, the modifiers are applied/removed in podz object (as intended), in "addon" to source object.
– MatH
Aug 30, 2019 at 10:52
• Just to clarify - I did use from_object as one can tell, I just didn't use it at the begining, for reasons mentioned above. I guess the order of dealing with modifiers, although important, doesn't matter here, since the first script works as expected. I think the issue is that when the script is in "addon" it applies/rmoves modifiers in ob.. (the source object) despite context.view_layer.objects.active = podz. But I don't understand why.
– MatH
Aug 30, 2019 at 12:33

The issue seems to be link to the context which does not allow:

context.view_layer.objects.active = podz


But you can:

override = { "object": podz, "active_object": podz }

for mod in [m for m in podz.modifiers if m.type == 'HOOK']:
bpy.ops.object.modifier_apply( override, modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'BOOLEAN']:
bpy.ops.object.modifier_remove( override, modifier = mod.name )
for mod in [m for m in podz.modifiers if m.type == 'SOLIDIFY']:
bpy.ops.object.modifier_apply( override, modifier = mod.name )


Don't know if that can be considered as a 'general case'...

• that did the trick. Didn't know you can do that. Still don't know why the context does not allow context.view_layer.objects.active = podz - I checked and the line does change podz status to active correctly. But still bpy.ops.object.modifier_remove/apply is applied to source object. You think this might be a bug? Anyway, I learned a lot, thank you very much.
– MatH
Aug 31, 2019 at 17:04
• The hint was effectively the original object looses its modifiers. So I conclude context.view_layer.objects.active = podz did not do the job. And context issues "happen sometimes"... Aug 31, 2019 at 17:08
• Yes, but it seemed to do the job - I printed out active object after that line and it was the new object. So what fails IMHO is bpy.ops.object.modifier_remove/apply which is somehow not reading context.view_layer.objects.active = podz or indeed the line itself is not changing dependencies in the scene correctly.
– MatH
Aug 31, 2019 at 17:15