RNA: Allow structs to define tags for their properties
authorJulian Eisel <eiseljulian@gmail.com>
Wed, 29 Nov 2017 02:52:06 +0000 (13:52 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 29 Nov 2017 02:53:34 +0000 (13:53 +1100)
Adds support for defining a number of tags as part of the rna-struct
definition, which its properties can set similar to property-flags.
BPY supports setting these tags when defining custom properties too.

* To define tags for a struct (which its properties can use then), define the tags in an `EnumPropertyItem` array, and assign them to the struct using `RNA_def_struct_property_tags(...)`.
* To set tags for an RNA-property in C, use the new `RNA_def_property_tags(...)`.
* To set tags for an RNA-property in Python, use the newly added tags parameter. E.g. `bpy.props.FloatProperty(name="Some Float", tags={'SOME_TAG', 'ANOTHER_TAG'})`.

source/blender/makesrna/RNA_access.h
source/blender/makesrna/RNA_define.h
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_define.c
source/blender/makesrna/intern/rna_internal_types.h
source/blender/makesrna/intern/rna_rna.c
source/blender/python/intern/bpy_props.c

index dd96b1848df915abb0bfb7e1af55a9c08287cb75..5f97724eaa63edcb5346efe449db26e3647c3309 100644 (file)
@@ -745,6 +745,7 @@ const char *RNA_struct_translation_context(const StructRNA *type);
 int RNA_struct_ui_icon(const StructRNA *type);
 
 PropertyRNA *RNA_struct_name_property(StructRNA *type);
+const EnumPropertyItem *RNA_struct_property_tag_defines(const StructRNA *type);
 PropertyRNA *RNA_struct_iterator_property(StructRNA *type);
 StructRNA *RNA_struct_base(StructRNA *type);
 
@@ -799,6 +800,7 @@ PropertyType RNA_property_type(PropertyRNA *prop);
 PropertySubType RNA_property_subtype(PropertyRNA *prop);
 PropertyUnit RNA_property_unit(PropertyRNA *prop);
 int RNA_property_flag(PropertyRNA *prop);
+int RNA_property_tags(PropertyRNA *prop);
 bool RNA_property_builtin(PropertyRNA *prop);
 void *RNA_property_py_data_get(PropertyRNA *prop);
 
@@ -835,6 +837,7 @@ bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r
 bool RNA_enum_description(const EnumPropertyItem *item, const int value, const char **description);
 int  RNA_enum_from_value(const EnumPropertyItem *item, const int value);
 int  RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifier);
+unsigned int RNA_enum_items_count(const EnumPropertyItem *item);
 
 void RNA_property_enum_items_ex(
         struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const bool use_static,
index 2b61a5bb605d76035faa4b3f46a74c54c3727680..5f71f2ccdcf5e3cecdadaff97d0812e6e6bfe727 100644 (file)
@@ -58,6 +58,7 @@ void RNA_def_struct_name_property(StructRNA *srna, PropertyRNA *prop);
 void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *structname);
 void RNA_def_struct_flag(StructRNA *srna, int flag);
 void RNA_def_struct_clear_flag(StructRNA *srna, int flag);
+void RNA_def_struct_property_tags(StructRNA *srna, const EnumPropertyItem *prop_tag_defines);
 void RNA_def_struct_refine_func(StructRNA *srna, const char *refine);
 void RNA_def_struct_idprops_func(StructRNA *srna, const char *refine);
 void RNA_def_struct_register_funcs(StructRNA *srna, const char *reg, const char *unreg, const char *instance);
@@ -140,6 +141,7 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop, const char *structname,
 
 void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag);
 void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag);
+void RNA_def_property_tags(PropertyRNA *prop, int tags);
 void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype);
 void RNA_def_property_array(PropertyRNA *prop, int length);
 void RNA_def_property_multi_array(PropertyRNA *prop, int dimension, const int length[]);
index ff081a56b61afb8a65fd291ae41f8dab39983b01..e1d4e8fb8ad15ce4343a8ee7de08ff66a980166a 100644 (file)
@@ -3010,7 +3010,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
        else fprintf(f, "NULL,\n");
        fprintf(f, "\t%d, ", prop->magic);
        rna_print_c_string(f, prop->identifier);
