[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [23032] branches/blender2.5/blender: Python part of multidim.

Arystanbek Dyussenov arystan.d at gmail.com
Sun Sep 6 17:14:00 CEST 2009


Revision: 23032
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=23032
Author:   kazanbas
Date:     2009-09-06 17:13:57 +0200 (Sun, 06 Sep 2009)

Log Message:
-----------
Python part of multidim. array support for RNA complete.

Multidim. arrays can now be modified at any level, for example:

struc.arrayprop = x
struc.arrayprop[i] = x
struc.arrayprop[i][j] = x
struc.arrayprop[i][j][k] = x
etc...

Approriate rvalue type/length checking is done. 

To ensure all works correctly, I wrote automated tests in release/test/rna_array.py.

These tests cover: array/item access, assignment on different levels, tests that proper exceptions are thrown on invalid item access/assignment.

The tests use properties of the RNA Test struct defined in rna_test.c. This struct is only compiled when building with BF_UNIT_TEST=1 scons arg.

Currently unit tests are run manually by loading the script in the Text Editor.
Here's the output I have: http://www.pasteall.org/7644

Things to improve here:
- better exception messages when multidim. array assignment fails. Those we have currently are not very useful for multidim.
- add tests for slice assignment

Modified Paths:
--------------
    branches/blender2.5/blender/source/blender/blenloader/intern/readblenentry.c
    branches/blender2.5/blender/source/blender/makesrna/RNA_access.h
    branches/blender2.5/blender/source/blender/makesrna/SConscript
    branches/blender2.5/blender/source/blender/makesrna/intern/SConscript
    branches/blender2.5/blender/source/blender/makesrna/intern/makesrna.c
    branches/blender2.5/blender/source/blender/makesrna/intern/rna_access.c
    branches/blender2.5/blender/source/blender/makesrna/intern/rna_define.c
    branches/blender2.5/blender/source/blender/makesrna/intern/rna_internal.h
    branches/blender2.5/blender/source/blender/makesrna/intern/rna_internal_types.h
    branches/blender2.5/blender/source/blender/makesrna/intern/rna_main.c
    branches/blender2.5/blender/source/blender/makesrna/intern/rna_mesh.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_array.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c
    branches/blender2.5/blender/source/blender/python/intern/bpy_rna.h
    branches/blender2.5/blender/tools/btools.py

Added Paths:
-----------
    branches/blender2.5/blender/release/test/
    branches/blender2.5/blender/release/test/rna_array.py
    branches/blender2.5/blender/source/blender/makesrna/intern/rna_test.c

Added: branches/blender2.5/blender/release/test/rna_array.py
===================================================================
--- branches/blender2.5/blender/release/test/rna_array.py	                        (rev 0)
+++ branches/blender2.5/blender/release/test/rna_array.py	2009-09-06 15:13:57 UTC (rev 23032)
@@ -0,0 +1,279 @@
+import unittest
+import random
+
+test= bpy.data.test
+
+# farr - 1-dimensional array of float
+# fdarr - dynamic 1-dimensional array of float
+# fmarr - 3-dimensional ([3][4][5]) array of float
+# fdmarr - dynamic 3-dimensional (ditto size) array of float
+
+# same as above for other types except that the first letter is "i" for int and "b" for bool
+
+class TestArray(unittest.TestCase):
+	# test that assignment works by: assign -> test value
+	# - rvalue = list of float
+	# - rvalue = list of numbers
+	# test.object
+	# bpy.data.test.farr[3], iarr[3], barr[...], fmarr, imarr, bmarr
+
+	def setUp(self):
+		test.farr= (1.0, 2.0, 3.0)
+		test.iarr= (7, 8, 9)
+		test.barr= (False, True, False)
+	
+	# test access
+	# test slice access, negative indices
+	def test_access(self):
+		rvals= ([1.0, 2.0, 3.0], [7, 8, 9], [False, True, False])
+		for arr, rval in zip((test.farr, test.iarr, test.barr), rvals):
+			self.assertEqual(prop_to_list(arr), rval)
+			self.assertEqual(arr[0:3], rval)
+			self.assertEqual(arr[1:2], rval[1:2])
+			self.assertEqual(arr[-1], arr[2])
+			self.assertEqual(arr[-2], arr[1])
+			self.assertEqual(arr[-3], arr[0])
+
+	# fail when index out of bounds
+	def test_access_fail(self):
+		for arr in (test.farr, test.iarr, test.barr):
+			self.assertRaises(IndexError, lambda : arr[4])
+	
+	# test assignment of a whole array
+	def test_assign_array(self):
+		# should accept int as float
+		test.farr= (1, 2, 3)
+
+	# fail when: unexpected no. of items, invalid item type
+	def test_assign_array_fail(self):
+		def assign_empty_list(arr):
+			setattr(test, arr, ())
+
+		for arr in ("farr", "iarr", "barr"):
+			self.assertRaises(ValueError, assign_empty_list, arr)
+
+		def assign_invalid_float():
+			test.farr= (1.0, 2.0, "3.0")
+
+		def assign_invalid_int():
+			test.iarr= ("1", 2, 3)
+
+		def assign_invalid_bool():
+			test.barr= (True, 0.123, False)
+
+		for func in [assign_invalid_float, assign_invalid_int, assign_invalid_bool]:
+			self.assertRaises(TypeError, func)
+
+		# shouldn't accept float as int
+		def assign_float_as_int():
+			test.iarr= (1, 2, 3.0)
+		self.assertRaises(TypeError, assign_float_as_int)
+
+		# non-dynamic arrays cannot change size
+		def assign_different_size(arr, val):
+			setattr(test, arr, val)
+		for arr, val in zip(("iarr", "farr", "barr"), ((1, 2), (1.0, 2.0), (True, False))):
+			self.assertRaises(ValueError, assign_different_size, arr, val)
+
+	# test assignment of specific items
+	def test_assign_item(self):
+		for arr, rand_func in zip((test.farr, test.iarr, test.barr), (rand_float, rand_int, rand_bool)):
+			for i in range(len(arr)):
+				val= rand_func()
+				arr[i]= val
+				
+				self.assertEqual(arr[i], val)
+
+		# float prop should accept also int
+		for i in range(len(test.farr)):
+			val= rand_int()
+			test.farr[i]= val
+			self.assertEqual(test.farr[i], float(val))
+
+		# 
+
+	def test_assign_item_fail(self):
+		def assign_bad_index(arr):
+			arr[4] = 1.0
+
+		def assign_bad_type(arr):
+			arr[1]= "123"
+			
+		for arr in [test.farr, test.iarr, test.barr]:
+			self.assertRaises(IndexError, assign_bad_index, arr)
+
+		# not testing bool because bool allows not only (True|False)
+		for arr in [test.farr, test.iarr]:	
+			self.assertRaises(TypeError, assign_bad_type, arr)
+
+	def test_dynamic_assign_array(self):
+		# test various lengths here
+		for arr, rand_func in zip(("fdarr", "idarr", "bdarr"), (rand_float, rand_int, rand_bool)):
+			for length in range(1, 64):
+				rval= make_random_array(length, rand_func)
+				setattr(test, arr, rval)
+				self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+	def test_dynamic_assign_array_fail(self):
+		# could also test too big length here
+		
+		def assign_empty_list(arr):
+			setattr(test, arr, ())
+
+		for arr in ("fdarr", "idarr", "bdarr"):
+			self.assertRaises(ValueError, assign_empty_list, arr)
+
+
+class TestMArray(unittest.TestCase):
+	def setUp(self):
+		# reset dynamic array sizes
+		for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
+			setattr(test, arr, make_random_3d_array((3, 4, 5), func))
+
+	# test assignment
+	def test_assign_array(self):
+		for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
+			# assignment of [3][4][5]
+			rval= make_random_3d_array((3, 4, 5), func)
+			setattr(test, arr, rval)
+			self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+		# test assignment of [2][4][5], [1][4][5] should work on dynamic arrays
+
+	def test_assign_array_fail(self):
+		def assign_empty_array():
+			test.fmarr= ()
+		self.assertRaises(ValueError, assign_empty_array)
+
+		def assign_invalid_size(arr, rval):
+			setattr(test, arr, rval)
+
+		# assignment of 3,4,4 or 3,3,5 should raise ex
+		for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
+			rval= make_random_3d_array((3, 4, 4), func)
+			self.assertRaises(ValueError, assign_invalid_size, arr, rval)
+
+			rval= make_random_3d_array((3, 3, 5), func)
+			self.assertRaises(ValueError, assign_invalid_size, arr, rval)
+
+			rval= make_random_3d_array((3, 3, 3), func)
+			self.assertRaises(ValueError, assign_invalid_size, arr, rval)
+
+	def test_assign_item(self):
+		# arr[i] = x
+		for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
+			rval= make_random_2d_array((4, 5), func)
+
+			for i in range(3):
+				getattr(test, arr)[i]= rval
+				self.assertEqual(prop_to_list(getattr(test, arr)[i]), rval)
+
+		# arr[i][j] = x
+		for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
+
+			arr= getattr(test, arr)
+			rval= make_random_array(5, func)
+
+			for i in range(3):
+				for j in range(4):
+					arr[i][j]= rval
+					self.assertEqual(prop_to_list(arr[i][j]), rval)
+
+
+	def test_assign_item_fail(self):
+		def assign_wrong_size(arr, i, rval):
+			getattr(test, arr)[i]= rval
+
+		# assign wrong size at level 2
+		for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
+			rval1= make_random_2d_array((3, 5), func)
+			rval2= make_random_2d_array((4, 3), func)
+
+			for i in range(3):
+				self.assertRaises(ValueError, assign_wrong_size, arr, i, rval1)
+				self.assertRaises(ValueError, assign_wrong_size, arr, i, rval2)
+
+	def test_dynamic_assign_array(self):
+		for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
+			# assignment of [3][4][5]
+			rval= make_random_3d_array((3, 4, 5), func)
+			setattr(test, arr, rval)
+			self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+			# [2][4][5]
+			rval= make_random_3d_array((2, 4, 5), func)
+			setattr(test, arr, rval)
+			self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+			# [1][4][5]
+			rval= make_random_3d_array((1, 4, 5), func)
+			setattr(test, arr, rval)
+			self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+
+	# test access
+	def test_access(self):
+		pass
+
+	# test slice access, negative indices
+	def test_access_fail(self):
+		pass
+
+random.seed()
+
+def rand_int():
+	return random.randint(-1000, 1000)
+
+def rand_float():
+	return float(rand_int())
+
+def rand_bool():
+	return bool(random.randint(0, 1))
+
+def make_random_array(len, rand_func):
+	arr= []
+	for i in range(len):
+		arr.append(rand_func())
+		
+	return arr
+
+def make_random_2d_array(dimsize, rand_func):
+	marr= []
+	for i in range(dimsize[0]):
+		marr.append([])
+
+		for j in range(dimsize[1]):
+			marr[-1].append(rand_func())
+
+	return marr
+
+def make_random_3d_array(dimsize, rand_func):
+	marr= []
+	for i in range(dimsize[0]):
+		marr.append([])
+
+		for j in range(dimsize[1]):
+			marr[-1].append([])
+
+			for k in range(dimsize[2]):
+				marr[-1][-1].append(rand_func())
+
+	return marr
+
+def prop_to_list(prop):
+	ret= []
+
+	for x in prop:
+		if type(x) not in (bool, int, float):
+			ret.append(prop_to_list(x))
+		else:
+			ret.append(x)
+
+	return ret
+
+def suite():
+	return unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(TestArray), unittest.TestLoader().loadTestsFromTestCase(TestMArray)])
+
+if __name__ == "__main__":
+	unittest.TextTestRunner(verbosity=2).run(suite())
+

