Merge branch 'blender-v5.1-release'

This commit is contained in:
Sean Kim 2026-02-19 11:40:06 -08:00
commit 429817d96a
6 changed files with 87 additions and 78 deletions

View file

@ -10,75 +10,75 @@ import os
import sys
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
from modules.mesh_test import SpecMeshTest, OperatorSpecObjectMode, RunTest
from modules.mesh_test import SpecMeshTest, OperatorSpec, RunTest
def main():
tests = [
SpecMeshTest('2D Non Cyclic', 'test2DNonCyclic', 'expected2DNonCyclic',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('2D NURBS With Tail', 'test2DNURBSWithTail', 'expected2DNURBSWithTail',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('2D Shape With Hole', 'test2DShapeWithHole', 'expected2DShapeWithHole',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('2D Simple Lower Res', 'test2DSimpleLowerRes', 'expected2DSimpleLowerRes',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('2D Simple Low Res', 'test2DSimpleLowRes', 'expected2DSimpleLowRes',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('2D Square', 'test2DSquare', 'expected2DSquare',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('2D Extrude', 'test2DExtrude', 'expected2DExtrude',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Back', 'testBevelBack', 'expectedBevelBack',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Back Low Res', 'testBevelBackLowRes', 'expectedBevelBackLowRes',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Extrude Back', 'testBevelExtrudeBack', 'expectedBevelExtrudeBack',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Extrude Front', 'testBevelExtrudeFront', 'expectedBevelExtrudeFront',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Extrude Full', 'testBevelExtrudeFull', 'expectedBevelExtrudeFull',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Extrude Half', 'testBevelExtrudeHalf', 'expectedBevelExtrudeHalf',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Front', 'testBevelFront', 'expectedBevelFront',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Front Low Res', 'testBevelFrontLowRes', 'expectedBevelFrontLowRes',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Full', 'testBevelFull', 'expectedBevelFull',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Full Low Res', 'testBevelFullLowRes', 'expectedBevelFullLowRes',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Half', 'testBevelHalf', 'expectedBevelHalf',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Bevel Half Low Res', 'testBevelHalfLowRes', 'expectedBevelHalfLowRes',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Caps None', 'testCapsNone', 'expectedCapsNone',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Caps Object Bevel', 'testCapsObjectBevel', 'expectedCapsObjectBevel',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Caps Profile Bevel', 'testCapsProfileBevel', 'expectedCapsProfileBevel',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Caps Profile Bevel Half', 'testCapsProfileBevelHalf', 'expectedCapsProfileBevelHalf',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Caps Profile Bevel Quarter', 'testCapsProfileBevelQuarter', 'expectedCapsProfileBevelQuarter',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Caps Round Bevel', 'testCapsRoundBevel', 'expectedCapsRoundBevel',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Caps Round Bevel Extrude', 'testCapsRoundBevelExtrude', 'expectedCapsRoundBevelExtrude',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Caps Round Bevel Half', 'testCapsRoundBevelHalf', 'expectedCapsRoundBevelHalf',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Caps Round Bevel Quarter', 'testCapsRoundBevelQuarter', 'expectedCapsRoundBevelQuarter',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Extrude Back', 'testExtrudeBack', 'expectedExtrudeBack',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Extrude Front', 'testExtrudeFront', 'expectedExtrudeFront',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Extrude Full', 'testExtrudeFull', 'expectedExtrudeFull',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Extrude Half', 'testExtrudeHalf', 'expectedExtrudeHalf',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
]
operator_test = RunTest(tests)

View file

@ -12,7 +12,7 @@ import sys
import bpy
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
from modules.mesh_test import SpecMeshTest, ModifierSpec, OperatorSpecObjectMode, DeformModifierSpec, RunTest
from modules.mesh_test import SpecMeshTest, ModifierSpec, OperatorSpec, DeformModifierSpec, RunTest
tests = [
@ -22,7 +22,7 @@ tests = [
SpecMeshTest("SurfaceDeform", "testObjMonkeySurfaceDeform", "expObjMonkeySurfaceDeform",
[DeformModifierSpec(10, [
ModifierSpec('surface_deform', 'SURFACE_DEFORM', {'target': bpy.data.objects["Cube"]})],
OperatorSpecObjectMode('surfacedeform_bind', {'modifier': 'surface_deform'}))]),
OperatorSpec('OBJECT', 'object.surfacedeform_bind', {'modifier': 'surface_deform'}))]),
# Mesh Deform Test, finally can bind to the Target object.
# Actual deformation occurs by animating imitating user input.
@ -30,7 +30,7 @@ tests = [
SpecMeshTest("MeshDeform", "testObjMonkeyMeshDeform", "expObjMonkeyMeshDeform",
[DeformModifierSpec(10, [ModifierSpec('mesh_deform', 'MESH_DEFORM',
{'object': bpy.data.objects["MeshCube"], 'precision': 2})],
OperatorSpecObjectMode('meshdeform_bind', {'modifier': 'mesh_deform'}))]),
OperatorSpec('OBJECT', 'object.meshdeform_bind', {'modifier': 'mesh_deform'}))]),
# Surface Deform Test, finally can bind to the Target object.
# Actual deformation occurs by animating imitating user input.
@ -47,7 +47,7 @@ tests = [
[ModifierSpec('hook2', 'HOOK', {'object': bpy.data.objects["Empty.001"],
'vertex_group': 'hook_vg'}),
ModifierSpec('laplace', 'LAPLACIANDEFORM', {'vertex_group': 'laplace_vg'})],
OperatorSpecObjectMode('laplaciandeform_bind', {'modifier': 'laplace'}))]),
OperatorSpec('OBJECT', 'object.laplaciandeform_bind', {'modifier': 'laplace'}))]),
SpecMeshTest("WarpPlane", "testObjPlaneWarp", "expObjPlaneWarp",
[DeformModifierSpec(10, [ModifierSpec('warp', 'WARP',
@ -78,7 +78,7 @@ tests = [
[DeformModifierSpec(10, [
ModifierSpec('mesh_deform_curve', 'MESH_DEFORM', {'object': bpy.data.objects["Cylinder"],
'precision': 2})],
OperatorSpecObjectMode('meshdeform_bind', {'modifier': 'mesh_deform_curve'}))]),
OperatorSpec('OBJECT', 'object.meshdeform_bind', {'modifier': 'mesh_deform_curve'}))]),
SpecMeshTest("WarpCurve", "testObjBezierCurveWarp", "expObjBezierCurveWarp",
[DeformModifierSpec(10, [ModifierSpec('warp_curve', 'WARP',

View file

@ -17,7 +17,7 @@ import bpy
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(BASE_DIR, "..", ".."))
from modules.mesh_test import RunTest, ModifierSpec, MultiModifierSpec, SpecMeshTest, OperatorSpecObjectMode
from modules.mesh_test import RunTest, ModifierSpec, MultiModifierSpec, SpecMeshTest, OperatorSpec
seed(0)

View file

@ -17,7 +17,7 @@ blender -b --factory-startup tests/files/modeling/modifiers/multires_modifier --
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(BASE_DIR, "..", ".."))
from modules.mesh_test import RunTest, ModifierSpec, SpecMeshTest, OperatorSpecObjectMode
from modules.mesh_test import RunTest, ModifierSpec, SpecMeshTest, OperatorSpec
def main():
@ -25,8 +25,8 @@ def main():
SpecMeshTest("CatmullClarkSubdivide", "testCubeMultires", "expectedCubeMultires",
[
ModifierSpec('multires', 'MULTIRES', {}),
OperatorSpecObjectMode('multires_subdivide', {'modifier': 'multires'}),
OperatorSpecObjectMode('modifier_apply', {'modifier': 'multires'})
OperatorSpec('OBJECT', 'object.multires_subdivide', {'modifier': 'multires'}),
OperatorSpec('OBJECT', 'object.modifier_apply', {'modifier': 'multires'})
], apply_modifier=False),
SpecMeshTest("SimpleSubdivideCube", "testCubeMultiresSimple", "expectedCubeMultiresSimple",
[
@ -43,14 +43,14 @@ def main():
SpecMeshTest("SimpleSubdivide", "testSuzanneSimple", "expectedSuzanneSimple",
[
ModifierSpec('multires', 'MULTIRES', {}),
OperatorSpecObjectMode('multires_subdivide', {'modifier': 'multires', 'mode': 'SIMPLE'}),
OperatorSpecObjectMode('modifier_apply', {'modifier': 'multires'})
OperatorSpec('OBJECT', 'object.multires_subdivide', {'modifier': 'multires', 'mode': 'SIMPLE'}),
OperatorSpec('OBJECT', 'object.modifier_apply', {'modifier': 'multires'})
], apply_modifier=False),
SpecMeshTest("LinearSubdivide", "testSuzanneLinear", "expectedSuzanneLinear",
[
ModifierSpec('multires', 'MULTIRES', {}),
OperatorSpecObjectMode('multires_subdivide', {'modifier': 'multires', 'mode': 'LINEAR'}),
OperatorSpecObjectMode('modifier_apply', {'modifier': 'multires'})
OperatorSpec('OBJECT', 'object.multires_subdivide', {'modifier': 'multires', 'mode': 'LINEAR'}),
OperatorSpec('OBJECT', 'object.modifier_apply', {'modifier': 'multires'})
], apply_modifier=False),
]

View file

@ -139,44 +139,47 @@ class OperatorSpecEditMode:
("and loading bmesh selection history" if (self.select_history) else "")
class OperatorSpecObjectMode:
class OperatorSpec:
"""
Holds an object operator and its parameters. Helper class for DeformModifierSpec.
Needed to support operations in Object Mode and not Edit Mode which is supported by OperatorSpecEditMode.
Holds an operator and its parameters.
"""
def __init__(self, operator_name: str, operator_parameters: dict):
def __init__(self, mode: str, operator_name: str, operator_parameters: dict):
"""
:param operator_name: str - name of the object operator from bpy.ops.object, e.g. "shade_smooth" or "shape_keys"
:param mode: str - the mode to be switched to prior to executing this operator
:param operator_name: str - name of the operator, along with its containing module , e.g. "object.shade_smooth" or "object.shape_keys"
:param operator_parameters: dict - contains operator parameters.
"""
self.mode = mode
self.operator_name = operator_name
self.operator_parameters = operator_parameters
def __str__(self):
return "Operator: " + self.operator_name + " with parameters: " + str(self.operator_parameters)
return "Mode: " + self.mode + " Operator: " + self.operator_name + \
" with parameters: " + str(self.operator_parameters)
class DeformModifierSpec:
"""
Holds a list of deform modifier and OperatorSpecObjectMode.
Holds a list of deform modifier and OperatorSpec.
For deform modifiers which have an object operator
"""
def __init__(self, frame_number: int, modifier_list: list, object_operator_spec: OperatorSpecObjectMode = None):
def __init__(self, frame_number: int, modifier_list: list, operator_spec: OperatorSpec = None):
"""
Constructs a Deform Modifier spec (for user input).
:param frame_number: int - the frame at which animated keyframe is inserted
:param modifier_list: ModifierSpec - contains modifiers
:param object_operator_spec: OperatorSpecObjectMode - contains object operators
:param operator_spec: OperatorSpec - contains operators
"""
self.frame_number = frame_number
self.modifier_list = modifier_list
self.object_operator_spec = object_operator_spec
self.operator_spec = operator_spec
def __str__(self):
return "Modifier: " + str(self.modifier_list) + " with object operator " + str(self.object_operator_spec)
return "Modifier: " + str(self.modifier_list) + " with object operator " + str(self.operator_spec)
class MeshTest(ABC):
@ -536,8 +539,8 @@ class SpecMeshTest(MeshTest):
self._apply_operator_edit_mode(
evaluated_test_object, operation)
elif isinstance(operation, OperatorSpecObjectMode):
self._apply_operator_object_mode(operation)
elif isinstance(operation, OperatorSpec):
self._apply_operator(operation)
elif isinstance(operation, DeformModifierSpec):
self._apply_deform_modifier(evaluated_test_object, operation)
@ -548,7 +551,7 @@ class SpecMeshTest(MeshTest):
else:
raise ValueError("Expected operation of type {} or {} or {} or {}. Got {}".
format(type(ModifierSpec), type(OperatorSpecEditMode),
type(OperatorSpecObjectMode), type(ParticleSystemSpec), type(operation)))
type(OperatorSpec), type(ParticleSystemSpec), type(operation)))
def _set_parameters_impl(self, modifier, modifier_parameters, nested_settings_path, modifier_name):
"""
@ -746,15 +749,18 @@ class SpecMeshTest(MeshTest):
bpy.ops.object.mode_set(mode='OBJECT')
def _apply_operator_object_mode(self, operator: OperatorSpecObjectMode):
def _apply_operator(self, operator: OperatorSpec):
"""
Applies the object operator.
"""
bpy.ops.object.mode_set(mode='OBJECT')
object_operator = getattr(bpy.ops.object, operator.operator_name)
from operator import attrgetter
bpy.ops.object.mode_set(mode=operator.mode)
operator_fn = attrgetter(operator.operator_name)(bpy.ops)
try:
retval = object_operator(**operator.operator_parameters)
retval = operator_fn(**operator.operator_parameters)
except AttributeError:
raise AttributeError("bpy.ops.object has no attribute {}".format(operator.operator_name))
except TypeError as ex:
@ -765,9 +771,12 @@ class SpecMeshTest(MeshTest):
if self.verbose:
print("Applied operator {}".format(operator))
def _apply_deform_modifier(self, test_object, operation: list):
if operator.mode != 'OBJECT':
bpy.ops.object.mode_set('OBJECT')
def _apply_deform_modifier(self, test_object, operation: DeformModifierSpec):
"""
arg: operation: list: List of modifiers or combination of modifier and object operator.
arg: operation: DeformModifierSpec: the modifier spec
"""
scene = bpy.context.scene
@ -775,14 +784,14 @@ class SpecMeshTest(MeshTest):
bpy.ops.object.mode_set(mode='OBJECT')
modifier_operations_list = operation.modifier_list
modifier_names = []
object_operations = operation.object_operator_spec
object_operations = operation.operator_spec
for modifier_operations in modifier_operations_list:
if isinstance(modifier_operations, ModifierSpec):
self._add_modifier(test_object, modifier_operations)
modifier_names.append(modifier_operations.modifier_name)
if isinstance(object_operations, OperatorSpecObjectMode):
self._apply_operator_object_mode(object_operations)
if isinstance(object_operations, OperatorSpec):
self._apply_operator(object_operations)
scene.frame_set(operation.frame_number)

View file

@ -11,7 +11,7 @@ import sys
import inspect
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
from modules.mesh_test import SpecMeshTest, OperatorSpecObjectMode, RunTest
from modules.mesh_test import SpecMeshTest, OperatorSpec, RunTest
class ConversionTypeTestHelper:
@ -102,21 +102,21 @@ class ConversionPair:
def main():
tests = [
SpecMeshTest('Mesh 1', 'Cube', 'Cube_Mesh',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Mesh 2', 'CubeWithEdges', 'CubeWithEdges_Mesh',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Mesh 3', 'Plane', 'Plane_Mesh',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Mesh 4', 'HollowPlane', 'HollowPlane_Mesh',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Mesh 5', 'Suzanne', 'Suzanne_Mesh',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Mesh 6', 'BezierCircle', 'BezierCircle_Mesh',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Mesh 7', 'BezierCurve', 'BezierCurve_Mesh',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
SpecMeshTest('Mesh 8', 'Text', 'Text_Mesh',
[OperatorSpecObjectMode('convert', {'target': 'MESH'})]),
[OperatorSpec('OBJECT', 'object.convert', {'target': 'MESH'})]),
]
type_tests = [