diff options
-rw-r--r-- | doc/python_api/sphinx_doc_gen.py | 72 | ||||
-rw-r--r-- | release/scripts/modules/rna_info.py | 36 |
2 files changed, 97 insertions, 11 deletions
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index ebaea669679..0d514e0694d 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -89,6 +89,16 @@ if USE_SHARED_RNA_ENUM_ITEMS_STATIC: del rna_enum_dict[key] del key, rna_enum_items_static + # Build enum `{pointer: identifier}` map, so any enum property pointer can + # lookup an identifier using `InfoPropertyRNA.enum_pointer` as the key. + rna_enum_pointer_to_id_map = { + enum_prop.as_pointer(): key + for key, enum_items in rna_enum_dict.items() + # It's possible the first item is a heading (which has no identifier). + # skip these as the `EnumProperty.enum_items` does not expose them. + if (enum_prop := next(iter(enum_prop for enum_prop in enum_items if enum_prop.identifier), None)) + } + def handle_args(): """ @@ -1231,15 +1241,23 @@ def pycontext2sphinx(basepath): # No need to check if there are duplicates yet as it's known there wont be. unique.add(prop.identifier) + enum_descr_override = None + if USE_SHARED_RNA_ENUM_ITEMS_STATIC: + enum_descr_override = pyrna_enum2sphinx_shared_link(prop) + type_descr = prop.get_type_description( - class_fmt=":class:`bpy.types.%s`", collection_id=_BPY_PROP_COLLECTION_ID) + class_fmt=":class:`bpy.types.%s`", + collection_id=_BPY_PROP_COLLECTION_ID, + enum_descr_override=enum_descr_override, + ) fw(".. data:: %s\n\n" % prop.identifier) if prop.description: fw(" %s\n\n" % prop.description) # Special exception, can't use generic code here for enums. if prop.type == "enum": - enum_text = pyrna_enum2sphinx(prop) + # If the link has been written, no need to inline the enum items. + enum_text = "" if enum_descr_override else pyrna_enum2sphinx(prop) if enum_text: write_indented_lines(" ", fw, enum_text) fw("\n") @@ -1301,6 +1319,11 @@ def pyrna_enum2sphinx(prop, use_empty_descriptions=False): Write a bullet point list of enum + descriptions. """ + # Write a link to the enum if this is part of `rna_enum_pointer_map`. + if USE_SHARED_RNA_ENUM_ITEMS_STATIC: + if (result := pyrna_enum2sphinx_shared_link(prop)) is not None: + return result + if use_empty_descriptions: ok = True else: @@ -1379,10 +1402,15 @@ def pyrna2sphinx(basepath): kwargs["collection_id"] = _BPY_PROP_COLLECTION_ID - type_descr = prop.get_type_description(**kwargs) + enum_descr_override = None + if USE_SHARED_RNA_ENUM_ITEMS_STATIC: + enum_descr_override = pyrna_enum2sphinx_shared_link(prop) + kwargs["enum_descr_override"] = enum_descr_override - enum_text = pyrna_enum2sphinx(prop) + type_descr = prop.get_type_description(**kwargs) + # If the link has been written, no need to inline the enum items. + enum_text = "" if enum_descr_override else pyrna_enum2sphinx(prop) if prop.name or prop.description or enum_text: fw(ident + ":%s%s:\n\n" % (id_name, identifier)) @@ -1483,7 +1511,15 @@ def pyrna2sphinx(basepath): if identifier in struct_blacklist: continue - type_descr = prop.get_type_description(class_fmt=":class:`%s`", collection_id=_BPY_PROP_COLLECTION_ID) + enum_descr_override = None + if USE_SHARED_RNA_ENUM_ITEMS_STATIC: + enum_descr_override = pyrna_enum2sphinx_shared_link(prop) + + type_descr = prop.get_type_description( + class_fmt=":class:`%s`", + collection_id=_BPY_PROP_COLLECTION_ID, + enum_descr_override=enum_descr_override, + ) # Read-only properties use "data" directive, variables properties use "attribute" directive. if "readonly" in type_descr: fw(" .. data:: %s\n" % identifier) @@ -1500,7 +1536,8 @@ def pyrna2sphinx(basepath): # Special exception, can't use generic code here for enums. if prop.type == "enum": - enum_text = pyrna_enum2sphinx(prop) + # If the link has been written, no need to inline the enum items. + enum_text = "" if enum_descr_override else pyrna_enum2sphinx(prop) if enum_text: write_indented_lines(" ", fw, enum_text) fw("\n") @@ -1539,8 +1576,16 @@ def pyrna2sphinx(basepath): for prop in func.return_values: # TODO: pyrna_enum2sphinx for multiple return values... actually don't # think we even use this but still! + + enum_descr_override = None + if USE_SHARED_RNA_ENUM_ITEMS_STATIC: + enum_descr_override = pyrna_enum2sphinx_shared_link(prop) + type_descr = prop.get_type_description( - as_ret=True, class_fmt=":class:`%s`", collection_id=_BPY_PROP_COLLECTION_ID) + as_ret=True, class_fmt=":class:`%s`", + collection_id=_BPY_PROP_COLLECTION_ID, + enum_descr_override=enum_descr_override, + ) descr = prop.description if not descr: descr = prop.name @@ -2067,6 +2112,19 @@ def write_rst_data(basepath): EXAMPLE_SET_USED.add("bpy.data") +def pyrna_enum2sphinx_shared_link(prop): + """ + Return a reference to the enum used by ``prop`` or None when not found. + """ + if ( + (prop.type == "enum") and + (pointer := prop.enum_pointer) and + (identifier := rna_enum_pointer_to_id_map.get(pointer)) + ): + return ":ref:`%s`" % identifier + return None + + def write_rst_enum_items(basepath, key, key_no_prefix, enum_items): """ Write a single page for a static enum in RST. diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py index 04120508df5..4788ed6a5fa 100644 --- a/release/scripts/modules/rna_info.py +++ b/release/scripts/modules/rna_info.py @@ -242,6 +242,7 @@ class InfoPropertyRNA: "default_str", "default", "enum_items", + "enum_pointer", "min", "max", "array_length", @@ -285,9 +286,17 @@ class InfoPropertyRNA: else: self.fixed_type = None + self.enum_pointer = 0 if self.type == "enum": - self.enum_items[:] = [(item.identifier, item.name, item.description) for item in rna_prop.enum_items] + items = tuple(rna_prop.enum_items) + items_static = tuple(rna_prop.enum_items_static) + self.enum_items[:] = [(item.identifier, item.name, item.description) for item in items] self.is_enum_flag = rna_prop.is_enum_flag + # Prioritize static items as this is never going to be allocated data and is therefor + # will be a stable match to compare against. + item = (items_static or items) + if item: + self.enum_pointer = item[0].as_pointer() else: self.is_enum_flag = False @@ -342,7 +351,19 @@ class InfoPropertyRNA: return "%s=%s" % (self.identifier, default) return self.identifier - def get_type_description(self, as_ret=False, as_arg=False, class_fmt="%s", collection_id="Collection"): + def get_type_description( + self, *, + as_ret=False, + as_arg=False, + class_fmt="%s", + collection_id="Collection", + enum_descr_override=None, + ): + """ + :arg enum_descr_override: Optionally override items for enum. + Otherwise expand the literal items. + :type enum_descr_override: string or None when unset. + """ type_str = "" if self.fixed_type is None: type_str += self.type @@ -357,10 +378,17 @@ class InfoPropertyRNA: if self.type in {"float", "int"}: type_str += " in [%s, %s]" % (range_str(self.min), range_str(self.max)) elif self.type == "enum": + enum_descr = enum_descr_override + if not enum_descr: + if self.is_enum_flag: + enum_descr = "{%s}" % ", ".join(("'%s'" % s[0]) for s in self.enum_items) + else: + enum_descr = "[%s]" % ", ".join(("'%s'" % s[0]) for s in self.enum_items) if self.is_enum_flag: - type_str += " set in {%s}" % ", ".join(("'%s'" % s[0]) for s in self.enum_items) + type_str += " set in %s" % enum_descr else: - type_str += " in [%s]" % ", ".join(("'%s'" % s[0]) for s in self.enum_items) + type_str += " in %s" % enum_descr + del enum_descr if not (as_arg or as_ret): # write default property, ignore function args for this |