-       fprintf(f, ", %d, %d, %d, ", prop->flag, prop->flag_parameter, prop->flag_internal);
+       fprintf(f, ", %d, %d, %d, %d, ", prop->flag, prop->flag_parameter, prop->flag_internal, prop->tags);
        rna_print_c_string(f, prop->name); fprintf(f, ",\n\t");
        rna_print_c_string(f, prop->description); fprintf(f, ",\n\t");
        fprintf(f, "%d, ", prop->icon);
@@ -3254,7 +3254,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
        fprintf(f, "\t");
        rna_print_c_string(f, srna->identifier);
        fprintf(f, ", NULL, NULL"); /* PyType - Cant initialize here */
-       fprintf(f, ", %d, ", srna->flag);
+       fprintf(f, ", %d, NULL, ", srna->flag);
        rna_print_c_string(f, srna->name);
        fprintf(f, ",\n\t");
        rna_print_c_string(f, srna->description);
index 14e0f6d45aae2f7e41613250093d804b17651ec9..7f5c57b1e2424089f88446e651a75877a8d4e257 100644 (file)
@@ -565,6 +565,11 @@ PropertyRNA *RNA_struct_name_property(StructRNA *type)
        return type->nameproperty;
 }
 
+const EnumPropertyItem *RNA_struct_property_tag_defines(const StructRNA *type)
+{
+       return type->prop_tag_defines;
+}
+
 PropertyRNA *RNA_struct_iterator_property(StructRNA *type)
 {
        return type->iteratorproperty;
@@ -930,6 +935,17 @@ int RNA_property_flag(PropertyRNA *prop)
        return rna_ensure_property(prop)->flag;
 }
 
+/**
+ * Get the tags set for \a prop as int bitfield.
+ * \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
+ *       in debug builds (to avoid performance issues in non-debug builds), which should be
+ *       the only way to set tags. Hence, at this point we assume the tag bitfield to be valid.
+ */
+int RNA_property_tags(PropertyRNA *prop)
+{
+       return rna_ensure_property(prop)->tags;
+}
+
 bool RNA_property_builtin(PropertyRNA *prop)
 {
        return (rna_ensure_property(prop)->flag_internal & PROP_INTERN_BUILTIN) != 0;
@@ -1596,6 +1612,18 @@ int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
        return -1;
 }
 
+unsigned int RNA_enum_items_count(const EnumPropertyItem *item)
+{
+       unsigned int i = 0;
+
+       while (item->identifier) {
+               item++;
+               i++;
+       }
+
+       return i;
+}
+
 bool RNA_property_enum_identifier(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value,
                                   const char **identifier)
 {
index fd511655c5fbfb72438929ad5592772b587b8b66..c8a6a503fd95fed906704bdd7b885408d395a3cc 100644 (file)
@@ -966,6 +966,11 @@ void RNA_def_struct_clear_flag(StructRNA *srna, int flag)
        srna->flag &= ~flag;
 }
 
+void RNA_def_struct_property_tags(StructRNA *srna, const EnumPropertyItem *prop_tag_defines)
+{
+       srna->prop_tag_defines = prop_tag_defines;
+}
+
 void RNA_def_struct_refine_func(StructRNA *srna, const char *refine)
 {
        if (!DefRNA.preprocess) {
@@ -1280,6 +1285,18 @@ void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag)
        prop->flag &= ~flag;
 }
 
