I've been trying to reuse certain parts of code as functions in my bpy scripts. But that means that the same bmesh will be created as 'my_bmesh.001' the next time I run that function. To deal with this, I join 'my_bmesh' with a different object, 'main_object' and then run the function again, hoping that it will notice that 'my_bmesh' doesn't exist anymore, because it was joined into 'main_object' thereby allowing me to avoid situations with .001 names. In one current case, where I make stairs using an add_stairs() function, that function makes 2 objects, 'stairs' and 'stairs_support'. At the end of the function, I join 'stairs_support' into 'stairs'. A different function runs that add_stairs() function twice, and here is where the problem happens. Since 'stairs_support' has already been joined to 'stairs', it no longer exists. Still, upon the next call to add_stairs(), instead of the new bmesh being named 'stairs_support', it would be named 'stairs_support.001' so when the script looks for 'stairs_support' to join it with 'stairs', it returns the error:
"KeyError: bpy_prop_collection[key]: key 'stairs_support' not found"
For now, I just have to check myself that the original object already exists, so it knows to go with the 'stairs_support.001' name, but I don't want to have to make something like a for-loop that goes until it figures out what number mesh the counter has gone up to. I know that the counter restarts when Blender starts up again, but I can't just restart Blender mid-script. How do I refresh this counter, after I join 'stairs_support' to 'stairs'? Or perhaps there is some other means of combating this issue without dealing with the naming counter?
My original script is full of 1AM math that somehow just works, so to keep the code as readable as possible, I created a new script in under 200 lines of code that demonstrates the issue I'm having.
Here is the script:
import bpy
import bmesh
from bpy_extras import object_utils
def add_box(width, height, depth, self, context):
verts = [(+(width / 2.0), +(height / 2.0), -(depth / 2.0)),
(+(width / 2.0), -(height / 2.0), -(depth / 2.0)),
(-(width / 2.0), -(height / 2.0), -(depth / 2.0)),
(-(width / 2.0), +(height / 2.0), -(depth / 2.0)),
(+(width / 2.0), +(height / 2.0), +(depth / 2.0)),
(+(width / 2.0), -(height / 2.0), +(depth / 2.0)),
(-(width / 2.0), -(height / 2.0), +(depth / 2.0)),
(-(width / 2.0), +(height / 2.0), +(depth / 2.0)),
]
faces = [(0, 1, 2, 3),
(4, 7, 6, 5),
(0, 4, 5, 1),
(1, 5, 6, 2),
(2, 6, 7, 3),
(4, 0, 3, 7),
]
mesh = bpy.data.meshes.new("Object1")
bm = bmesh.new()
for v_co in verts:
bm.verts.new(v_co)
bm.verts.ensure_lookup_table()
for f_idx in faces:
bm.faces.new([bm.verts[i] for i in f_idx])
bm.to_mesh(mesh)
mesh.update()
# add the mesh as an object into the scene with this utility module
object_utils.object_data_add(context, mesh, operator=self)
width += 1.0
verts = [(+(width / 2.0), +(height / 2.0), -(depth / 2.0)),
(+(width / 2.0), -(height / 2.0), -(depth / 2.0)),
(-(width / 2.0), -(height / 2.0), -(depth / 2.0)),
(-(width / 2.0), +(height / 2.0), -(depth / 2.0)),
(+(width / 2.0), +(height / 2.0), +(depth / 2.0)),
(+(width / 2.0), -(height / 2.0), +(depth / 2.0)),
(-(width / 2.0), -(height / 2.0), +(depth / 2.0)),
(-(width / 2.0), +(height / 2.0), +(depth / 2.0)),
]
faces = [(0, 1, 2, 3),
(4, 7, 6, 5),
(0, 4, 5, 1),
(1, 5, 6, 2),
(2, 6, 7, 3),
(4, 0, 3, 7),
]
mesh = bpy.data.meshes.new("Object2")
bm = bmesh.new()
for v_co in verts:
bm.verts.new(v_co)
bm.verts.ensure_lookup_table()
for f_idx in faces:
bm.faces.new([bm.verts[i] for i in f_idx])
bm.to_mesh(mesh)
mesh.update()
# add the mesh as an object into the scene with this utility module
object_utils.object_data_add(context, mesh, operator=self)
#THE WAY IT CURRENTLY FAILS:
bpy.data.objects['Object1'].select=True
bpy.data.objects['Object2'].select=True
bpy.context.scene.objects.active = bpy.data.objects['Object1']
bpy.ops.object.join()
bpy.data.objects['Object1'].name = 'Final_object'
#TO MAKE IT WORK, COMMENT OUT THE ABOVE (ALL LINES FROM 79 TO 83) AND UNCOMMENT THE SECTION BELOW:
"""
#Join them and rename them
bpy.ops.object.select_all(action='DESELECT')
if bpy.data.objects.get('Object1') is not None:
bpy.data.objects['Object1'].select=True
else:
bpy.data.objects['Object1.001'].select=True
if bpy.data.objects.get('Object2') is not None:
bpy.data.objects['Object2'].select=True
else:
bpy.data.objects['Object2.001'].select=True
if bpy.data.objects.get('Object1') is not None:
bpy.context.scene.objects.active = bpy.data.objects['Object1']
else:
bpy.context.scene.objects.active = bpy.data.objects['Object1.001']
bpy.ops.object.join()
if bpy.data.objects.get('Object1') is not None:
bpy.data.objects['Object1'].name = 'Final_object'
else:
bpy.data.objects['Object1.001'].name = 'Final_object'
"""
from bpy.props import (
BoolProperty,
BoolVectorProperty,
FloatProperty,
FloatVectorProperty,
)
class AddBox(bpy.types.Operator):
bl_idname = "mesh.primitive_box_add"
bl_label = "Add Box"
bl_options = {'REGISTER', 'UNDO'}
width = FloatProperty(
name="Width",
description="Box Width",
min=0.01, max=100.0,
default=1.0,
)
height = FloatProperty(
name="Height",
description="Box Height",
min=0.01, max=100.0,
default=1.0,
)
depth = FloatProperty(
name="Depth",
description="Box Depth",
min=0.01, max=100.0,
default=1.0,
)
layers = BoolVectorProperty(
name="Layers",
description="Object Layers",
size=20,
options={'HIDDEN', 'SKIP_SAVE'},
)
# generic transform props
view_align = BoolProperty(
name="Align to View",
default=False,
)
location = FloatVectorProperty(
name="Location",
subtype='TRANSLATION',
)
rotation = FloatVectorProperty(
name="Rotation",
subtype='EULER',
)
def execute(self, context):
add_box(self.width, self.height, self.depth, self, context)
add_box(self.width, self.height, self.depth, self, context)
return {'FINISHED'}
def menu_func(self, context):
self.layout.operator(AddBox.bl_idname, icon='MESH_CUBE')
def register():
bpy.utils.register_class(AddBox)
bpy.types.INFO_MT_mesh_add.append(menu_func)
def unregister():
bpy.utils.unregister_class(AddBox)
bpy.types.INFO_MT_mesh_add.remove(menu_func)
if __name__ == "__main__":
register()
And a test .blend file: