1 import unittest 2 import pickle 3 from ctypes import * 4 import _ctypes_test 5 dll = CDLL(_ctypes_test.__file__) 6 7 class X(Structure): 8 _fields_ = [("a", c_int), ("b", c_double)] 9 init_called = 0 10 def __init__(self, *args, **kw): 11 X.init_called += 1 12 self.x = 42 13 14 class Y(X): 15 _fields_ = [("str", c_char_p)] 16 17 class PickleTest: 18 def dumps(self, item): 19 return pickle.dumps(item, self.proto) 20 21 def loads(self, item): 22 return pickle.loads(item) 23 24 def test_simple(self): 25 for src in [ 26 c_int(42), 27 c_double(3.14), 28 ]: 29 dst = self.loads(self.dumps(src)) 30 self.assertEqual(src.__dict__, dst.__dict__) 31 self.assertEqual(memoryview(src).tobytes(), 32 memoryview(dst).tobytes()) 33 34 def test_struct(self): 35 X.init_called = 0 36 37 x = X() 38 x.a = 42 39 self.assertEqual(X.init_called, 1) 40 41 y = self.loads(self.dumps(x)) 42 43 # loads must NOT call __init__ 44 self.assertEqual(X.init_called, 1) 45 46 # ctypes instances are identical when the instance __dict__ 47 # and the memory buffer are identical 48 self.assertEqual(y.__dict__, x.__dict__) 49 self.assertEqual(memoryview(y).tobytes(), 50 memoryview(x).tobytes()) 51 52 def test_unpickable(self): 53 # ctypes objects that are pointers or contain pointers are 54 # unpickable. 55 self.assertRaises(ValueError, lambda: self.dumps(Y())) 56 57 prototype = CFUNCTYPE(c_int) 58 59 for item in [ 60 c_char_p(), 61 c_wchar_p(), 62 c_void_p(), 63 pointer(c_int(42)), 64 dll._testfunc_p_p, 65 prototype(lambda: 42), 66 ]: 67 self.assertRaises(ValueError, lambda: self.dumps(item)) 68 69 def test_wchar(self): 70 self.dumps(c_char(b"x")) 71 # Issue 5049 72 self.dumps(c_wchar(u"x")) 73 74 for proto in range(pickle.HIGHEST_PROTOCOL + 1): 75 name = 'PickleTest_%s' % proto 76 globals()[name] = type(name, 77 (PickleTest, unittest.TestCase), 78 {'proto': proto}) 79 80 if __name__ == "__main__": 81 unittest.main() 82