Modified: branches/blender2.5/blender/source/blender/blenloader/intern/readblenentry.c
===================================================================
--- branches/blender2.5/blender/source/blender/blenloader/intern/readblenentry.c	2009-09-06 14:32:02 UTC (rev 23031)
+++ branches/blender2.5/blender/source/blender/blenloader/intern/readblenentry.c	2009-09-06 15:13:57 UTC (rev 23032)
@@ -32,14 +32,13 @@
 #include <config.h>
 #endif
 
+#include "BLI_storage.h" /* _LARGEFILE_SOURCE */
+
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <math.h>
 
-
-#include "BLI_storage.h" /* _LARGEFILE_SOURCE */
-
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"

Modified: branches/blender2.5/blender/source/blender/makesrna/RNA_access.h
===================================================================
--- branches/blender2.5/blender/source/blender/makesrna/RNA_access.h	2009-09-06 14:32:02 UTC (rev 23031)
+++ branches/blender2.5/blender/source/blender/makesrna/RNA_access.h	2009-09-06 15:13:57 UTC (rev 23032)
@@ -586,6 +586,7 @@
 int RNA_property_flag(PropertyRNA *prop);
 
 int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop);
+int RNA_property_multidimensional_array_length(PointerRNA *ptr, PropertyRNA *prop, int dimension);
 int RNA_property_dynamic_array_set_length(PointerRNA *ptr, PropertyRNA *prop, int length);
 char RNA_property_array_item_char(PropertyRNA *prop, int index);
 unsigned short RNA_property_array_dimension(PropertyRNA *prop, unsigned short dim_size[]);

Modified: branches/blender2.5/blender/source/blender/makesrna/SConscript
===================================================================
--- branches/blender2.5/blender/source/blender/makesrna/SConscript	2009-09-06 14:32:02 UTC (rev 23031)
+++ branches/blender2.5/blender/source/blender/makesrna/SConscript	2009-09-06 15:13:57 UTC (rev 23032)
@@ -37,4 +37,7 @@
 if env['WITH_BF_GAMEENGINE']:
 	defs.append('GAMEBLENDER=1')
 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list