[Bf-blender-cvs] [ddcb6b1023b] master: Cleanup: replace macros with converter callbacks for bpy.props
Campbell Barton
noreply at git.blender.org
Fri Jul 30 04:04:12 CEST 2021
Commit: ddcb6b1023bf3089cd6d2db3012b68b9ec2b980f
Author: Campbell Barton
Date: Thu Jul 29 15:11:58 2021 +1000
Branches: master
https://developer.blender.org/rBddcb6b1023bf3089cd6d2db3012b68b9ec2b980f
Cleanup: replace macros with converter callbacks for bpy.props
Macros were used for expanding shared logic for some properties.
Replace this with Python converters & a funciton that handles
deferred registration.
Add generic converter functions for RNA enums:
- pyrna_enum_value_parse_string
- pyrna_enum_bitfield_parse_set
===================================================================
M source/blender/python/intern/bpy_props.c
M source/blender/python/intern/bpy_rna.c
M source/blender/python/intern/bpy_rna.h
===================================================================
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 6d5ca209866..4b4ca5a0209 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -503,7 +503,7 @@ struct BPYPropArrayLength {
};
/**
- * Use with PyArg_ParseTuple's "O&" formatting.
+ * Use with #PyArg_ParseTuple's `O&` formatting.
*/
static int bpy_prop_array_length_parse(PyObject *o, void *p)
{
@@ -2422,86 +2422,128 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
* This define runs at the start of each function and deals with
* returning a deferred property #BPy_PropDeferred (to be registered later).
*
- * \note `srna` will always be left set if this function doesn't return.
+ * \param self: The self argument from the caller.
+ * \param args: The positional arguments of the caller.
+ * \param kw: The keyword arguments of the caller.
+ * \param method_object: The method of the caller (unfortunately this can't be deduced).
+ * \param r_deferred_result: The deferred result (or NULL in the case of an error).
+ * The caller must return this value unless a valid `srna` is returned.
+ *
+ * \returns When not null, the caller is expected to perform the registration.
*/
-#define BPY_PROPDEF_HEAD(_func) \
- { \
- const int args_len = PyTuple_GET_SIZE(args); \
- if (args_len == 1) { \
- self = PyTuple_GET_ITEM(args, 0); \
- args = PyTuple_New(0); \
- PyObject *ret = BPy_##_func(self, args, kw); \
- Py_DECREF(args); \
- return ret; \
- } \
- if (args_len > 1) { \
- PyErr_SetString(PyExc_ValueError, "all args must be keywords"); \
- return NULL; \
- } \
- srna = srna_from_self(self, #_func "(...):"); \
- if (srna == NULL) { \
- if (PyErr_Occurred()) { \
- return NULL; \
- } \
- return bpy_prop_deferred_data_CreatePyObject(pymeth_##_func, kw); \
- } \
- } \
- (void)0
-
-/* terse macros for error checks shared between all funcs can't use function
- * calls because of static strings passed to pyrna_set_to_enum_bitfield */
-#define BPY_PROPDEF_CHECK(_func, _property_flag_items, _property_flag_override_items) \
- if (UNLIKELY(id_len >= MAX_IDPROP_NAME)) { \
- PyErr_Format(PyExc_TypeError, \
- #_func "(): '%.200s' too long, max length is %d", \
- id, \
- MAX_IDPROP_NAME - 1); \
- return NULL; \
- } \
- if (UNLIKELY(RNA_def_property_free_identifier(srna, id) == -1)) { \
- PyErr_Format(PyExc_TypeError, #_func "(): '%s' is defined as a non-dynamic type", id); \
- return NULL; \
- } \
- if (UNLIKELY(pyopts && pyrna_set_to_enum_bitfield( \
- _property_flag_items, pyopts, &opts, #_func "(options={ ...}):"))) { \
- return NULL; \
- } \
- if (UNLIKELY(pyopts_override && pyrna_set_to_enum_bitfield(_property_flag_override_items, \
- pyopts_override, \
- &opts_override, \
- #_func "(override={ ...}):"))) { \
- return NULL; \
- } \
- { \
- const EnumPropertyItem *tag_defines = RNA_struct_property_tag_defines(srna); \
- if (py_tags && !tag_defines) { \
- PyErr_Format(PyExc_TypeError, \
- #_func "(): property-tags not available for '%s'", \
- RNA_struct_identifier(srna)); \
- return NULL; \
- } \
- if (UNLIKELY(py_tags && pyrna_set_to_enum_bitfield( \
- tag_defines, py_tags, &prop_tags, #_func "(tags={ ...}):"))) { \
- return NULL; \
- } \
- } \
- (void)0
-
-#define BPY_PROPDEF_SUBTYPE_CHECK( \
- _func, _property_flag_items, _property_flag_override_items, _subtype) \
- BPY_PROPDEF_CHECK(_func, _property_flag_items, _property_flag_override_items); \
- if (UNLIKELY(pysubtype && RNA_enum_value_from_id(_subtype, pysubtype, &subtype) == 0)) { \
- const char *enum_str = BPy_enum_as_string(_subtype); \
- PyErr_Format(PyExc_TypeError, \
- #_func \
- "(subtype='%s'): " \
- "subtype not found in (%s)", \
- pysubtype, \
- enum_str); \
- MEM_freeN((void *)enum_str); \
- return NULL; \
- } \
- (void)0
+static StructRNA *bpy_prop_deferred_data_or_srna(PyObject *self,
+ PyObject *args,
+ PyObject *kw,
+ PyObject *method_object,
+ PyObject **r_deferred_result)
+{
+ /* This must be the methods of one of the main property types defined in this file. */
+ BLI_assert(PyCFunction_CheckExact(method_object));
+
+ const int args_len = PyTuple_GET_SIZE(args);
+ PyMethodDef *method_def = ((PyCFunctionObject *)method_object)->m_ml;
+
+ /* Call this function with the first argument set to `self`. */
+ if (args_len == 1) {
+ self = PyTuple_GET_ITEM(args, 0);
+ args = PyTuple_New(0);
+
+ /* This will be #BPy_BoolProperty` or one of the functions that define a type. */
+ PyCFunctionWithKeywords method_fn = (PyCFunctionWithKeywords)method_def->ml_meth;
+ *r_deferred_result = method_fn(self, args, kw);
+ Py_DECREF(args);
+ /* May be an error (depending on `r_deferred_result`). */
+ return NULL;
+ }
+
+ const char *error_prefix = method_def->ml_name;
+ if (args_len > 1) {
+ PyErr_Format(PyExc_ValueError, "%s: all args must be keywords", error_prefix);
+ *r_deferred_result = NULL;
+ /* An error. */
+ return NULL;
+ }
+
+ StructRNA *srna = srna_from_self(self, error_prefix);
+ if (srna == NULL) {
+ *r_deferred_result = PyErr_Occurred() ?
+ NULL :
+ bpy_prop_deferred_data_CreatePyObject(method_object, kw);
+ /* May be an error (depending on `r_deferred_result`). */
+ return NULL;
+ }
+
+ /* Crash if this is ever used by accident! */
+#ifndef NDEBUG
+ *r_deferred_result = (PyObject *)(intptr_t)1;
+#endif
+
+ /* No error or deferred result, perform registration immediately. */
+ return srna;
+}
+
+struct BPy_PropIDParse {
+ const char *value;
+ StructRNA *srna;
+};
+
+/**
+ * Use with #PyArg_ParseTuple's `O&` formatting.
+ */
+static int bpy_prop_arg_parse_id(PyObject *o, void *p)
+{
+ struct BPy_PropIDParse *parse_data = p;
+ StructRNA *srna = parse_data->srna;
+
+ if (!PyUnicode_Check(o)) {
+ PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name);
+ return 0;
+ }
+
+ Py_ssize_t id_len;
+ const char *id;
+
+ id = PyUnicode_AsUTF8AndSize(o, &id_len);
+ if (UNLIKELY(id_len >= MAX_IDPROP_NAME)) {
+ PyErr_Format(PyExc_TypeError, "'%.200s' too long, max length is %d", id, MAX_IDPROP_NAME - 1);
+ return 0;
+ }
+
+ if (UNLIKELY(RNA_def_property_free_identifier(srna, id) == -1)) {
+ PyErr_Format(PyExc_TypeError,
+ "'%s' is defined as a non-dynamic type for '%s'",
+ id,
+ RNA_struct_identifier(srna));
+ return 0;
+ }
+ parse_data->value = id;
+ return 1;
+}
+
+/**
+ * Needed so #RNA_struct_property_tag_defines can be called on the `srna`.
+ */
+struct BPy_EnumProperty_Parse_WithSRNA {
+ struct BPy_EnumProperty_Parse base;
+ StructRNA *srna;
+};
+
+/**
+ * Wrapper for #pyrna_enum_bitfield_parse_set
+ * that looks up tags from the `srna`.
+ */
+static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
+{
+ struct BPy_EnumProperty_Parse_WithSRNA *parse_data = p;
+ parse_data->base.items = RNA_struct_property_tag_defines(parse_data->srna);
+ if (parse_data->base.items == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "property-tags not available for '%s'",
+ RNA_struct_identifier(parse_data->srna));
+ return 0;
+ }
+ return pyrna_enum_bitfield_parse_set(o, &parse_data->base);
+}
/** \} */
@@ -2624,26 +2666,40 @@ PyDoc_STRVAR(BPy_BoolProperty_doc,
BPY_PROPDEF_SET_DOC);
static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
{
- /* Keep this block first. */
StructRNA *srna;
- BPY_PROPDEF_HEAD(BoolProperty);
- BLI_assert(srna != NULL);
+ { /* Keep this block first. */
+ PyObject *deferred_result;
+ srna = bpy_prop_deferred_data_or_srna(self, args, kw, pymeth_BoolProperty, &deferred_result);
+ if (srna == NULL) {
+ return deferred_result;
+ }
+ }
- const char *id = NULL, *name = NULL, *description = "";
- Py_ssize_t id_len;
+ struct BPy_PropIDParse id_data = {
+ .srna = srna,
+ };
+ const char *name = NULL, *description = "";
bool def = false;
PropertyRNA *prop;
- PyObject *pyopts = NULL;
- PyObject *pyopts_override = NULL;
- int opts = 0;
- int opts_override = 0;
- int prop_tags = 0;
- const char *pysubtype = NULL;
- int subtype = PROP_NONE;
+ struct BPy_EnumProperty_Parse options_enum = {
+ .items = property_flag_items,
+ .value = 0,
+ };
+ struct BPy_EnumProperty_Parse override_enum = {
+ .items = property_flag_override_items,
+ .value = 0,
+ };
+ struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
+ .srna = srna,
+ };
+ struct BPy_EnumProperty_Parse subtype_enum = {
+ .items = property_subtype_number_items,
+ .value = PROP_NONE,
+ };
+
PyObject *update_fn = NULL;
PyObject *get_fn = NULL;
PyObject *set_fn = NULL;
- PyObject *py_tags = NULL;
static const char *_keywords[] = {
"attr",
@@ -2659,34 +2715,30 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
"set",
NULL,
};
- static _PyArg_Parser _parser = {"s#|$ssO&O!O!O!sOOO:BoolProperty", _keywords, 0};
+ static _PyArg_Parser _parser = {"O&|$ssO&O&O&O&O&OOO:BoolProperty", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args,
kw,
&_parser,
- &id,
- &id_len,
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list