+/**
+ * Add the property-tags passed as \a tags to \a prop (if valid).
+ *
+ * \note Multiple tags can be set by passing them within \a tags (using bitflags).
+ * \note Doesn't do any type-checking with the tags defined in the parent StructRNA
+ *       of \a prop. This should be done before (e.g. see #WM_operatortype_prop_tag).
+ */
+void RNA_def_property_tags(PropertyRNA *prop, int tags)
+{
+       prop->tags |= tags;
+}
+
 void RNA_def_parameter_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter)
 {
        prop->flag |= flag_property;
index 59f68cdf10630117bdf53929188cd0391c7a1c2d..d93f3308b2ad98bd2bcaaf25c6fcbebc5b384aba 100644 (file)
@@ -168,6 +168,8 @@ struct PropertyRNA {
        short flag_parameter;
        /* Internal ("private") flags. */
        short flag_internal;
+       /* The subset of StructRNA.prop_tag_defines values that applies to this property. */
+       short tags;
 
        /* user readable name */
        const char *name;
@@ -365,6 +367,9 @@ struct StructRNA {
 
        /* various options */
        int flag;
+       /* Each StructRNA type can define own tags which properties can set
+        * (PropertyRNA.tags) for changed behavior based on struct-type. */
+       const EnumPropertyItem *prop_tag_defines;
 
        /* user readable name */
        const char *name;
index 1d87bdb972eff60d2cf35de0435b0fd8aaa6f616..507262675b323535e70ea4b091a16dad6cb5bda4 100644 (file)
@@ -330,6 +330,16 @@ static PointerRNA rna_Struct_functions_get(CollectionPropertyIterator *iter)
        return rna_pointer_inherit_refine(&iter->parent, &RNA_Function, internal->link);
 }
 
+static void rna_Struct_property_tags_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+       /* here ptr->data should always be the same as iter->parent.type */
+       StructRNA *srna = (StructRNA *)ptr->data;
+       const EnumPropertyItem *tag_defines = RNA_struct_property_tag_defines(srna);
+       unsigned int tag_count = RNA_enum_items_count(tag_defines);
+
+       rna_iterator_array_begin(iter, (void *)tag_defines, sizeof(EnumPropertyItem), tag_count, 0, NULL);
+}
+
 /* Builtin properties iterator re-uses the Struct properties iterator, only
  * difference is that we need to set the ptr data to the type of the struct
  * whose properties we want to iterate over. */
@@ -603,6 +613,34 @@ static int rna_Property_is_library_editable_flag_get(PointerRNA *ptr)
        return (prop->flag & PROP_LIB_EXCEPTION) != 0;
 }
 
+static int rna_Property_tags_get(PointerRNA *ptr)
+{
+       return RNA_property_tags(ptr->data);
+}
+
+static const EnumPropertyItem *rna_Property_tags_itemf(
+        bContext *UNUSED(C), PointerRNA *ptr,
+        PropertyRNA *UNUSED(prop), bool *r_free)
+{
+       PropertyRNA *this_prop = (PropertyRNA *)ptr->data;
+       const StructRNA *srna = RNA_property_pointer_type(ptr, this_prop);
+       EnumPropertyItem *prop_tags;
+       EnumPropertyItem tmp = {0, "", 0, "", ""};
+       int totitem = 0;
+
+       for (const EnumPropertyItem *struct_tags = RNA_struct_property_tag_defines(srna);
+            struct_tags->identifier;
+            struct_tags++)
+       {
+               memcpy(&tmp, struct_tags, sizeof(tmp));
+               RNA_enum_item_add(&prop_tags, &totitem, &tmp);
+       }
+       RNA_enum_item_end(&prop_tags, &totitem);
+       *r_free = true;
+
+       return prop_tags;
+}
+
 static int rna_Property_array_length_get(PointerRNA *ptr)
 {
        PropertyRNA *prop = (PropertyRNA *)ptr->data;
@@ -1112,6 +1150,14 @@ static void rna_def_struct(BlenderRNA *brna)
                                          "rna_iterator_listbase_end", "rna_Struct_functions_get",
                                          NULL, NULL, NULL, NULL);
        RNA_def_property_ui_text(prop, "Functions", "");
+
+       prop = RNA_def_property(srna, "property_tags", PROP_COLLECTION, PROP_NONE);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_struct_type(prop, "EnumPropertyItem");
+       RNA_def_property_collection_funcs(prop, "rna_Struct_property_tags_begin", "rna_iterator_array_next",
+                                         "rna_iterator_array_end", "rna_iterator_array_get",
+                                         NULL, NULL, NULL, NULL);
+       RNA_def_property_ui_text(prop, "Property Tags", "Tags that properties can use to influence behavior");
 }
 
 static void rna_def_property(BlenderRNA *brna)
@@ -1142,6 +1188,9 @@ static void rna_def_property(BlenderRNA *brna)
                {PROP_LAYER_MEMBER, "LAYER_MEMBERSHIP", 0, "Layer Membership", ""},
                {0, NULL, 0, NULL, NULL}
        };
+       EnumPropertyItem dummy_prop_tags[] = {
+               {0, NULL, 0, NULL, NULL}
+       };
 
        srna = RNA_def_struct(brna, "Property", NULL);
        RNA_def_struct_ui_text(srna, "Property Definition", "RNA property definition");
@@ -1266,6 +1315,13 @@ static void rna_def_property(BlenderRNA *brna)
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
        RNA_def_property_boolean_funcs(prop, "rna_Property_is_library_editable_flag_get", NULL);
        RNA_def_property_ui_text(prop, "Library Editable", "Property is editable from linked instances (changes not saved)");
