PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/ctypes/test/test_callbacks.py

https://gitlab.com/unofficial-mirrors/cpython
Python | 282 lines | 197 code | 59 blank | 26 comment | 12 complexity | 06314e73474d4db8ddd5d57a8090bf5f MD5 | raw file
  1. import functools
  2. import unittest
  3. from ctypes import *
  4. from ctypes.test import need_symbol
  5. import _ctypes_test
  6. class Callbacks(unittest.TestCase):
  7. functype = CFUNCTYPE
  8. ## def tearDown(self):
  9. ## import gc
  10. ## gc.collect()
  11. def callback(self, *args):
  12. self.got_args = args
  13. return args[-1]
  14. def check_type(self, typ, arg):
  15. PROTO = self.functype.__func__(typ, typ)
  16. result = PROTO(self.callback)(arg)
  17. if typ == c_float:
  18. self.assertAlmostEqual(result, arg, places=5)
  19. else:
  20. self.assertEqual(self.got_args, (arg,))
  21. self.assertEqual(result, arg)
  22. PROTO = self.functype.__func__(typ, c_byte, typ)
  23. result = PROTO(self.callback)(-3, arg)
  24. if typ == c_float:
  25. self.assertAlmostEqual(result, arg, places=5)
  26. else:
  27. self.assertEqual(self.got_args, (-3, arg))
  28. self.assertEqual(result, arg)
  29. ################
  30. def test_byte(self):
  31. self.check_type(c_byte, 42)
  32. self.check_type(c_byte, -42)
  33. def test_ubyte(self):
  34. self.check_type(c_ubyte, 42)
  35. def test_short(self):
  36. self.check_type(c_short, 42)
  37. self.check_type(c_short, -42)
  38. def test_ushort(self):
  39. self.check_type(c_ushort, 42)
  40. def test_int(self):
  41. self.check_type(c_int, 42)
  42. self.check_type(c_int, -42)
  43. def test_uint(self):
  44. self.check_type(c_uint, 42)
  45. def test_long(self):
  46. self.check_type(c_long, 42)
  47. self.check_type(c_long, -42)
  48. def test_ulong(self):
  49. self.check_type(c_ulong, 42)
  50. def test_longlong(self):
  51. self.check_type(c_longlong, 42)
  52. self.check_type(c_longlong, -42)
  53. def test_ulonglong(self):
  54. self.check_type(c_ulonglong, 42)
  55. def test_float(self):
  56. # only almost equal: double -> float -> double
  57. import math
  58. self.check_type(c_float, math.e)
  59. self.check_type(c_float, -math.e)
  60. def test_double(self):
  61. self.check_type(c_double, 3.14)
  62. self.check_type(c_double, -3.14)
  63. def test_longdouble(self):
  64. self.check_type(c_longdouble, 3.14)
  65. self.check_type(c_longdouble, -3.14)
  66. def test_char(self):
  67. self.check_type(c_char, b"x")
  68. self.check_type(c_char, b"a")
  69. # disabled: would now (correctly) raise a RuntimeWarning about
  70. # a memory leak. A callback function cannot return a non-integral
  71. # C type without causing a memory leak.
  72. @unittest.skip('test disabled')
  73. def test_char_p(self):
  74. self.check_type(c_char_p, "abc")
  75. self.check_type(c_char_p, "def")
  76. def test_pyobject(self):
  77. o = ()
  78. from sys import getrefcount as grc
  79. for o in (), [], object():
  80. initial = grc(o)
  81. # This call leaks a reference to 'o'...
  82. self.check_type(py_object, o)
  83. before = grc(o)
  84. # ...but this call doesn't leak any more. Where is the refcount?
  85. self.check_type(py_object, o)
  86. after = grc(o)
  87. self.assertEqual((after, o), (before, o))
  88. def test_unsupported_restype_1(self):
  89. # Only "fundamental" result types are supported for callback
  90. # functions, the type must have a non-NULL stgdict->setfunc.
  91. # POINTER(c_double), for example, is not supported.
  92. prototype = self.functype.__func__(POINTER(c_double))
  93. # The type is checked when the prototype is called
  94. self.assertRaises(TypeError, prototype, lambda: None)
  95. def test_unsupported_restype_2(self):
  96. prototype = self.functype.__func__(object)
  97. self.assertRaises(TypeError, prototype, lambda: None)
  98. def test_issue_7959(self):
  99. proto = self.functype.__func__(None)
  100. class X(object):
  101. def func(self): pass
  102. def __init__(self):
  103. self.v = proto(self.func)
  104. import gc
  105. for i in range(32):
  106. X()
  107. gc.collect()
  108. live = [x for x in gc.get_objects()
  109. if isinstance(x, X)]
  110. self.assertEqual(len(live), 0)
  111. def test_issue12483(self):
  112. import gc
  113. class Nasty:
  114. def __del__(self):
  115. gc.collect()
  116. CFUNCTYPE(None)(lambda x=Nasty(): None)
  117. @need_symbol('WINFUNCTYPE')
  118. class StdcallCallbacks(Callbacks):
  119. try:
  120. functype = WINFUNCTYPE
  121. except NameError:
  122. pass
  123. ################################################################
  124. class SampleCallbacksTestCase(unittest.TestCase):
  125. def test_integrate(self):
  126. # Derived from some then non-working code, posted by David Foster
  127. dll = CDLL(_ctypes_test.__file__)
  128. # The function prototype called by 'integrate': double func(double);
  129. CALLBACK = CFUNCTYPE(c_double, c_double)
  130. # The integrate function itself, exposed from the _ctypes_test dll
  131. integrate = dll.integrate
  132. integrate.argtypes = (c_double, c_double, CALLBACK, c_long)
  133. integrate.restype = c_double
  134. def func(x):
  135. return x**2
  136. result = integrate(0.0, 1.0, CALLBACK(func), 10)
  137. diff = abs(result - 1./3.)
  138. self.assertLess(diff, 0.01, "%s not less than 0.01" % diff)
  139. def test_issue_8959_a(self):
  140. from ctypes.util import find_library
  141. libc_path = find_library("c")
  142. if not libc_path:
  143. self.skipTest('could not find libc')
  144. libc = CDLL(libc_path)
  145. @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
  146. def cmp_func(a, b):
  147. return a[0] - b[0]
  148. array = (c_int * 5)(5, 1, 99, 7, 33)
  149. libc.qsort(array, len(array), sizeof(c_int), cmp_func)
  150. self.assertEqual(array[:], [1, 5, 7, 33, 99])
  151. @need_symbol('WINFUNCTYPE')
  152. def test_issue_8959_b(self):
  153. from ctypes.wintypes import BOOL, HWND, LPARAM
  154. global windowCount
  155. windowCount = 0
  156. @WINFUNCTYPE(BOOL, HWND, LPARAM)
  157. def EnumWindowsCallbackFunc(hwnd, lParam):
  158. global windowCount
  159. windowCount += 1
  160. return True #Allow windows to keep enumerating
  161. windll.user32.EnumWindows(EnumWindowsCallbackFunc, 0)
  162. def test_callback_register_int(self):
  163. # Issue #8275: buggy handling of callback args under Win64
  164. # NOTE: should be run on release builds as well
  165. dll = CDLL(_ctypes_test.__file__)
  166. CALLBACK = CFUNCTYPE(c_int, c_int, c_int, c_int, c_int, c_int)
  167. # All this function does is call the callback with its args squared
  168. func = dll._testfunc_cbk_reg_int
  169. func.argtypes = (c_int, c_int, c_int, c_int, c_int, CALLBACK)
  170. func.restype = c_int
  171. def callback(a, b, c, d, e):
  172. return a + b + c + d + e
  173. result = func(2, 3, 4, 5, 6, CALLBACK(callback))
  174. self.assertEqual(result, callback(2*2, 3*3, 4*4, 5*5, 6*6))
  175. def test_callback_register_double(self):
  176. # Issue #8275: buggy handling of callback args under Win64
  177. # NOTE: should be run on release builds as well
  178. dll = CDLL(_ctypes_test.__file__)
  179. CALLBACK = CFUNCTYPE(c_double, c_double, c_double, c_double,
  180. c_double, c_double)
  181. # All this function does is call the callback with its args squared
  182. func = dll._testfunc_cbk_reg_double
  183. func.argtypes = (c_double, c_double, c_double,
  184. c_double, c_double, CALLBACK)
  185. func.restype = c_double
  186. def callback(a, b, c, d, e):
  187. return a + b + c + d + e
  188. result = func(1.1, 2.2, 3.3, 4.4, 5.5, CALLBACK(callback))
  189. self.assertEqual(result,
  190. callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5))
  191. def test_callback_large_struct(self):
  192. class Check: pass
  193. class X(Structure):
  194. _fields_ = [
  195. ('first', c_ulong),
  196. ('second', c_ulong),
  197. ('third', c_ulong),
  198. ]
  199. def callback(check, s):
  200. check.first = s.first
  201. check.second = s.second
  202. check.third = s.third
  203. check = Check()
  204. s = X()
  205. s.first = 0xdeadbeef
  206. s.second = 0xcafebabe
  207. s.third = 0x0bad1dea
  208. CALLBACK = CFUNCTYPE(None, X)
  209. dll = CDLL(_ctypes_test.__file__)
  210. func = dll._testfunc_cbk_large_struct
  211. func.argtypes = (X, CALLBACK)
  212. func.restype = None
  213. # the function just calls the callback with the passed structure
  214. func(s, CALLBACK(functools.partial(callback, check)))
  215. self.assertEqual(check.first, s.first)
  216. self.assertEqual(check.second, s.second)
  217. self.assertEqual(check.third, s.third)
  218. self.assertEqual(check.first, 0xdeadbeef)
  219. self.assertEqual(check.second, 0xcafebabe)
  220. self.assertEqual(check.third, 0x0bad1dea)
  221. ################################################################
  222. if __name__ == '__main__':
  223. unittest.main()