Reputation: 18299
How do I pass in the name of a capsule into the second argument of PyCapsule_New
via ctypes
?
I've tried the following, but it seems that something is off:
capsule = ctypes.pythonapi.PyCapsule_New(b'data', b'abcdef.ghijkl', None)
capsule = ctypes.pythonapi.PyCapsule_New(b'data', ctypes.create_string_buffer(b"abcdef.ghijkl"), None)
capsule = ctypes.pythonapi.PyCapsule_New(b'data', ctypes.c_chap_p(b"abcdef.ghijkl"), None)
For example, the name of the capsule is not being set correctly:
>>> import ctypes
>>> ctypes.pythonapi.PyCapsule_New.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p]
>>> ctypes.pythonapi.PyCapsule_New.restype = ctypes.py_object
>>>
>>> capsule = ctypes.pythonapi.PyCapsule_New(b'data', b'abcdef.ghijkl', None)
>>>
>>> capsule
<capsule object "" at 0xf7102f98>
>>> capsule
<capsule object "e" at 0xf7102f98>
>>> capsule
<capsule object "���capsule
<capsule object "" at 0xf7102f98>
>>> capsule
<capsule object "e" at 0xf7102f98>
>>> capsule
<capsule object "e" at 0xf7102f98>
>>> capsule
<capsule object "���
If I use ctypes.create_string_buffer(b"abcdef.ghijkl")
:
>>> capsule = ctypes.pythonapi.PyCapsule_New(b'data', ctypes.create_string_buffer(b"abcdef.ghijkl"), None)
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf7102fb0>
>>> capsule
<capsule object "" at 0xf7102fb0>
>>> capsule
<capsule object "" at 0xf7102fb0>
>>> capsule
<capsule object "" at 0xf7102fb0>
>>> capsule
<capsule object "" at 0xf7102fb0>
The strange thing here is that if I make a C Extension that returns a capsule, I can extract it's name using ctypes, and it works:
>>> capsule_from_c_ext = mycext.capsule()
>>> ctypes.pythonapi.PyCapsule_GetName.restype = ctypes.c_char_p
>>> ctypes.pythonapi.PyCapsule_GetName.argtypes = [ctypes.py_object]
>>> name = ctypes.pythonapi.PyCapsule_GetName(capsule_from_c_ext)
>>> name
b"abcdef.ghijkl"
>>> type(name)
<class 'bytes'>
>>> assert name == b"abcdef.ghijkl"
>>>
>>> capsule = ctypes.pythonapi.PyCapsule_New(b'data', name, None)
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf6f23c20>
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf6f23c20>
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf6f23c20>
>>>
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf6f23c20>
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf6f23c20>
Additionally, if you use a shorter name, like b'name'
, it appears to work correctly.
Upvotes: 0
Views: 480
Reputation: 18299
I got a hint from the docs:
The name string may either be NULL or a pointer to a valid C string. If non-NULL, this string must outlive the capsule. (Though it is permitted to free it inside the destructor.)
Creating a variable with the name first, and then calling it, seems to work:
>>> import ctypes
>>> ctypes.pythonapi.PyCapsule_New.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p]
>>> ctypes.pythonapi.PyCapsule_New.restype = ctypes.py_object
>>> name = b'abcdef.ghijkl'
>>> capsule = ctypes.pythonapi.PyCapsule_New(b'data', name, None)
>>>
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf6f23bd8>
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf6f23bd8>
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf6f23bd8>
>>> capsule
<capsule object "abcdef.ghijkl" at 0xf6f23bd8>
And you can prove that you need the name
variable to not be deallocated:
del name
>>> capsule
<capsule object "" at 0xf7102fb0>
>>> capsule
<capsule object "" at 0xf7102fb0>
>>> capsule
<capsule object "" at 0xf7102fb0>
>>> capsule
<capsule object "" at 0xf7102fb0>
Upvotes: 1