+
+       prop = RNA_def_property(srna, "tags", PROP_ENUM, PROP_NONE);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_enum_items(prop, dummy_prop_tags);
+       RNA_def_property_enum_funcs(prop, "rna_Property_tags_get", NULL, "rna_Property_tags_itemf");
+       RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
+       RNA_def_property_ui_text(prop, "Tags", "Subset of tags (defined in parent struct) that are set for this property");
 }
 
 static void rna_def_function(BlenderRNA *brna)
index e4e21587c79be5217f42cdea37aa58f5a6907cd6..abeaeb27d88ad9b63cae9cfdcc841d3e9313f782 100644 (file)
@@ -1858,7 +1858,22 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, PyObject *ge
                                                 #_func"(options={ ...}):")))     \
        {                                                                         \
                return NULL;                                                          \
-       } (void)0
+       }                                                                         \
+       {                                                                         \
+               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, _subtype)      \
        BPY_PROPDEF_CHECK(_func, _property_flag_items);                           \
@@ -1941,6 +1956,10 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, PyObject *ge
 "   :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \
 "   :type type: class\n" \
 
+#define BPY_PROPDEF_TAGS_DOC \
+"   :arg tags: Enumerator of tags that are defined by parent class.\n" \
+"   :type tags: set\n" \
+
 #if 0
 static int bpy_struct_id_used(StructRNA *srna, char *identifier)
 {
@@ -1959,6 +1978,7 @@ PyDoc_STRVAR(BPy_BoolProperty_doc,
                            "description=\"\", "
                            "default=False, "
                            "options={'ANIMATABLE'}, "
+                           "tags={}, "
                            "subtype='NONE', "
                            "update=None, "
                            "get=None, "
@@ -1969,6 +1989,7 @@ PyDoc_STRVAR(BPy_BoolProperty_doc,
 BPY_PROPDEF_NAME_DOC
 BPY_PROPDEF_DESC_DOC
 BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_TAGS_DOC
 BPY_PROPDEF_SUBTYPE_NUMBER_DOC
 BPY_PROPDEF_UPDATE_DOC
 BPY_PROPDEF_GET_DOC
@@ -1987,22 +2008,25 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
                PropertyRNA *prop;
                PyObject *pyopts = NULL;
                int opts = 0;
+               int prop_tags = 0;
                const char *pysubtype = NULL;
                int subtype = PROP_NONE;
                PyObject *update_cb = NULL;
                PyObject *get_cb = NULL;
                PyObject *set_cb = NULL;
+               PyObject *py_tags = NULL;
 
                static const char *_keywords[] = {
                        "attr", "name", "description", "default",
-                       "options", "subtype", "update", "get", "set", NULL,
+                       "options", "tags", "subtype",
+                       "update", "get", "set", NULL,
                };
-               static _PyArg_Parser _parser = {"s#|ssO&O!sOOO:BoolProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#|ssO&O!O!sOOO:BoolProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &name, &description, PyC_ParseBool, &def,
-                       &PySet_Type, &pyopts, &pysubtype,
+                       &PySet_Type, &pyopts, &PySet_Type, &py_tags, &pysubtype,
                        &update_cb, &get_cb, &set_cb))
                {
                        return NULL;
@@ -2024,6 +2048,9 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
                RNA_def_property_boolean_default(prop, def);
                RNA_def_property_ui_text(prop, name ? name : id, description);
 
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }
@@ -2040,6 +2067,7 @@ PyDoc_STRVAR(BPy_BoolVectorProperty_doc,
                                  "description=\"\", "
                                  "default=(False, False, False), "
                                  "options={'ANIMATABLE'}, "
+                                 "tags={}, "
                                  "subtype='NONE', "
                                  "size=3, "
                                  "update=None, "
@@ -2053,6 +2081,7 @@ BPY_PROPDEF_DESC_DOC
 "   :arg default: sequence of booleans the length of *size*.\n"
 "   :type default: sequence\n"
 BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_TAGS_DOC
 BPY_PROPDEF_SUBTYPE_ARRAY_DOC
 BPY_PROPDEF_VECSIZE_DOC
 BPY_PROPDEF_UPDATE_DOC
@@ -2074,22 +2103,26 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
                PyObject *pydef = NULL;
                PyObject *pyopts = NULL;
                int opts = 0;
+               int prop_tags = 0;
                const char *pysubtype = NULL;
                int subtype = PROP_NONE;
                PyObject *update_cb = NULL;
                PyObject *get_cb = NULL;
                PyObject *set_cb = NULL;
+               PyObject *py_tags = NULL;
 
                static const char *_keywords[] = {
                        "attr", "name", "description", "default",
-                       "options", "subtype", "size", "update", "get", "set", NULL,
+                       "options", "tags", "subtype", "size",
+                       "update", "get", "set", NULL,
                };
-               static _PyArg_Parser _parser = {"s#|ssOO!siOOO:BoolVectorProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#|ssOO!O!siOOO:BoolVectorProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &name, &description, &pydef,
-                       &PySet_Type, &pyopts, &pysubtype, &size,
+                       &PySet_Type, &pyopts, &PySet_Type, &py_tags,
+                       &pysubtype, &size,
                        &update_cb, &get_cb, &set_cb))
                {
                        return NULL;
@@ -2123,6 +2156,9 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
                if (pydef) RNA_def_property_boolean_array_default(prop, def);
                RNA_def_property_ui_text(prop, name ? name : id, description);
 
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }
@@ -2142,6 +2178,7 @@ PyDoc_STRVAR(BPy_IntProperty_doc,
                           "soft_min=-2**31, soft_max=2**31-1, "
                           "step=1, "
                           "options={'ANIMATABLE'}, "
+                          "tags={}, "
                           "subtype='NONE', "
                           "update=None, "
                           "get=None, "
@@ -2161,6 +2198,7 @@ BPY_PROPDEF_NUM_SOFTMIN_DOC
 "   :type soft_max: int\n"
 BPY_PROPDEF_INT_STEP_DOC
 BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_TAGS_DOC
 BPY_PROPDEF_SUBTYPE_NUMBER_DOC
 BPY_PROPDEF_UPDATE_DOC
 BPY_PROPDEF_GET_DOC
@@ -2179,24 +2217,27 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
                PropertyRNA *prop;
                PyObject *pyopts = NULL;
                int opts = 0;
+               int prop_tags = 0;
                const char *pysubtype = NULL;
                int subtype = PROP_NONE;
                PyObject *update_cb = NULL;
                PyObject *get_cb = NULL;
                PyObject *set_cb = NULL;
+               PyObject *py_tags = NULL;
 
                static const char *_keywords[] = {
                        "attr", "name", "description", "default",
                        "min", "max", "soft_min", "soft_max",
-                       "step", "options", "subtype", "update", "get", "set", NULL,
+                       "step", "options", "tags", "subtype",
+                       "update", "get", "set", NULL,
                };
-               static _PyArg_Parser _parser = {"s#|ssiiiiiiO!sOOO:IntProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#|ssiiiiiiO!O!sOOO:IntProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &name, &description, &def,
                        &min, &max, &soft_min, &soft_max,
-                       &step, &PySet_Type, &pyopts, &pysubtype,
+                       &step, &PySet_Type, &pyopts, &PySet_Type, &py_tags, &pysubtype,
                        &update_cb, &get_cb, &set_cb))
                {
                        return NULL;
@@ -2220,6 +2261,9 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
                RNA_def_property_range(prop, min, max);
                RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, 3);
 
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }
@@ -2238,6 +2282,7 @@ PyDoc_STRVAR(BPy_IntVectorProperty_doc,
                                 "soft_max=2**31-1, "
                                 "step=1, "
                                 "options={'ANIMATABLE'}, "
+                                "tags={}, "
                                 "subtype='NONE', "
                                 "size=3, "
                                 "update=None, "
@@ -2260,6 +2305,7 @@ BPY_PROPDEF_NUM_SOFTMAX_DOC
 "   :type soft_max: int\n"
 BPY_PROPDEF_INT_STEP_DOC
 BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_TAGS_DOC
 BPY_PROPDEF_SUBTYPE_ARRAY_DOC
 BPY_PROPDEF_VECSIZE_DOC
 BPY_PROPDEF_UPDATE_DOC
@@ -2282,24 +2328,27 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
                PyObject *pydef = NULL;
                PyObject *pyopts = NULL;
                int opts = 0;
+               int prop_tags = 0;
                const char *pysubtype = NULL;
                int subtype = PROP_NONE;
                PyObject *update_cb = NULL;
                PyObject *get_cb = NULL;
                PyObject *set_cb = NULL;
+               PyObject *py_tags = NULL;
 
                static const char *_keywords[] = {
                        "attr", "name", "description", "default",
                        "min", "max", "soft_min", "soft_max",
-                       "step", "options", "subtype", "size", "update", "get", "set", NULL,
+                       "step", "options", "tags", "subtype", "size",
+                       "update", "get", "set", NULL,
                };
-               static _PyArg_Parser _parser = {"s#|ssOiiiiiO!siOOO:IntVectorProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#|ssOiiiiiO!O!siOOO:IntVectorProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &name, &description, &pydef,
                        &min, &max, &soft_min, &soft_max,
-                       &step, &PySet_Type, &pyopts,
+                       &step, &PySet_Type, &pyopts, &PySet_Type, &py_tags,
                        &pysubtype, &size,
                        &update_cb, &get_cb, &set_cb))
                {
@@ -2335,6 +2384,9 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
                RNA_def_property_ui_text(prop, name ? name : id, description);
                RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, 3);
 
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }
@@ -2355,6 +2407,7 @@ PyDoc_STRVAR(BPy_FloatProperty_doc,
                             "step=3, "
                             "precision=2, "
                             "options={'ANIMATABLE'}, "
+                            "tags={}, "
                             "subtype='NONE', "
                             "unit='NONE', "
                             "update=None, "
@@ -2376,6 +2429,7 @@ BPY_PROPDEF_NUM_SOFTMAX_DOC
 BPY_PROPDEF_FLOAT_STEP_DOC
 BPY_PROPDEF_FLOAT_PREC_DOC
 BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_TAGS_DOC
 BPY_PROPDEF_SUBTYPE_NUMBER_DOC
 BPY_PROPDEF_UNIT_DOC
 BPY_PROPDEF_UPDATE_DOC
@@ -2396,6 +2450,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
                PropertyRNA *prop;
                PyObject *pyopts = NULL;
                int opts = 0;
+               int prop_tags = 0;
                const char *pysubtype = NULL;
                int subtype = PROP_NONE;
                const char *pyunit = NULL;
@@ -2403,21 +2458,22 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
                PyObject *update_cb = NULL;
                PyObject *get_cb = NULL;
                PyObject *set_cb = NULL;
+               PyObject *py_tags = NULL;
 
                static const char *_keywords[] = {
                        "attr", "name", "description", "default",
                        "min", "max", "soft_min", "soft_max",
-                       "step", "precision", "options", "subtype",
+                       "step", "precision", "options", "tags", "subtype",
                        "unit", "update", "get", "set", NULL,
                };
-               static _PyArg_Parser _parser = {"s#|ssffffffiO!ssOOO:FloatProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#|ssffffffiO!O!ssOOO:FloatProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &name, &description, &def,
                        &min, &max, &soft_min, &soft_max,
                        &step, &precision, &PySet_Type,
-                       &pyopts, &pysubtype, &pyunit,
+                       &pyopts, &PySet_Type, &py_tags, &pysubtype, &pyunit,
                        &update_cb, &get_cb, &set_cb))
                {
                        return NULL;
@@ -2446,6 +2502,9 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
                RNA_def_property_ui_text(prop, name ? name : id, description);
                RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, precision);
 
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }
@@ -2465,6 +2524,7 @@ PyDoc_STRVAR(BPy_FloatVectorProperty_doc,
                                   "step=3, "
                                   "precision=2, "
                                   "options={'ANIMATABLE'}, "
+                                  "tags={}, "
                                   "subtype='NONE', "
                                   "unit='NONE', "
                                   "size=3, "
@@ -2487,6 +2547,7 @@ BPY_PROPDEF_NUM_SOFTMIN_DOC
 BPY_PROPDEF_NUM_SOFTMAX_DOC
 "   :type soft_max: float\n"
 BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_TAGS_DOC
 BPY_PROPDEF_FLOAT_STEP_DOC
 BPY_PROPDEF_FLOAT_PREC_DOC
 BPY_PROPDEF_SUBTYPE_ARRAY_DOC
@@ -2512,6 +2573,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
                PyObject *pydef = NULL;
                PyObject *pyopts = NULL;
                int opts = 0;
+               int prop_tags = 0;
                const char *pysubtype = NULL;
                int subtype = PROP_NONE;
                const char *pyunit = NULL;
@@ -2519,21 +2581,22 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
                PyObject *update_cb = NULL;
                PyObject *get_cb = NULL;
                PyObject *set_cb = NULL;
+               PyObject *py_tags = NULL;
 
                static const char *_keywords[] = {
                        "attr", "name", "description", "default",
                        "min", "max", "soft_min", "soft_max",
-                       "step", "precision", "options", "subtype",
+                       "step", "precision", "options", "tags", "subtype",
                        "unit", "size", "update", "get", "set", NULL,
                };
-               static _PyArg_Parser _parser = {"s#|ssOfffffiO!ssiOOO:FloatVectorProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#|ssOfffffiO!O!ssiOOO:FloatVectorProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &name, &description, &pydef,
                        &min, &max, &soft_min, &soft_max,
                        &step, &precision, &PySet_Type,
-                       &pyopts, &pysubtype, &pyunit, &size,
+                       &pyopts, &PySet_Type, &py_tags, &pysubtype, &pyunit, &size,
                        &update_cb, &get_cb, &set_cb))
                {
                        return NULL;
@@ -2573,6 +2636,9 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
                RNA_def_property_ui_text(prop, name ? name : id, description);
                RNA_def_property_ui_range(prop, MAX2(soft_min, min), MIN2(soft_max, max), step, precision);
 
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }
@@ -2589,6 +2655,7 @@ PyDoc_STRVAR(BPy_StringProperty_doc,
                              "default=\"\", "
                              "maxlen=0, "
                              "options={'ANIMATABLE'}, "
+                             "tags={}, "
                              "subtype='NONE', "
                              "update=None, "
                              "get=None, "
@@ -2603,6 +2670,7 @@ BPY_PROPDEF_DESC_DOC
 "   :arg maxlen: maximum length of the string.\n"
 "   :type maxlen: int\n"
 BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_TAGS_DOC
 BPY_PROPDEF_SUBTYPE_STRING_DOC
 BPY_PROPDEF_UPDATE_DOC
 BPY_PROPDEF_GET_DOC
@@ -2621,22 +2689,25 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
                PropertyRNA *prop;
                PyObject *pyopts = NULL;
                int opts = 0;
+               int prop_tags = 0;
                const char *pysubtype = NULL;
                int subtype = PROP_NONE;
                PyObject *update_cb = NULL;
                PyObject *get_cb = NULL;
                PyObject *set_cb = NULL;
+               PyObject *py_tags = NULL;
 
                static const char *_keywords[] = {
                        "attr", "name", "description", "default",
-                       "maxlen", "options", "subtype", "update", "get", "set", NULL,
+                       "maxlen", "options", "tags", "subtype",
+                       "update", "get", "set", NULL,
                };
-               static _PyArg_Parser _parser = {"s#|sssiO!sOOO:StringProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#|sssiO!O!sOOO:StringProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &name, &description, &def,
-                       &maxlen, &PySet_Type, &pyopts, &pysubtype,
+                       &maxlen, &PySet_Type, &pyopts, &PySet_Type, &py_tags, &pysubtype,
                        &update_cb, &get_cb, &set_cb))
                {
                        return NULL;
@@ -2659,6 +2730,9 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
                if (def && def[0]) RNA_def_property_string_default(prop, def);
                RNA_def_property_ui_text(prop, name ? name : id, description);
 
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }
@@ -2675,6 +2749,7 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
                            "description=\"\", "
                            "default=None, "
                            "options={'ANIMATABLE'}, "
