bl_pyapi_idprop.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. # Apache License, Version 2.0
  2. # ./blender.bin --background -noaudio --python tests/python/bl_pyapi_idprop.py -- --verbose
  3. import bpy
  4. import unittest
  5. import numpy as np
  6. from array import array
  7. class TestHelper:
  8. @property
  9. def id(self):
  10. return self._id
  11. def setUp(self):
  12. self._id = bpy.context.scene
  13. assert(len(self._id.keys()) == 0 or self._id.keys() == ["cycles"])
  14. def tearDown(self):
  15. for key in list(self._id.keys()):
  16. if key != "cycles":
  17. del self._id[key]
  18. def assertAlmostEqualSeq(self, list1, list2):
  19. self.assertEqual(len(list1), len(list2))
  20. for v1, v2 in zip(list1, list2):
  21. self.assertAlmostEqual(v1, v2, places=5)
  22. class TestIdPropertyCreation(TestHelper, unittest.TestCase):
  23. def test_name_empty(self):
  24. self.id[""] = 4
  25. self.assertEqual(self.id[""], 4)
  26. def test_name_too_long(self):
  27. with self.assertRaises(KeyError):
  28. self.id["name" * 30] = 4
  29. def test_int(self):
  30. self.id["a"] = 2
  31. self.assertEqual(self.id["a"], 2)
  32. self.assertTrue(isinstance(self.id["a"], int))
  33. with self.assertRaises(OverflowError):
  34. self.id["a"] = 2 ** 31 # integer <= 2 ** 31-1
  35. def test_double(self):
  36. self.id["a"] = 2.5
  37. self.assertEqual(self.id["a"], 2.5)
  38. self.assertTrue(isinstance(self.id["a"], float))
  39. def test_unicode(self):
  40. self.id["a"] = "Hello World"
  41. self.assertEqual(self.id["a"], "Hello World")
  42. self.assertTrue(isinstance(self.id["a"], str))
  43. def test_bytes(self):
  44. self.id["a"] = b"Hello World"
  45. self.assertEqual(self.id["a"], b"Hello World")
  46. self.assertTrue(isinstance(self.id["a"], bytes))
  47. def test_sequence_double_list(self):
  48. mylist = [1.2, 3.4, 5.6]
  49. self.id["a"] = mylist
  50. self.assertEqual(self.id["a"].to_list(), mylist)
  51. self.assertEqual(self.id["a"].typecode, "d")
  52. def test_sequence_int_list(self):
  53. mylist = [1, 2, 3]
  54. self.id["a"] = mylist
  55. self.assertEqual(self.id["a"].to_list(), mylist)
  56. self.assertEqual(self.id["a"].typecode, "i")
  57. def test_sequence_float_array(self):
  58. mylist = [1.2, 3.4, 5.6]
  59. self.id["a"] = array("f", mylist)
  60. self.assertAlmostEqualSeq(self.id["a"].to_list(), mylist)
  61. self.assertEqual(self.id["a"].typecode, "f")
  62. def test_sequence_double_array(self):
  63. mylist = [1.2, 3.4, 5.6]
  64. self.id["a"] = array("d", mylist)
  65. self.assertAlmostEqualSeq(self.id["a"].to_list(), mylist)
  66. self.assertEqual(self.id["a"].typecode, "d")
  67. def test_sequence_int_array(self):
  68. mylist = [1, 2, 3]
  69. self.id["a"] = array("i", mylist)
  70. self.assertAlmostEqualSeq(self.id["a"].to_list(), mylist)
  71. self.assertEqual(self.id["a"].typecode, "i")
  72. def test_sequence_other_array(self):
  73. mylist = [1, 2, 3]
  74. self.id["a"] = array("Q", mylist)
  75. self.assertEqual(self.id["a"].to_list(), mylist)
  76. def test_sequence_mixed_numerical_type(self):
  77. self.id["a"] = [1, 2, 3.4, 5]
  78. self.assertAlmostEqualSeq(self.id["a"].to_list(), [1.0, 2.0, 3.4, 5.0])
  79. self.assertEqual(self.id["a"].typecode, "d")
  80. def test_sequence_str_list(self):
  81. # I'm a bit surprised that this works
  82. mylist = ["abc", "qwe"]
  83. self.id["a"] = mylist
  84. self.assertEqual(self.id["a"], mylist)
  85. def test_sequence_mixed_type(self):
  86. with self.assertRaises(TypeError):
  87. mylist = ["abc", 3, "qwe", 3.4]
  88. self.id["a"] = mylist
  89. def test_mapping_simple(self):
  90. mydict = {"1": 10, "2": "20", "3": 30.5}
  91. self.id["a"] = mydict
  92. self.assertEqual(self.id["a"]["1"], mydict["1"])
  93. self.assertEqual(self.id["a"]["2"], mydict["2"])
  94. self.assertEqual(self.id["a"]["3"], mydict["3"])
  95. def test_mapping_complex(self):
  96. mydict = {
  97. "1": [1, 2, 3],
  98. "2": {"1": "abc", "2": array("i", [4, 5, 6])},
  99. "3": {"1": {"1": 10}, "2": b"qwe"},
  100. }
  101. self.id["a"] = mydict
  102. self.assertEqual(self.id["a"]["1"].to_list(), [1, 2, 3])
  103. self.assertEqual(self.id["a"]["2"]["1"], "abc")
  104. self.assertEqual(self.id["a"]["2"]["2"].to_list(), [4, 5, 6])
  105. self.assertEqual(self.id["a"]["3"]["1"]["1"], 10)
  106. self.assertEqual(self.id["a"]["3"]["2"], b"qwe")
  107. with self.assertRaises(KeyError):
  108. a = self.id["a"]["2"]["a"]
  109. def test_invalid_type(self):
  110. with self.assertRaises(TypeError):
  111. self.id["a"] = self
  112. class TestBufferProtocol(TestHelper, unittest.TestCase):
  113. def test_int(self):
  114. self.id["a"] = array("i", [1, 2, 3, 4, 5])
  115. a = np.frombuffer(self.id["a"], self.id["a"].typecode)
  116. self.assertEqual(len(a), 5)
  117. a[2] = 10
  118. self.assertEqual(self.id["a"].to_list(), [1, 2, 10, 4, 5])
  119. def test_float(self):
  120. self.id["a"] = array("f", [1.0, 2.0, 3.0, 4.0])
  121. a = np.frombuffer(self.id["a"], self.id["a"].typecode)
  122. self.assertEqual(len(a), 4)
  123. a[-1] = 10
  124. self.assertEqual(self.id["a"].to_list(), [1.0, 2.0, 3.0, 10.0])
  125. def test_double(self):
  126. self.id["a"] = array("d", [1.0, 2.0, 3.0, 4.0])
  127. a = np.frombuffer(self.id["a"], self.id["a"].typecode)
  128. a[1] = 10
  129. self.assertEqual(self.id["a"].to_list(), [1.0, 10.0, 3.0, 4.0])
  130. def test_full_update(self):
  131. self.id["a"] = array("i", [1, 2, 3, 4, 5, 6])
  132. a = np.frombuffer(self.id["a"], self.id["a"].typecode)
  133. a[:] = [10, 20, 30, 40, 50, 60]
  134. self.assertEqual(self.id["a"].to_list(), [10, 20, 30, 40, 50, 60])
  135. def test_partial_update(self):
  136. self.id["a"] = array("i", [1, 2, 3, 4, 5, 6, 7, 8])
  137. a = np.frombuffer(self.id["a"], self.id["a"].typecode)
  138. a[1:5] = [10, 20, 30, 40]
  139. self.assertEqual(self.id["a"].to_list(), [1, 10, 20, 30, 40, 6, 7, 8])
  140. def test_copy(self):
  141. self.id["a"] = array("i", [1, 2, 3, 4, 5])
  142. self.id["b"] = self.id["a"]
  143. self.assertEqual(self.id["a"].to_list(), self.id["b"].to_list())
  144. def test_memview_attributes(self):
  145. mylist = [1, 2, 3]
  146. self.id["a"] = mylist
  147. view1 = memoryview(self.id["a"])
  148. view2 = memoryview(array("i", mylist))
  149. self.assertEqualMemviews(view1, view2)
  150. def assertEqualMemviews(self, view1, view2):
  151. props_to_compare = (
  152. "contiguous", "format", "itemsize", "nbytes", "ndim",
  153. "readonly", "shape", "strides", "suboffsets"
  154. )
  155. for attr in props_to_compare:
  156. self.assertEqual(getattr(view1, attr), getattr(view2, attr))
  157. self.assertEqual(list(view1), list(view2))
  158. self.assertEqual(view1.tobytes(), view2.tobytes())
  159. if __name__ == '__main__':
  160. import sys
  161. sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
  162. unittest.main()