Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 1 | r''' |
| 2 | This tests the '_objects' attribute of ctypes instances. '_objects' |
| 3 | holds references to objects that must be kept alive as long as the |
| 4 | ctypes instance, to make sure that the memory buffer is valid. |
| 5 | |
| 6 | WARNING: The '_objects' attribute is exposed ONLY for debugging ctypes itself, |
| 7 | it MUST NEVER BE MODIFIED! |
| 8 | |
| 9 | '_objects' is initialized to a dictionary on first use, before that it |
| 10 | is None. |
| 11 | |
| 12 | Here is an array of string pointers: |
| 13 | |
| 14 | >>> from ctypes import * |
| 15 | >>> array = (c_char_p * 5)() |
Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 16 | >>> print(array._objects) |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 17 | None |
| 18 | >>> |
| 19 | |
| 20 | The memory block stores pointers to strings, and the strings itself |
| 21 | assigned from Python must be kept. |
| 22 | |
Victor Stinner | 42746df | 2010-07-27 23:36:41 +0000 | [diff] [blame] | 23 | >>> array[4] = b'foo bar' |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 24 | >>> array._objects |
Thomas Heller | f7c6d86 | 2007-07-12 13:55:37 +0000 | [diff] [blame] | 25 | {'4': b'foo bar'} |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 26 | >>> array[4] |
Thomas Heller | 8b93952 | 2009-09-04 18:24:41 +0000 | [diff] [blame] | 27 | b'foo bar' |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 28 | >>> |
| 29 | |
| 30 | It gets more complicated when the ctypes instance itself is contained |
| 31 | in a 'base' object. |
| 32 | |
| 33 | >>> class X(Structure): |
| 34 | ... _fields_ = [("x", c_int), ("y", c_int), ("array", c_char_p * 5)] |
| 35 | ... |
| 36 | >>> x = X() |
Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 37 | >>> print(x._objects) |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 38 | None |
| 39 | >>> |
| 40 | |
| 41 | The'array' attribute of the 'x' object shares part of the memory buffer |
| 42 | of 'x' ('_b_base_' is either None, or the root object owning the memory block): |
| 43 | |
Guido van Rossum | 7131f84 | 2007-02-09 20:13:25 +0000 | [diff] [blame] | 44 | >>> print(x.array._b_base_) # doctest: +ELLIPSIS |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 45 | <ctypes.test.test_objects.X object at 0x...> |
| 46 | >>> |
| 47 | |
Victor Stinner | 42746df | 2010-07-27 23:36:41 +0000 | [diff] [blame] | 48 | >>> x.array[0] = b'spam spam spam' |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 49 | >>> x._objects |
Thomas Heller | f7c6d86 | 2007-07-12 13:55:37 +0000 | [diff] [blame] | 50 | {'0:2': b'spam spam spam'} |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 51 | >>> x.array._b_base_._objects |
Thomas Heller | f7c6d86 | 2007-07-12 13:55:37 +0000 | [diff] [blame] | 52 | {'0:2': b'spam spam spam'} |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 53 | >>> |
| 54 | |
| 55 | ''' |
| 56 | |
Berker Peksag | 1e8ee9b | 2016-04-24 07:31:42 +0300 | [diff] [blame] | 57 | import unittest, doctest |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 58 | |
| 59 | import ctypes.test.test_objects |
| 60 | |
| 61 | class TestCase(unittest.TestCase): |
Zachary Ware | 9422df0 | 2014-06-13 13:44:39 -0500 | [diff] [blame] | 62 | def test(self): |
| 63 | failures, tests = doctest.testmod(ctypes.test.test_objects) |
| 64 | self.assertFalse(failures, 'doctests failed, see output above') |
Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 65 | |
| 66 | if __name__ == '__main__': |
Zachary Ware | 9422df0 | 2014-06-13 13:44:39 -0500 | [diff] [blame] | 67 | doctest.testmod(ctypes.test.test_objects) |