+                           "tags={}, "
                            "update=None, "
                            "get=None, "
                            "set=None)\n"
@@ -2716,6 +2791,7 @@ BPY_PROPDEF_DESC_DOC
 "      (i.e. if a callback function is given as *items* parameter).\n"
 "   :type default: string or set\n"
 BPY_PROPDEF_OPTIONS_ENUM_DOC
+BPY_PROPDEF_TAGS_DOC
 BPY_PROPDEF_UPDATE_DOC
 BPY_PROPDEF_GET_DOC
 BPY_PROPDEF_SET_DOC
@@ -2736,21 +2812,23 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
                PropertyRNA *prop;
                PyObject *pyopts = NULL;
                int opts = 0;
+               int prop_tags = 0;
                bool is_itemf = false;
                PyObject *update_cb = NULL;
                PyObject *get_cb = NULL;
                PyObject *set_cb = NULL;
+               PyObject *py_tags = NULL;
 
                static const char *_keywords[] = {
                        "attr", "items", "name", "description", "default",
-                       "options", "update", "get", "set", NULL,
+                       "options", "tags", "update", "get", "set", NULL,
                };
-               static _PyArg_Parser _parser = {"s#O|ssOO!OOO:EnumProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#O|ssOO!O!OOO:EnumProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &items, &name, &description,
-                       &def, &PySet_Type, &pyopts,
+                       &def, &PySet_Type, &pyopts, &PySet_Type, &py_tags,
                        &update_cb, &get_cb, &set_cb))
                {
                        return NULL;
@@ -2813,6 +2891,9 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
                if (opts & PROP_ENUM_FLAG)  prop = RNA_def_enum_flag(srna, id, eitems, defvalue, name ? name : id, description);
                else                        prop = RNA_def_enum(srna, id, eitems, defvalue, name ? name : id, description);
 
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }
@@ -2861,6 +2942,7 @@ PyDoc_STRVAR(BPy_PointerProperty_doc,
                               "name=\"\", "
                               "description=\"\", "
                               "options={'ANIMATABLE'}, "
+                              "tags={}, "
                               "poll=None, "
                               "update=None)\n"
 "\n"
@@ -2870,6 +2952,7 @@ BPY_PROPDEF_TYPE_DOC
 BPY_PROPDEF_NAME_DOC
 BPY_PROPDEF_DESC_DOC
 BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_TAGS_DOC
 BPY_PROPDEF_POLL_DOC
 BPY_PROPDEF_UPDATE_DOC
 );
