From 4b82edd53c1efde12d68d7239c14115a0a408d9e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 23 Sep 2025 13:35:33 +1000 Subject: [PATCH] Cleanup: minor changes to the BMesh Python API - Add typed array access functions, avoiding the need for casting. - Share error prefix for exceptions. - Use "num" suffix instead of "len". --- source/blender/python/bmesh/bmesh_py_types.cc | 222 ++++++++++-------- source/blender/python/bmesh/bmesh_py_types.hh | 47 +++- .../python/bmesh/bmesh_py_types_customdata.cc | 8 +- .../python/bmesh/bmesh_py_types_select.cc | 59 +++-- source/blender/python/bmesh/bmesh_py_utils.cc | 68 ++---- 5 files changed, 230 insertions(+), 174 deletions(-) diff --git a/source/blender/python/bmesh/bmesh_py_types.cc b/source/blender/python/bmesh/bmesh_py_types.cc index b5a06623236..27f61ae1da4 100644 --- a/source/blender/python/bmesh/bmesh_py_types.cc +++ b/source/blender/python/bmesh/bmesh_py_types.cc @@ -768,20 +768,22 @@ static PyObject *bpy_bmfaceseq_active_get(BPy_BMElemSeq *self, void * /*closure* static int bpy_bmfaceseq_active_set(BPy_BMElem *self, PyObject *value, void * /*closure*/) { + const char *error_prefix = "faces.active = f"; BMesh *bm = self->bm; if (value == Py_None) { bm->act_face = nullptr; return 0; } if (BPy_BMFace_Check(value)) { - BPY_BM_CHECK_SOURCE_INT(bm, "faces.active = f", value); + BPY_BM_CHECK_SOURCE_INT(bm, error_prefix, value); bm->act_face = ((BPy_BMFace *)value)->f; return 0; } PyErr_Format(PyExc_TypeError, - "faces.active = f: expected BMFace or None, not %.200s", + "%s: expected BMFace or None, not %.200s", + error_prefix, Py_TYPE(value)->tp_name); return -1; } @@ -1143,14 +1145,10 @@ PyDoc_STRVAR( " :rtype: :class:`BMesh`\n"); static PyObject *bpy_bmesh_copy(BPy_BMesh *self) { - BMesh *bm; - BMesh *bm_copy; - BPY_BM_CHECK_OBJ(self); - bm = self->bm; - - bm_copy = BM_mesh_copy(bm); + BMesh *bm = self->bm; + BMesh *bm_copy = BM_mesh_copy(bm); if (bm_copy) { return BPy_BMesh_CreatePyObject(bm_copy, BPY_BMFLAG_NOP); @@ -1168,11 +1166,9 @@ PyDoc_STRVAR( " Clear all mesh data.\n"); static PyObject *bpy_bmesh_clear(BPy_BMesh *self) { - BMesh *bm; - BPY_BM_CHECK_OBJ(self); - bm = self->bm; + BMesh *bm = self->bm; BM_mesh_clear(bm); @@ -1225,7 +1221,6 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args) { PyObject *py_mesh; Mesh *mesh; - BMesh *bm; BPY_BM_CHECK_OBJ(self); @@ -1241,7 +1236,7 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args) return nullptr; } - bm = self->bm; + BMesh *bm = self->bm; Main *bmain = nullptr; BMeshToMeshParams params{}; @@ -1293,7 +1288,6 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject Depsgraph *depsgraph; Scene *scene_eval; const Mesh *mesh_eval; - BMesh *bm; bool use_cage = false; bool use_fnorm = true; bool use_vert_normal = true; @@ -1358,7 +1352,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject return nullptr; } - bm = self->bm; + BMesh *bm = self->bm; BMeshFromMeshParams params{}; params.calc_face_normal = use_fnorm; @@ -1400,7 +1394,6 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject * { static const char *kwlist[] = { "mesh", "face_normals", "vertex_normals", "use_shape_key", "shape_key_index", nullptr}; - BMesh *bm; PyObject *py_mesh; Mesh *mesh; bool use_fnorm = true; @@ -1427,7 +1420,7 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject * return nullptr; } - bm = self->bm; + BMesh *bm = self->bm; BMeshFromMeshParams params{}; params.calc_face_normal = use_fnorm; @@ -1598,23 +1591,20 @@ PyDoc_STRVAR( " :rtype: list[tuple[:class:`BMLoop`, :class:`BMLoop`, :class:`BMLoop`]]\n"); static PyObject *bpy_bmesh_calc_loop_triangles(BPy_BMElem *self) { - BMesh *bm; - int corner_tris_tot; PyObject *ret; - int i; BPY_BM_CHECK_OBJ(self); - bm = self->bm; + BMesh *bm = self->bm; corner_tris_tot = poly_to_tri_count(bm->totface, bm->totloop); blender::Array> corner_tris(corner_tris_tot); BM_mesh_calc_tessellation(bm, corner_tris); ret = PyList_New(corner_tris_tot); - for (i = 0; i < corner_tris_tot; i++) { + for (int i = 0; i < corner_tris_tot; i++) { PyList_SET_ITEM(ret, i, BPy_BMLoop_Array_As_Tuple(bm, corner_tris[i].data(), 3)); } @@ -1760,6 +1750,7 @@ PyDoc_STRVAR( " :type fac: float\n"); static PyObject *bpy_bmvert_copy_from_vert_interp(BPy_BMVert *self, PyObject *args) { + const char *error_prefix = "BMVert.copy_from_vert_interp(...)"; PyObject *vert_seq; float fac; @@ -1770,19 +1761,10 @@ static PyObject *bpy_bmvert_copy_from_vert_interp(BPy_BMVert *self, PyObject *ar } BMesh *bm = self->bm; - BMVert **vert_array = nullptr; - Py_ssize_t vert_seq_len; /* always 2 */ - vert_array = static_cast( - BPy_BMElem_PySeq_As_Array(&bm, - vert_seq, - 2, - 2, - &vert_seq_len, - BM_VERT, - true, - true, - "BMVert.copy_from_vert_interp(...)")); + Py_ssize_t vert_seq_num; /* Always 2. */ + BMVert **vert_array = BPy_BMVert_PySeq_As_Array( + &bm, vert_seq, 2, 2, &vert_seq_num, true, true, error_prefix); if (vert_array == nullptr) { return nullptr; @@ -1806,6 +1788,7 @@ PyDoc_STRVAR( " :type face: :class:`BMFace`\n"); static PyObject *bpy_bmvert_copy_from_face_interp(BPy_BMVert *self, PyObject *args) { + const char *error_prefix = "copy_from_face_interp(...)"; BPy_BMFace *py_face = nullptr; BPY_BM_CHECK_OBJ(self); @@ -1816,7 +1799,7 @@ static PyObject *bpy_bmvert_copy_from_face_interp(BPy_BMVert *self, PyObject *ar BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(bm, "copy_from_face_interp()", py_face); + BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, py_face); BM_vert_interp_from_face(bm, self->v, py_face->f); @@ -2039,17 +2022,19 @@ PyDoc_STRVAR( " :rtype: :class:`BMVert` | None\n"); static PyObject *bpy_bmedge_other_vert(BPy_BMEdge *self, BPy_BMVert *value) { + const char *error_prefix = "BMEdge.other_vert(...)"; BMVert *other; BPY_BM_CHECK_OBJ(self); if (!BPy_BMVert_Check(value)) { PyErr_Format(PyExc_TypeError, - "BMEdge.other_vert(vert): BMVert expected, not '%.200s'", + "%s: BMVert expected, not '%.200s'", + error_prefix, Py_TYPE(value)->tp_name); return nullptr; } - BPY_BM_CHECK_SOURCE_OBJ(self->bm, "BMEdge.other_vert(vert)", value); + BPY_BM_CHECK_SOURCE_OBJ(self->bm, error_prefix, value); other = BM_edge_other_vert(self->e, value->v); @@ -2096,6 +2081,7 @@ PyDoc_STRVAR( " :type vert: bool\n"); static PyObject *bpy_bmface_copy_from_face_interp(BPy_BMFace *self, PyObject *args) { + const char *error_prefix = "BMFace.copy_from_face_interp(...)"; BPy_BMFace *py_face = nullptr; bool do_vertex = true; @@ -2113,7 +2099,7 @@ static PyObject *bpy_bmface_copy_from_face_interp(BPy_BMFace *self, PyObject *ar BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(bm, "BMFace.copy_from_face_interp(face)", py_face); + BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, py_face); BM_face_interp_from_face(bm, self->f, py_face->f, do_vertex); @@ -2376,6 +2362,7 @@ PyDoc_STRVAR( " :type multires: bool\n"); static PyObject *bpy_bmloop_copy_from_face_interp(BPy_BMLoop *self, PyObject *args) { + const char *error_prefix = "BMLoop.copy_from_face_interp(face)"; BPy_BMFace *py_face = nullptr; bool do_vertex = true; bool do_multires = true; @@ -2396,7 +2383,7 @@ static PyObject *bpy_bmloop_copy_from_face_interp(BPy_BMLoop *self, PyObject *ar BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(bm, "BMLoop.copy_from_face_interp(face)", py_face); + BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, py_face); BM_loop_interp_from_face(bm, self->l, py_face->f, do_vertex, do_multires); @@ -2532,6 +2519,7 @@ PyDoc_STRVAR( " :rtype: :class:`BMEdge`\n"); static PyObject *bpy_bmedgeseq_new(BPy_BMElemSeq *self, PyObject *args) { + const char *error_prefix = "edges.new(...)"; PyObject *vert_seq; BPy_BMEdge *py_edge_example = nullptr; /* optional */ @@ -2543,17 +2531,15 @@ static PyObject *bpy_bmedgeseq_new(BPy_BMElemSeq *self, PyObject *args) BMesh *bm = self->bm; BMEdge *e; - BMVert **vert_array = nullptr; - Py_ssize_t vert_seq_len; /* always 2 */ PyObject *ret = nullptr; if (py_edge_example) { BPY_BM_CHECK_OBJ(py_edge_example); } - vert_array = static_cast(BPy_BMElem_PySeq_As_Array( - &bm, vert_seq, 2, 2, &vert_seq_len, BM_VERT, true, true, "edges.new(...)")); - + Py_ssize_t vert_seq_num; /* Always 2. */ + BMVert **vert_array = BPy_BMVert_PySeq_As_Array( + &bm, vert_seq, 2, 2, &vert_seq_num, true, true, error_prefix); if (vert_array == nullptr) { return nullptr; } @@ -2608,6 +2594,7 @@ PyDoc_STRVAR( " :rtype: :class:`BMFace`\n"); static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args) { + const char *error_prefix = "faces.new(...)"; PyObject *vert_seq; BPy_BMFace *py_face_example = nullptr; /* optional */ @@ -2618,9 +2605,6 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args) } BMesh *bm = self->bm; - Py_ssize_t vert_seq_len; - - BMVert **vert_array = nullptr; PyObject *ret = nullptr; @@ -2630,16 +2614,16 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args) BPY_BM_CHECK_OBJ(py_face_example); } - vert_array = static_cast(BPy_BMElem_PySeq_As_Array( - &bm, vert_seq, 3, PY_SSIZE_T_MAX, &vert_seq_len, BM_VERT, true, true, "faces.new(...)")); - + Py_ssize_t vert_seq_num; + BMVert **vert_array = BPy_BMVert_PySeq_As_Array( + &bm, vert_seq, 3, PY_SSIZE_T_MAX, &vert_seq_num, true, true, error_prefix); if (vert_array == nullptr) { return nullptr; } /* check if the face exists */ - if (BM_face_exists(vert_array, vert_seq_len) != nullptr) { - PyErr_SetString(PyExc_ValueError, "faces.new(verts): face already exists"); + if (BM_face_exists(vert_array, vert_seq_num) != nullptr) { + PyErr_Format(PyExc_ValueError, "%s: face already exists", error_prefix); goto cleanup; } @@ -2648,14 +2632,14 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args) f_new = BM_face_create_verts(bm, vert_array, - vert_seq_len, + vert_seq_num, py_face_example ? py_face_example->f : nullptr, BM_CREATE_NOP, true); if (UNLIKELY(f_new == nullptr)) { - PyErr_SetString(PyExc_ValueError, - "faces.new(verts): couldn't create the new face, internal error"); + PyErr_Format( + PyExc_ValueError, "%s: couldn't create the new face, internal error", error_prefix); goto cleanup; } @@ -2682,6 +2666,7 @@ PyDoc_STRVAR( " :type vert: :class:`BMVert`\n"); static PyObject *bpy_bmvertseq_remove(BPy_BMElemSeq *self, BPy_BMVert *value) { + const char *error_prefix = "verts.remove(vert)"; BPY_BM_CHECK_OBJ(self); if (!BPy_BMVert_Check(value)) { @@ -2690,7 +2675,7 @@ static PyObject *bpy_bmvertseq_remove(BPy_BMElemSeq *self, BPy_BMVert *value) BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(bm, "verts.remove(vert)", value); + BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, value); BM_vert_kill(bm, value->v); bpy_bm_generic_invalidate((BPy_BMGeneric *)value); @@ -2708,6 +2693,7 @@ PyDoc_STRVAR( " :type edge: :class:`BMEdge`\n"); static PyObject *bpy_bmedgeseq_remove(BPy_BMElemSeq *self, BPy_BMEdge *value) { + const char *error_prefix = "edges.remove(...)"; BPY_BM_CHECK_OBJ(self); if (!BPy_BMEdge_Check(value)) { @@ -2716,7 +2702,7 @@ static PyObject *bpy_bmedgeseq_remove(BPy_BMElemSeq *self, BPy_BMEdge *value) BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(bm, "edges.remove(edges)", value); + BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, value); BM_edge_kill(bm, value->e); bpy_bm_generic_invalidate((BPy_BMGeneric *)value); @@ -2734,6 +2720,7 @@ PyDoc_STRVAR( " :type face: :class:`BMFace`\n"); static PyObject *bpy_bmfaceseq_remove(BPy_BMElemSeq *self, BPy_BMFace *value) { + const char *error_prefix = "faces.remove(...)"; BPY_BM_CHECK_OBJ(self); if (!BPy_BMFace_Check(value)) { @@ -2742,7 +2729,7 @@ static PyObject *bpy_bmfaceseq_remove(BPy_BMElemSeq *self, BPy_BMFace *value) BMesh *bm = self->bm; - BPY_BM_CHECK_SOURCE_OBJ(bm, "faces.remove(face)", value); + BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, value); BM_face_kill(bm, value->f); bpy_bm_generic_invalidate((BPy_BMGeneric *)value); @@ -2764,6 +2751,7 @@ PyDoc_STRVAR( " :rtype: :class:`BMEdge`\n"); static PyObject *bpy_bmedgeseq_get__method(BPy_BMElemSeq *self, PyObject *args) { + const char *error_prefix = "edges.get(...)"; PyObject *vert_seq; PyObject *fallback = Py_None; /* optional */ @@ -2775,12 +2763,11 @@ static PyObject *bpy_bmedgeseq_get__method(BPy_BMElemSeq *self, PyObject *args) BMesh *bm = self->bm; BMEdge *e; - BMVert **vert_array = nullptr; - Py_ssize_t vert_seq_len; /* always 2 */ PyObject *ret = nullptr; - vert_array = static_cast(BPy_BMElem_PySeq_As_Array( - &bm, vert_seq, 2, 2, &vert_seq_len, BM_VERT, true, true, "edges.get(...)")); + Py_ssize_t vert_seq_num; /* Always 2. */ + BMVert **vert_array = BPy_BMVert_PySeq_As_Array( + &bm, vert_seq, 2, 2, &vert_seq_num, true, true, error_prefix); if (vert_array == nullptr) { return nullptr; @@ -2812,6 +2799,7 @@ PyDoc_STRVAR( " :rtype: :class:`BMFace`\n"); static PyObject *bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args) { + const char *error_prefix = "faces.get(...)"; PyObject *vert_seq; PyObject *fallback = Py_None; /* optional */ @@ -2823,18 +2811,17 @@ static PyObject *bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args) BMesh *bm = self->bm; BMFace *f = nullptr; - BMVert **vert_array = nullptr; - Py_ssize_t vert_seq_len; PyObject *ret = nullptr; - vert_array = static_cast(BPy_BMElem_PySeq_As_Array( - &bm, vert_seq, 1, PY_SSIZE_T_MAX, &vert_seq_len, BM_VERT, true, true, "faces.get(...)")); + Py_ssize_t vert_seq_num; + BMVert **vert_array = BPy_BMVert_PySeq_As_Array( + &bm, vert_seq, 1, PY_SSIZE_T_MAX, &vert_seq_num, true, true, error_prefix); if (vert_array == nullptr) { return nullptr; } - f = BM_face_exists(vert_array, vert_seq_len); + f = BM_face_exists(vert_array, vert_seq_num); if (f != nullptr) { ret = BPy_BMFace_CreatePyObject(bm, f); } @@ -4457,7 +4444,7 @@ void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm, PyObject *seq_fast, Py_ssize_t min, Py_ssize_t max, - Py_ssize_t *r_size, + Py_ssize_t *r_seq_num, const char htype, const bool do_unique_check, const bool do_bm_check, @@ -4465,28 +4452,28 @@ void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm, { BMesh *bm = (r_bm && *r_bm) ? *r_bm : nullptr; PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast); - const Py_ssize_t seq_len = PySequence_Fast_GET_SIZE(seq_fast); + const Py_ssize_t seq_num = PySequence_Fast_GET_SIZE(seq_fast); Py_ssize_t i, i_last_dirty = PY_SSIZE_T_MAX; BPy_BMElem *item; BMElem **alloc; - *r_size = 0; + *r_seq_num = 0; - if (seq_len < min || seq_len > max) { + if (seq_num < min || seq_num > max) { PyErr_Format(PyExc_TypeError, "%s: sequence incorrect size, expected [%d - %d], given %d", error_prefix, min, max, - seq_len); + seq_num); return nullptr; } /* from now on, use goto */ - alloc = static_cast(PyMem_MALLOC(seq_len * sizeof(BPy_BMElem **))); + alloc = static_cast(PyMem_MALLOC(seq_num * sizeof(BPy_BMElem **))); - for (i = 0; i < seq_len; i++) { + for (i = 0; i < seq_num; i++) { item = (BPy_BMElem *)seq_fast_items[i]; if (!BPy_BMElem_CheckHType(Py_TYPE(item), htype)) { @@ -4528,7 +4515,7 @@ void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm, if (do_unique_check) { /* check for double verts! */ bool ok = true; - for (i = 0; i < seq_len; i++) { + for (i = 0; i < seq_num; i++) { if (UNLIKELY(BM_elem_flag_test(alloc[i], BM_ELEM_INTERNAL_TAG) == false)) { ok = false; } @@ -4548,7 +4535,7 @@ void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm, } } - *r_size = seq_len; + *r_seq_num = seq_num; if (r_bm) { *r_bm = bm; } @@ -4568,7 +4555,7 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, - Py_ssize_t *r_size, + Py_ssize_t *r_seq_num, const char htype, const bool do_unique_check, const bool do_bm_check, @@ -4582,55 +4569,104 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, } ret = static_cast(BPy_BMElem_PySeq_As_Array_FAST( - r_bm, seq_fast, min, max, r_size, htype, do_unique_check, do_bm_check, error_prefix)); + r_bm, seq_fast, min, max, r_seq_num, htype, do_unique_check, do_bm_check, error_prefix)); Py_DECREF(seq_fast); return ret; } -PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len) +BMVert **BPy_BMVert_PySeq_As_Array(BMesh **r_bm, + PyObject *seq, + Py_ssize_t min, + Py_ssize_t max, + Py_ssize_t *r_seq_num, + bool do_unique_check, + bool do_bm_check, + const char *error_prefix) +{ + return static_cast(BPy_BMElem_PySeq_As_Array( + r_bm, seq, min, max, r_seq_num, BM_VERT, do_unique_check, do_bm_check, error_prefix)); +} +BMEdge **BPy_BMEdge_PySeq_As_Array(BMesh **r_bm, + PyObject *seq, + Py_ssize_t min, + Py_ssize_t max, + Py_ssize_t *r_seq_num, + bool do_unique_check, + bool do_bm_check, + const char *error_prefix) +{ + return static_cast(BPy_BMElem_PySeq_As_Array( + r_bm, seq, min, max, r_seq_num, BM_EDGE, do_unique_check, do_bm_check, error_prefix)); +} +BMFace **BPy_BMFace_PySeq_As_Array(BMesh **r_bm, + PyObject *seq, + Py_ssize_t min, + Py_ssize_t max, + Py_ssize_t *r_seq_num, + bool do_unique_check, + bool do_bm_check, + const char *error_prefix) +{ + return static_cast(BPy_BMElem_PySeq_As_Array( + r_bm, seq, min, max, r_seq_num, BM_FACE, do_unique_check, do_bm_check, error_prefix)); +} +BMLoop **BPy_BMLoop_PySeq_As_Array(BMesh **r_bm, + PyObject *seq, + Py_ssize_t min, + Py_ssize_t max, + Py_ssize_t *r_seq_num, + bool do_unique_check, + bool do_bm_check, + const char *error_prefix) +{ + return static_cast(BPy_BMElem_PySeq_As_Array( + r_bm, seq, min, max, r_seq_num, BM_LOOP, do_unique_check, do_bm_check, error_prefix)); +} + +PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_num) { Py_ssize_t i; - PyObject *ret = PyTuple_New(elem_len); - for (i = 0; i < elem_len; i++) { + PyObject *ret = PyTuple_New(elem_num); + for (i = 0; i < elem_num; i++) { PyTuple_SET_ITEM(ret, i, BPy_BMElem_CreatePyObject(bm, elem[i])); } return ret; } -PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_len) +PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_num) { Py_ssize_t i; - PyObject *ret = PyTuple_New(elem_len); - for (i = 0; i < elem_len; i++) { + PyObject *ret = PyTuple_New(elem_num); + for (i = 0; i < elem_num; i++) { PyTuple_SET_ITEM(ret, i, BPy_BMVert_CreatePyObject(bm, elem[i])); } return ret; } -PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_len) +PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_num) { Py_ssize_t i; - PyObject *ret = PyTuple_New(elem_len); - for (i = 0; i < elem_len; i++) { + PyObject *ret = PyTuple_New(elem_num); + for (i = 0; i < elem_num; i++) { PyTuple_SET_ITEM(ret, i, BPy_BMEdge_CreatePyObject(bm, elem[i])); } return ret; } -PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len) +PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_num) { Py_ssize_t i; - PyObject *ret = PyTuple_New(elem_len); - for (i = 0; i < elem_len; i++) { + PyObject *ret = PyTuple_New(elem_num); + for (i = 0; i < elem_num; i++) { PyTuple_SET_ITEM(ret, i, BPy_BMFace_CreatePyObject(bm, elem[i])); } return ret; } -PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop *const *elem, Py_ssize_t elem_len) +PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop *const *elem, Py_ssize_t elem_num) { Py_ssize_t i; - PyObject *ret = PyTuple_New(elem_len); - for (i = 0; i < elem_len; i++) { + PyObject *ret = PyTuple_New(elem_num); + for (i = 0; i < elem_num; i++) { PyTuple_SET_ITEM(ret, i, BPy_BMLoop_CreatePyObject(bm, elem[i])); } diff --git a/source/blender/python/bmesh/bmesh_py_types.hh b/source/blender/python/bmesh/bmesh_py_types.hh index b3921d63700..49bb3205967 100644 --- a/source/blender/python/bmesh/bmesh_py_types.hh +++ b/source/blender/python/bmesh/bmesh_py_types.hh @@ -157,7 +157,7 @@ enum { PyObject *seq_fast, Py_ssize_t min, Py_ssize_t max, - Py_ssize_t *r_size, + Py_ssize_t *r_seq_num, char htype, bool do_unique_check, bool do_bm_check, @@ -166,19 +166,52 @@ enum { PyObject *seq, Py_ssize_t min, Py_ssize_t max, - Py_ssize_t *r_size, + Py_ssize_t *r_seq_num, char htype, bool do_unique_check, bool do_bm_check, const char *error_prefix); -[[nodiscard]] PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len); -[[nodiscard]] PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_len); -[[nodiscard]] PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_len); -[[nodiscard]] PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len); +[[nodiscard]] BMVert **BPy_BMVert_PySeq_As_Array(BMesh **r_bm, + PyObject *seq, + Py_ssize_t min, + Py_ssize_t max, + Py_ssize_t *r_seq_num, + bool do_unique_check, + bool do_bm_check, + const char *error_prefix); +[[nodiscard]] BMEdge **BPy_BMEdge_PySeq_As_Array(BMesh **r_bm, + PyObject *seq, + Py_ssize_t min, + Py_ssize_t max, + Py_ssize_t *r_seq_num, + bool do_unique_check, + bool do_bm_check, + const char *error_prefix); +[[nodiscard]] BMFace **BPy_BMFace_PySeq_As_Array(BMesh **r_bm, + PyObject *seq, + Py_ssize_t min, + Py_ssize_t max, + Py_ssize_t *r_seq_num, + bool do_unique_check, + bool do_bm_check, + const char *error_prefix); +[[nodiscard]] BMLoop **BPy_BMLoop_PySeq_As_Array(BMesh **r_bm, + PyObject *seq, + Py_ssize_t min, + Py_ssize_t max, + Py_ssize_t *r_seq_num, + bool do_unique_check, + bool do_bm_check, + const char *error_prefix); + +[[nodiscard]] PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_num); +[[nodiscard]] PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_num); +[[nodiscard]] PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_num); +[[nodiscard]] PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_num); [[nodiscard]] PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop *const *elem, - Py_ssize_t elem_len); + Py_ssize_t elem_num); [[nodiscard]] int BPy_BMElem_CheckHType(PyTypeObject *type, char htype); /** diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.cc b/source/blender/python/bmesh/bmesh_py_types_customdata.cc index 2e4cb4db60d..2eaca7875c5 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.cc +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.cc @@ -431,20 +431,22 @@ PyDoc_STRVAR( " :type other: :class:`BMLayerItem`\n"); static PyObject *bpy_bmlayeritem_copy_from(BPy_BMLayerItem *self, BPy_BMLayerItem *value) { + const char *error_prefix = "layer.copy_from(...)"; CustomData *data; if (!BPy_BMLayerItem_Check(value)) { PyErr_Format(PyExc_TypeError, - "layer.copy_from(x): expected BMLayerItem, not '%.200s'", + "%s: expected BMLayerItem, not '%.200s'", + error_prefix, Py_TYPE(value)->tp_name); return nullptr; } BPY_BM_CHECK_OBJ(self); - BPY_BM_CHECK_SOURCE_OBJ(self->bm, "layer.copy_from()", value); + BPY_BM_CHECK_SOURCE_OBJ(self->bm, error_prefix, value); if ((self->htype != value->htype) || (self->type != value->type)) { - PyErr_SetString(PyExc_ValueError, "layer.copy_from(other): layer type mismatch"); + PyErr_Format(PyExc_ValueError, "%s: layer type mismatch", error_prefix); } else if (self->index == value->index) { diff --git a/source/blender/python/bmesh/bmesh_py_types_select.cc b/source/blender/python/bmesh/bmesh_py_types_select.cc index b8dc3f9dbe0..06dbe4898e3 100644 --- a/source/blender/python/bmesh/bmesh_py_types_select.cc +++ b/source/blender/python/bmesh/bmesh_py_types_select.cc @@ -86,15 +86,18 @@ PyDoc_STRVAR( " Add an element to the selection history (no action taken if its already added).\n"); static PyObject *bpy_bmeditselseq_add(BPy_BMEditSelSeq *self, BPy_BMElem *value) { + const char *error_prefix = "select_history.add(...)"; BPY_BM_CHECK_OBJ(self); if ((BPy_BMVert_Check(value) || BPy_BMEdge_Check(value) || BPy_BMFace_Check(value)) == false) { - PyErr_Format( - PyExc_TypeError, "Expected a BMVert/BMedge/BMFace not a %.200s", Py_TYPE(value)->tp_name); + PyErr_Format(PyExc_TypeError, + "%s: expected a BMVert/BMedge/BMFace not a %.200s", + error_prefix, + Py_TYPE(value)->tp_name); return nullptr; } - BPY_BM_CHECK_SOURCE_OBJ(self->bm, "select_history.add()", value); + BPY_BM_CHECK_SOURCE_OBJ(self->bm, error_prefix, value); BM_select_history_store(self->bm, value->ele); @@ -109,18 +112,21 @@ PyDoc_STRVAR( " Remove an element from the selection history.\n"); static PyObject *bpy_bmeditselseq_remove(BPy_BMEditSelSeq *self, BPy_BMElem *value) { + const char *error_prefix = "select_history.remove(...)"; BPY_BM_CHECK_OBJ(self); if ((BPy_BMVert_Check(value) || BPy_BMEdge_Check(value) || BPy_BMFace_Check(value)) == false) { - PyErr_Format( - PyExc_TypeError, "Expected a BMVert/BMedge/BMFace not a %.200s", Py_TYPE(value)->tp_name); + PyErr_Format(PyExc_TypeError, + "%s: expected a BMVert/BMedge/BMFace not a %.200s", + error_prefix, + Py_TYPE(value)->tp_name); return nullptr; } - BPY_BM_CHECK_SOURCE_OBJ(self->bm, "select_history.remove()", value); + BPY_BM_CHECK_SOURCE_OBJ(self->bm, error_prefix, value); if (BM_select_history_remove(self->bm, value->ele) == false) { - PyErr_SetString(PyExc_ValueError, "Element not found in selection history"); + PyErr_Format(PyExc_ValueError, "%s: element not found in selection history", error_prefix); return nullptr; } @@ -137,15 +143,18 @@ PyDoc_STRVAR( " Like remove but doesn't raise an error when the elements not in the selection list.\n"); static PyObject *bpy_bmeditselseq_discard(BPy_BMEditSelSeq *self, BPy_BMElem *value) { + const char *error_prefix = "select_history.discard()"; BPY_BM_CHECK_OBJ(self); if ((BPy_BMVert_Check(value) || BPy_BMEdge_Check(value) || BPy_BMFace_Check(value)) == false) { - PyErr_Format( - PyExc_TypeError, "Expected a BMVert/BMedge/BMFace not a %.200s", Py_TYPE(value)->tp_name); + PyErr_Format(PyExc_TypeError, + "%s: expected a BMVert/BMedge/BMFace not a %.200s", + error_prefix, + Py_TYPE(value)->tp_name); return nullptr; } - BPY_BM_CHECK_SOURCE_OBJ(self->bm, "select_history.discard()", value); + BPY_BM_CHECK_SOURCE_OBJ(self->bm, error_prefix, value); BM_select_history_remove(self->bm, value->ele); @@ -427,24 +436,22 @@ void BPy_BM_init_types_select() int BPy_BMEditSel_Assign(BPy_BMesh *self, PyObject *value) { - BMesh *bm; - Py_ssize_t value_len; - Py_ssize_t i; - BMElem **value_array = nullptr; - + const char *error_prefix = "BMesh.select_history = value"; BPY_BM_CHECK_INT(self); - bm = self->bm; + BMesh *bm = self->bm; - value_array = static_cast(BPy_BMElem_PySeq_As_Array(&bm, - value, - 0, - PY_SSIZE_T_MAX, - &value_len, - BM_VERT | BM_EDGE | BM_FACE, - true, - true, - "BMesh.select_history = value")); + Py_ssize_t value_num; + BMElem **value_array = static_cast( + BPy_BMElem_PySeq_As_Array(&bm, + value, + 0, + PY_SSIZE_T_MAX, + &value_num, + BM_VERT | BM_EDGE | BM_FACE, + true, + true, + error_prefix)); if (value_array == nullptr) { return -1; @@ -452,7 +459,7 @@ int BPy_BMEditSel_Assign(BPy_BMesh *self, PyObject *value) BM_select_history_clear(bm); - for (i = 0; i < value_len; i++) { + for (Py_ssize_t i = 0; i < value_num; i++) { BM_select_history_store_notest(bm, value_array[i]); } diff --git a/source/blender/python/bmesh/bmesh_py_utils.cc b/source/blender/python/bmesh/bmesh_py_utils.cc index 05a3d7d712a..e864367eb41 100644 --- a/source/blender/python/bmesh/bmesh_py_utils.cc +++ b/source/blender/python/bmesh/bmesh_py_utils.cc @@ -196,6 +196,7 @@ PyDoc_STRVAR( " .. note:: The verts mustn't share an edge or face.\n"); static PyObject *bpy_bm_utils_vert_splice(PyObject * /*self*/, PyObject *args) { + const char *error_prefix = "vert_splice(...)"; BPy_BMVert *py_vert; BPy_BMVert *py_vert_target; @@ -213,20 +214,20 @@ static PyObject *bpy_bm_utils_vert_splice(PyObject * /*self*/, PyObject *args) BPY_BM_CHECK_OBJ(py_vert_target); bm = py_vert->bm; - BPY_BM_CHECK_SOURCE_OBJ(bm, "vert_splice", py_vert_target); + BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, py_vert_target); if (py_vert->v == py_vert_target->v) { - PyErr_SetString(PyExc_ValueError, "vert_splice(...): vert arguments match"); + PyErr_Format(PyExc_ValueError, "%s: vert arguments match", error_prefix); return nullptr; } if (BM_edge_exists(py_vert->v, py_vert_target->v)) { - PyErr_SetString(PyExc_ValueError, "vert_splice(...): verts cannot share an edge"); + PyErr_Format(PyExc_ValueError, "%s: verts cannot share an edge", error_prefix); return nullptr; } if (BM_vert_pair_share_face_check(py_vert->v, py_vert_target->v)) { - PyErr_SetString(PyExc_ValueError, "vert_splice(...): verts cannot share a face"); + PyErr_Format(PyExc_ValueError, "%s: verts cannot share a face", error_prefix); return nullptr; } @@ -253,6 +254,7 @@ PyDoc_STRVAR( " :rtype: tuple[:class:`bmesh.types.BMVert`, ...]\n"); static PyObject *bpy_bm_utils_vert_separate(PyObject * /*self*/, PyObject *args) { + const char *error_prefix = "vert_separate(...)"; BPy_BMVert *py_vert; PyObject *edge_seq; @@ -260,10 +262,6 @@ static PyObject *bpy_bm_utils_vert_separate(PyObject * /*self*/, PyObject *args) BMVert **elem; int elem_len; - /* edges to split */ - BMEdge **edge_array; - Py_ssize_t edge_array_len; - PyObject *ret; if (!PyArg_ParseTuple(args, "O!O:vert_separate", &BPy_BMVert_Type, &py_vert, &edge_seq)) { @@ -274,21 +272,16 @@ static PyObject *bpy_bm_utils_vert_separate(PyObject * /*self*/, PyObject *args) bm = py_vert->bm; - edge_array = static_cast(BPy_BMElem_PySeq_As_Array(&bm, - edge_seq, - 0, - PY_SSIZE_T_MAX, - &edge_array_len, - BM_EDGE, - true, - true, - "vert_separate(...)")); + /* Edges to split. */ + Py_ssize_t edge_array_num; + BMEdge **edge_array = BPy_BMEdge_PySeq_As_Array( + &bm, edge_seq, 0, PY_SSIZE_T_MAX, &edge_array_num, true, true, error_prefix); if (edge_array == nullptr) { return nullptr; } - BM_vert_separate(bm, py_vert->v, edge_array, edge_array_len, false, &elem, &elem_len); + BM_vert_separate(bm, py_vert->v, edge_array, edge_array_num, false, &elem, &elem_len); /* return collected verts */ ret = BPy_BMVert_Array_As_Tuple(bm, elem, elem_len); MEM_freeN(elem); @@ -554,14 +547,12 @@ PyDoc_STRVAR( "ignored as loose edges.\n"); static PyObject *bpy_bm_utils_face_split_edgenet(PyObject * /*self*/, PyObject *args, PyObject *kw) { + const char *error_prefix = "face_split_edgenet(...)"; static const char *kwlist[] = {"face", "edgenet", nullptr}; BPy_BMFace *py_face; PyObject *edge_seq; - BMEdge **edge_array; - Py_ssize_t edge_array_len; - BMesh *bm; bool ok; @@ -581,15 +572,9 @@ static PyObject *bpy_bm_utils_face_split_edgenet(PyObject * /*self*/, PyObject * bm = py_face->bm; - edge_array = static_cast(BPy_BMElem_PySeq_As_Array(&bm, - edge_seq, - 1, - PY_SSIZE_T_MAX, - &edge_array_len, - BM_EDGE, - true, - true, - "face_split_edgenet(...)")); + Py_ssize_t edge_array_num; + BMEdge **edge_array = BPy_BMEdge_PySeq_As_Array( + &bm, edge_seq, 1, PY_SSIZE_T_MAX, &edge_array_num, true, true, error_prefix); if (edge_array == nullptr) { return nullptr; @@ -597,7 +582,7 @@ static PyObject *bpy_bm_utils_face_split_edgenet(PyObject * /*self*/, PyObject * /* --- main function body --- */ blender::Vector face_arr; - ok = BM_face_split_edgenet(bm, py_face->f, edge_array, edge_array_len, &face_arr); + ok = BM_face_split_edgenet(bm, py_face->f, edge_array, edge_array_num, &face_arr); PyMem_FREE(edge_array); @@ -626,10 +611,9 @@ PyDoc_STRVAR( " :rtype: :class:`bmesh.types.BMFace`\n"); static PyObject *bpy_bm_utils_face_join(PyObject * /*self*/, PyObject *args) { + const char *error_prefix = "face_join(...)"; BMesh *bm = nullptr; PyObject *py_face_array; - BMFace **face_array; - Py_ssize_t face_seq_len = 0; BMFace *f_new; bool do_remove = true; @@ -637,16 +621,9 @@ static PyObject *bpy_bm_utils_face_join(PyObject * /*self*/, PyObject *args) return nullptr; } - face_array = static_cast(BPy_BMElem_PySeq_As_Array(&bm, - py_face_array, - 2, - PY_SSIZE_T_MAX, - &face_seq_len, - BM_FACE, - true, - true, - "face_join(...)")); - + Py_ssize_t face_seq_len = 0; + BMFace **face_array = BPy_BMFace_PySeq_As_Array( + &bm, py_face_array, 2, PY_SSIZE_T_MAX, &face_seq_len, true, true, error_prefix); if (face_array == nullptr) { return nullptr; /* error will be set */ } @@ -687,6 +664,7 @@ PyDoc_STRVAR( " This is the same as loop_separate, and has only been added for convenience.\n"); static PyObject *bpy_bm_utils_face_vert_separate(PyObject * /*self*/, PyObject *args) { + const char *error_prefix = "face_vert_separate()"; BPy_BMFace *py_face; BPy_BMVert *py_vert; @@ -703,12 +681,12 @@ static PyObject *bpy_bm_utils_face_vert_separate(PyObject * /*self*/, PyObject * bm = py_face->bm; BPY_BM_CHECK_OBJ(py_face); - BPY_BM_CHECK_SOURCE_OBJ(bm, "face_vert_separate()", py_vert); + BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, py_vert); l = BM_face_vert_share_loop(py_face->f, py_vert->v); if (l == nullptr) { - PyErr_SetString(PyExc_ValueError, "vertex not found in face"); + PyErr_Format(PyExc_ValueError, "%s: vertex not found in face", error_prefix); return nullptr; }