[Bf-blender-cvs] [1c6b66c9cf8] master: PyDoc: replace in-lined enum references with links where possible

Campbell Barton noreply at git.blender.org
Tue May 31 06:19:38 CEST 2022


Commit: 1c6b66c9cf80b3c9b4542b27948ae232f930a211
Author: Campbell Barton
Date:   Tue May 31 14:07:14 2022 +1000
Branches: master
https://developer.blender.org/rB1c6b66c9cf80b3c9b4542b27948ae232f930a211

PyDoc: replace in-lined enum references with links where possible

Avoid in-lining large enums such as icons and event types, linking
to them instead.

This mitigates T76453, where long enums took a lot of space in the docs,
this was a problem with `UILayout` where each icon argument would list
all icons. [0] worked around the issue using CSS to scroll the list.
However this has the draw-back where some items are clipped in a way
that's not obvious, see: T87008.

The reason this isn't a complete solution is that Python defined enums
aren't written into their own pages which can be linked to, although
currently there are no large Python enums included in the API docs.
All in-lined enums are now under 20 items.

[0]: 1e8f2665916c049748a3985a2fce736701925095

===================================================================

M	doc/python_api/sphinx_doc_gen.py
M	release/scripts/modules/rna_info.py

===================================================================

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



More information about the Bf-blender-cvs mailing list