@@ -2886,18 +2969,21 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
                StructRNA *ptype;
                PyObject *type = Py_None;
                PyObject *pyopts = NULL;
+               PyObject *py_tags = NULL;
                int opts = 0;
+               int prop_tags = 0;
                PyObject *update_cb = NULL, *poll_cb = NULL;
 
                static const char *_keywords[] = {
-                       "attr", "type", "name", "description", "options", "poll", "update", NULL,
+                       "attr", "type", "name", "description", "options",
+                       "tags", "poll", "update", NULL,
                };
-               static _PyArg_Parser _parser = {"s#O|ssO!OO:PointerProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#O|ssO!O!OO:PointerProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &type, &name, &description,
-                       &PySet_Type, &pyopts,
+                       &PySet_Type, &pyopts, &PySet_Type, &py_tags,
                        &poll_cb, &update_cb))
                {
                        return NULL;
@@ -2921,6 +3007,9 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
                        return NULL;
                }
                prop = RNA_def_pointer_runtime(srna, id, ptype, name ? name : id, description);
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }
@@ -2941,7 +3030,8 @@ PyDoc_STRVAR(BPy_CollectionProperty_doc,
 ".. function:: CollectionProperty(type=None, "
                                  "name=\"\", "
                                  "description=\"\", "
-                                 "options={'ANIMATABLE'})\n"
+                                 "options={'ANIMATABLE'}, "
+                                 "tags={})\n"
 "\n"
 "   Returns a new collection property definition.\n"
 "\n"
@@ -2949,6 +3039,7 @@ BPY_PROPDEF_TYPE_DOC
 BPY_PROPDEF_NAME_DOC
 BPY_PROPDEF_DESC_DOC
 BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_TAGS_DOC
 );
 PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
 {
@@ -2963,17 +3054,20 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
                StructRNA *ptype;
                PyObject *type = Py_None;
                PyObject *pyopts = NULL;
+               PyObject *py_tags = NULL;
                int opts = 0;
+               int prop_tags = 0;
 
                static const char *_keywords[] = {
-                       "attr", "type", "name", "description", "options", NULL,
+                       "attr", "type", "name", "description",
+                       "options", "tags", NULL,
                };
-               static _PyArg_Parser _parser = {"s#O|ssO!:CollectionProperty", _keywords, 0};
+               static _PyArg_Parser _parser = {"s#O|ssO!O!:CollectionProperty", _keywords, 0};
                if (!_PyArg_ParseTupleAndKeywordsFast(
                        args, kw, &_parser,
                        &id, &id_len,
                        &type, &name, &description,
-                       &PySet_Type, &pyopts))
+                       &PySet_Type, &pyopts, &PySet_Type, &py_tags))
                {
                        return NULL;
                }
@@ -2992,6 +3086,9 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
                }
 
                prop = RNA_def_collection_runtime(srna, id, ptype, name ? name : id, description);
+               if (py_tags) {
+                       RNA_def_property_tags(prop, prop_tags);
+               }
                if (pyopts) {
                        bpy_prop_assign_flag(prop, opts);
                }