I'm trying to programatically apply a partial scaling to a mesh. For this specific scaling, I'm trying to replicate what happens when you've selected a number of vertices of a mesh in Edit Mode and scale them by pressing 'S' to bring them closer together or farther apart.

Like so: [img]

What I've tried is this:


# object was originally a plane which I extruded into the z-axis, so this selects the upper half of the mesh.
upper_verts = [vert for vert in glyph_obj.data.vertices if vert.co[2] > 0]
for vert in upper_verts:
    vert.select = True
bpy.ops.transform.resize(value=(0.9, 0.9, 0.9), orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False, snap=False, snap_elements={'INCREMENT'}, use_snap_project=False, snap_target='CLOSEST', use_snap_self=True, use_snap_edit=True, use_snap_nonedit=True, use_snap_selectable=False)

Where glyph_obj is a bpy Object .

The last command, the bpy.ops.transform.resize, I copied from the info window from when I performed the operation by hand.

I can see in the viewer that my script does select all the appropriate vertices, but no transformation is performed. No errors are generated either. Because I followed programmatically all the steps I would have done by hand (I think), I don't know what I'm missing.

  • $\begingroup$ Operators in bpy.ops are for interactive use through the UI and should be avoided in scripts because they depend on context. Using them through scripts may yield unexpected results at best, or fail entirely at worst. Manipulate data directly from bpy.data instead. $\endgroup$ Commented Jan 26, 2023 at 9:29
  • 1
    $\begingroup$ I would try going out of edit mode then in again, it should force the selection state to be updated $\endgroup$
    – Gorgious
    Commented Jan 26, 2023 at 9:44
  • $\begingroup$ @DuarteFarrajotaRamos Yeah I sort of knew that, but had to use bpy.ops operators for some imports and then continued using them. Think I'll stick to bmesh from now on. $\endgroup$ Commented Jan 28, 2023 at 19:20

1 Answer 1


Without an operator:

import bmesh
from bpy import context as C
from mathutils import Vector

condition = lambda v: v.co.z > 0
scale = 0.9

ob = C.object
me = ob.data
bm = bmesh.from_edit_mesh(me)
verts = [v for v in bm.verts if condition(v)]
average = sum((v.co for v in verts), start=Vector()) / len(verts)

for v in verts:
    offset = v.co - average
#    direction = offset.normalized()
#    v.co += direction * scale
    v.co += offset * (scale - 1)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .