bl_rna_defaults.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. # Apache License, Version 2.0
  2. # ./blender.bin --background -noaudio --factory-startup --python tests/python/bl_rna_defaults.py
  3. import bpy
  4. DUMMY_NAME = "Untitled"
  5. DUMMY_PATH = __file__
  6. GLOBALS = {
  7. "error_num": 0,
  8. }
  9. def as_float_32(f):
  10. from struct import pack, unpack
  11. return unpack("f", pack("f", f))[0]
  12. def repr_float_precision(f, round_fn):
  13. """
  14. Get's the value which was most likely entered by a human in C.
  15. Needed since Python will show trailing precision from a 32bit float.
  16. """
  17. f_round = round_fn(f)
  18. f_str = repr(f)
  19. f_str_frac = f_str.partition(".")[2]
  20. if not f_str_frac:
  21. return f_str
  22. for i in range(1, len(f_str_frac)):
  23. f_test = round(f, i)
  24. f_test_round = round_fn(f_test)
  25. if f_test_round == f_round:
  26. return "%.*f" % (i, f_test)
  27. return f_str
  28. def repr_float_32(f):
  29. return repr_float_precision(f, as_float_32)
  30. def validate_defaults(test_id, o):
  31. def warning(prop_id, val_real, val_default, *, repr_fn=repr):
  32. print("Error %s: '%s.%s' is:%s, expected:%s" %
  33. (test_id, o.__class__.__name__, prop_id,
  34. repr_fn(val_real), repr_fn(val_default)))
  35. GLOBALS["error_num"] += 1
  36. properties = type(o).bl_rna.properties.items()
  37. for prop_id, prop in properties:
  38. if prop_id == "rna_type":
  39. continue
  40. prop_type = prop.type
  41. if prop_type in {'STRING', 'COLLECTION'}:
  42. continue
  43. if prop_type == 'POINTER':
  44. # traverse down pointers if they're set
  45. val_real = getattr(o, prop_id)
  46. if (val_real is not None) and (not isinstance(val_real, bpy.types.ID)):
  47. validate_defaults("%s.%s" % (test_id, prop_id), val_real)
  48. elif prop_type in {'INT', 'BOOL'}:
  49. # array_length = prop.array_length
  50. if not prop.is_array:
  51. val_real = getattr(o, prop_id)
  52. val_default = prop.default
  53. if val_real != val_default:
  54. warning(prop_id, val_real, val_default)
  55. else:
  56. pass # TODO, array defaults
  57. elif prop_type == 'FLOAT':
  58. # array_length = prop.array_length
  59. if not prop.is_array:
  60. val_real = getattr(o, prop_id)
  61. val_default = prop.default
  62. if val_real != val_default:
  63. warning(prop_id, val_real, val_default, repr_fn=repr_float_32)
  64. else:
  65. pass # TODO, array defaults
  66. elif prop_type == 'ENUM':
  67. val_real = getattr(o, prop_id)
  68. if prop.is_enum_flag:
  69. val_default = prop.default_flag
  70. else:
  71. val_default = prop.default
  72. if val_real != val_default:
  73. warning(prop_id, val_real, val_default)
  74. # print(prop_id, prop_type)
  75. def _test_id_gen(data_attr, args_create=(DUMMY_NAME,), create_method="new"):
  76. def test_gen(test_id):
  77. id_collection = getattr(bpy.data, data_attr)
  78. create_fn = getattr(id_collection, create_method)
  79. o = create_fn(*args_create)
  80. o.user_clear()
  81. validate_defaults(test_id, o)
  82. id_collection.remove(o)
  83. return test_gen
  84. test_Action = _test_id_gen("actions")
  85. test_Armature = _test_id_gen("armatures")
  86. test_Camera = _test_id_gen("cameras")
  87. test_Group = _test_id_gen("groups")
  88. test_Lattice = _test_id_gen("lattices")
  89. test_LineStyle = _test_id_gen("linestyles")
  90. test_Mask = _test_id_gen("masks")
  91. test_Material = _test_id_gen("materials")
  92. test_Mesh = _test_id_gen("meshes")
  93. test_MetaBall = _test_id_gen("metaballs")
  94. test_MovieClip = _test_id_gen("movieclips", args_create=(DUMMY_PATH,), create_method="load")
  95. test_Object = _test_id_gen("objects", args_create=(DUMMY_NAME, None))
  96. test_Palette = _test_id_gen("palettes")
  97. test_Particle = _test_id_gen("particles")
  98. test_Scene = _test_id_gen("scenes")
  99. test_Sound = _test_id_gen("sounds", args_create=(DUMMY_PATH,), create_method="load")
  100. test_Speaker = _test_id_gen("speakers")
  101. test_Text = _test_id_gen("texts")
  102. test_VectorFont = _test_id_gen("fonts", args_create=("<builtin>",), create_method="load")
  103. test_World = _test_id_gen("worlds")
  104. ns = globals()
  105. for t in bpy.data.curves.bl_rna.functions["new"].parameters["type"].enum_items.keys():
  106. ns["test_Curve_%s" % t] = _test_id_gen("curves", args_create=(DUMMY_NAME, t))
  107. for t in bpy.data.lights.bl_rna.functions["new"].parameters["type"].enum_items.keys():
  108. ns["test_Light_%s" % t] = _test_id_gen("lights", args_create=(DUMMY_NAME, t))
  109. # types are a dynamic enum, have to hard-code.
  110. for t in "ShaderNodeTree", "CompositorNodeTree", "TextureNodeTree":
  111. ns["test_NodeGroup_%s" % t] = _test_id_gen("node_groups", args_create=(DUMMY_NAME, t))
  112. for t in bpy.data.textures.bl_rna.functions["new"].parameters["type"].enum_items.keys():
  113. ns["test_Texture_%s" % t] = _test_id_gen("textures", args_create=(DUMMY_NAME, t))
  114. del ns
  115. def main():
  116. for fn_id, fn_val in sorted(globals().items()):
  117. if fn_id.startswith("test_") and callable(fn_val):
  118. fn_val(fn_id)
  119. print("Error (total): %d" % GLOBALS["error_num"])
  120. if __name__ == "__main__":
  121. main()