Tests: Add simple script accessing (almost) all RNA properties.
Only runs on factory startup file, so not all possible paths are covered. But should reduce likeliness of issues like #133551 in the future.
This commit is contained in:
@@ -257,6 +257,11 @@ add_blender_test(
|
||||
--python ${CMAKE_CURRENT_LIST_DIR}/bl_rna_paths.py
|
||||
)
|
||||
|
||||
add_blender_test(
|
||||
bl_rna_accessors
|
||||
--python ${CMAKE_CURRENT_LIST_DIR}/bl_rna_accessors.py
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# BLEND IO & LINKING
|
||||
|
||||
|
||||
82
tests/python/bl_rna_accessors.py
Normal file
82
tests/python/bl_rna_accessors.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
"""
|
||||
Simple test looping over (most of) all RNA API and checking that data can be accessed.
|
||||
|
||||
Note that not all RNA is covered, this focuses mainly on data accessible from `bpy.data`.
|
||||
"""
|
||||
|
||||
import bpy
|
||||
import unittest
|
||||
|
||||
|
||||
# Walk over all exposed RNA properties in factory startup file, and access them.
|
||||
class TestRnaProperties(unittest.TestCase):
|
||||
def process_rna_struct(self, struct, rna_path):
|
||||
# These paths are problematic to process, skip for the time being.
|
||||
SKIP_PROPERTIES = {
|
||||
bpy.types.Depsgraph.bl_rna.properties["object_instances"],
|
||||
# XXX To be removed once #133551 is fixed.
|
||||
bpy.types.ToolSettings.bl_rna.properties["uv_sculpt"],
|
||||
}
|
||||
|
||||
if repr(struct) in self.processed_data:
|
||||
return
|
||||
self.processed_data.add(repr(struct))
|
||||
|
||||
def generate_rna_path(struct, rna_path_root, p, p_data, p_keys_str=[]):
|
||||
if not p_data:
|
||||
return None
|
||||
rna_path_references = [rna_path_root + "." + p.identifier if rna_path_root else p.identifier]
|
||||
if p_keys_str:
|
||||
rna_path_reference = rna_path_references[0]
|
||||
rna_path_references = [rna_path_reference + '[' + p_key + ']' for p_key in p_keys_str if p_key]
|
||||
return rna_path_references[0]
|
||||
|
||||
def process_pointer_property(self, struct, rna_path, p, p_data, p_keys_str=[]):
|
||||
rna_path_sub = generate_rna_path(struct, rna_path, p, p_data, p_keys_str)
|
||||
if p.identifier in {"bl_rna", "rna_type"}:
|
||||
return
|
||||
if isinstance(p_data, bpy.types.ID) and not p_data.is_embedded_data:
|
||||
return
|
||||
if rna_path_sub is None:
|
||||
return
|
||||
self.process_rna_struct(p_data, rna_path_sub)
|
||||
|
||||
for p in struct.bl_rna.properties:
|
||||
if p in SKIP_PROPERTIES:
|
||||
continue
|
||||
if p.type == 'COLLECTION':
|
||||
try:
|
||||
iter_data = getattr(struct, p.identifier)
|
||||
except:
|
||||
self.assertTrue(False, msg=f"Failed to retrieve {rna_path}.{p.identifier} collection")
|
||||
for p_idx, (p_key, p_data) in enumerate(iter_data.items()):
|
||||
p_keys_str = ['"' + p_key + '"', str(p_idx)] if isinstance(p_key, str) else [str(p_key), str(p_idx)]
|
||||
process_pointer_property(self, struct, rna_path, p, p_data, p_keys_str)
|
||||
elif p.type == 'POINTER':
|
||||
try:
|
||||
p_data = getattr(struct, p.identifier)
|
||||
except:
|
||||
self.assertTrue(False, msg=f"Failed to retrieve {rna_path}.{p.identifier} pointer")
|
||||
process_pointer_property(self, struct, rna_path, p, p_data)
|
||||
else:
|
||||
try:
|
||||
p_data = getattr(struct, p.identifier)
|
||||
except:
|
||||
self.assertTrue(False, msg=f"Failed to retrieve {rna_path}.{p.identifier} value")
|
||||
|
||||
def test_paths_generation(self):
|
||||
bpy.ops.wm.read_factory_settings()
|
||||
self.processed_data = set()
|
||||
for data_block in bpy.data.user_map().keys():
|
||||
self.process_rna_struct(data_block, "")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user