Re: return a ctypes object to C
On 31-10-2019 15:39, Arnaud Loonstra wrote: On 31-10-2019 14:44, Thomas Jollans wrote: On 31/10/2019 14.13, Arnaud Loonstra wrote: On 30-10-2019 09:32, Arnaud Loonstra wrote: Hi all, I'm trying to wrap my head around the ctypes API. I have a C structure I wish to create in Python and then return from python to C. So a python method is called from C and needs to return an object which we then process in C again. I have a binding to access and create the C methods and structures so in Python I can call the Zmsg() constructor. I now need to return this. My python test method is simply: def actor_test( *args, **kwargs): print("test") msg = Zmsg() frame = Zframe(b"Hello", 5) msg.prepend(frame) return msg the method is called from C as follows: PyObject *pReturn = PyObject_CallObject(pFunc, NULL); This correctly calls the method. However the returned object is of course a PyObject*. The debugger says it's "" PyObject [class] "" [super class] "" [meta type] "" ob_refcnt 1 Py_ssize_t However how I can I get it back to the original C type (zmsg_t *) Any help really appreciated. What I've found so far is that I can return the address of the ctypes object. msg = Zmsg() frame = Zframe(b"Hello", 5) msg.prepend(frame) return addressof(msg._as_parameter_.contents) In C I can then cast it back to the original type. PyObject *pReturn = PyObject_CallObject(pFunc, NULL); assert(pReturn); long bla = PyLong_AsLong(pReturn); zmsg_t* test = (zmsg_t *)bla; assert(test); char *hello = zmsg_popstr(test); assert(hello); assert(streq(hello, "Hello")); This works, I'm not sure if this is the right way. It also creates a complicated setup with the garbage collector. Anybody better ideas? You've already got a complicated setup with your ctypes objects... If you're using the Python C API anyway, why would you use ctypes at all? You can create custom Python types in C to wrap your C pointers. Alternatively: if you're using ctypes anyway, why use the Python C API at all? You can create C function pointers from Python functions with ctypes. If you're mixing two different ways of interfacing Python and C, the result will ALWAYS be messy. Better to stick to one. Personally, I prefer cffi or cython depending on the situation, as I find them clearer and easier to use than ctypes. Using the Python C API directly is usually the hardest to understand and the easiest to get wrong. -- Thomas Hi Thomas, I have an engine running which can call handlers. These handlers return a zmsg_t (a message) which the engine then can process. In this engine we have Python embedded and I want to use a Python method as a handler. To embed Python we need to use the Python C API. To construct a zmsg_t type in Python we need to call the corresponding C method and we use ctypes to do that. I'm using a ctypes binding because it already exists, it's here: https://github.com/zeromq/czmq/blob/d6283985ba52fd8c3f8fbdc7cd5c08372ff69ca1/bindings/python/czmq/_czmq_ctypes.py#L4392 I know I can use cffi for example but that's IMHO just a ctypes alternative. Are you saying it's better to create some approach to create a zmsg_t using the Python C API? Please enlighten me if this should be done differently. Rg, Arnaud Ok, you're reply triggered me to do some more reading into the C-API. I've found I can do it all using the C-API. Especially this guide was very helpful for my situation: https://docs.python.org/3/extending/newtypes_tutorial.html Thnx, Arnaud -- https://mail.python.org/mailman/listinfo/python-list
Re: return a ctypes object to C
On 10/30/19, Arnaud Loonstra wrote: > > I have a binding to access and create the C methods and structures so in > Python I can call the Zmsg() constructor. I now need to return this. > > My python test method is simply: > > def actor_test( *args, **kwargs): > print("test") > msg = Zmsg() > frame = Zframe(b"Hello", 5) > msg.prepend(frame) > return msg > > the method is called from C as follows: > > PyObject *pReturn = PyObject_CallObject(pFunc, NULL); > > This correctly calls the method. However the returned object is of > course a PyObject*. The debugger says it's > > "" PyObject > [class] "" > [super class] "" > [meta type] "" > ob_refcnt 1 Py_ssize_t > > However how I can I get it back to the original C type (zmsg_t *) I don't know what this Zmsg type is. It doesn't appear to be a ctypes type such as a Structure. Either way, I'd wager that it supports the buffer protocol. https://docs.python.org/3/c-api/buffer.html Call PyObject_GetBuffer to get a simple view, and try casting the `buf` pointer to a zmsg_t pointer. -- https://mail.python.org/mailman/listinfo/python-list
Re: return a ctypes object to C
On 31-10-2019 14:44, Thomas Jollans wrote: On 31/10/2019 14.13, Arnaud Loonstra wrote: On 30-10-2019 09:32, Arnaud Loonstra wrote: Hi all, I'm trying to wrap my head around the ctypes API. I have a C structure I wish to create in Python and then return from python to C. So a python method is called from C and needs to return an object which we then process in C again. I have a binding to access and create the C methods and structures so in Python I can call the Zmsg() constructor. I now need to return this. My python test method is simply: def actor_test( *args, **kwargs): print("test") msg = Zmsg() frame = Zframe(b"Hello", 5) msg.prepend(frame) return msg the method is called from C as follows: PyObject *pReturn = PyObject_CallObject(pFunc, NULL); This correctly calls the method. However the returned object is of course a PyObject*. The debugger says it's "" PyObject [class] "" [super class] "" [meta type] "" ob_refcnt 1 Py_ssize_t However how I can I get it back to the original C type (zmsg_t *) Any help really appreciated. What I've found so far is that I can return the address of the ctypes object. msg = Zmsg() frame = Zframe(b"Hello", 5) msg.prepend(frame) return addressof(msg._as_parameter_.contents) In C I can then cast it back to the original type. PyObject *pReturn = PyObject_CallObject(pFunc, NULL); assert(pReturn); long bla = PyLong_AsLong(pReturn); zmsg_t* test = (zmsg_t *)bla; assert(test); char *hello = zmsg_popstr(test); assert(hello); assert(streq(hello, "Hello")); This works, I'm not sure if this is the right way. It also creates a complicated setup with the garbage collector. Anybody better ideas? You've already got a complicated setup with your ctypes objects... If you're using the Python C API anyway, why would you use ctypes at all? You can create custom Python types in C to wrap your C pointers. Alternatively: if you're using ctypes anyway, why use the Python C API at all? You can create C function pointers from Python functions with ctypes. If you're mixing two different ways of interfacing Python and C, the result will ALWAYS be messy. Better to stick to one. Personally, I prefer cffi or cython depending on the situation, as I find them clearer and easier to use than ctypes. Using the Python C API directly is usually the hardest to understand and the easiest to get wrong. -- Thomas Hi Thomas, I have an engine running which can call handlers. These handlers return a zmsg_t (a message) which the engine then can process. In this engine we have Python embedded and I want to use a Python method as a handler. To embed Python we need to use the Python C API. To construct a zmsg_t type in Python we need to call the corresponding C method and we use ctypes to do that. I'm using a ctypes binding because it already exists, it's here: https://github.com/zeromq/czmq/blob/d6283985ba52fd8c3f8fbdc7cd5c08372ff69ca1/bindings/python/czmq/_czmq_ctypes.py#L4392 I know I can use cffi for example but that's IMHO just a ctypes alternative. Are you saying it's better to create some approach to create a zmsg_t using the Python C API? Please enlighten me if this should be done differently. Rg, Arnaud -- https://mail.python.org/mailman/listinfo/python-list
Re: return a ctypes object to C
On 31/10/2019 14.13, Arnaud Loonstra wrote: > On 30-10-2019 09:32, Arnaud Loonstra wrote: >> Hi all, >> >> I'm trying to wrap my head around the ctypes API. I have a C >> structure I wish to create in Python and then return from python to C. >> >> So a python method is called from C and needs to return an object >> which we then process in C again. >> >> I have a binding to access and create the C methods and structures so >> in Python I can call the Zmsg() constructor. I now need to return this. >> >> My python test method is simply: >> >> def actor_test( *args, **kwargs): >> print("test") >> msg = Zmsg() >> frame = Zframe(b"Hello", 5) >> msg.prepend(frame) >> return msg >> >> the method is called from C as follows: >> >> PyObject *pReturn = PyObject_CallObject(pFunc, NULL); >> >> This correctly calls the method. However the returned object is of >> course a PyObject*. The debugger says it's >> >> "" PyObject >> [class] "" >> [super class] "" >> [meta type] "" >> ob_refcnt 1 Py_ssize_t >> >> However how I can I get it back to the original C type (zmsg_t *) >> >> Any help really appreciated. >> > > What I've found so far is that I can return the address of the ctypes > object. > > msg = Zmsg() > frame = Zframe(b"Hello", 5) > msg.prepend(frame) > return addressof(msg._as_parameter_.contents) > > In C I can then cast it back to the original type. > > PyObject *pReturn = PyObject_CallObject(pFunc, NULL); > assert(pReturn); > long bla = PyLong_AsLong(pReturn); > zmsg_t* test = (zmsg_t *)bla; > assert(test); > char *hello = zmsg_popstr(test); > assert(hello); > assert(streq(hello, "Hello")); > > This works, I'm not sure if this is the right way. It also creates a > complicated setup with the garbage collector. > > Anybody better ideas? You've already got a complicated setup with your ctypes objects... If you're using the Python C API anyway, why would you use ctypes at all? You can create custom Python types in C to wrap your C pointers. Alternatively: if you're using ctypes anyway, why use the Python C API at all? You can create C function pointers from Python functions with ctypes. If you're mixing two different ways of interfacing Python and C, the result will ALWAYS be messy. Better to stick to one. Personally, I prefer cffi or cython depending on the situation, as I find them clearer and easier to use than ctypes. Using the Python C API directly is usually the hardest to understand and the easiest to get wrong. -- Thomas -- https://mail.python.org/mailman/listinfo/python-list
Re: return a ctypes object to C
On 30-10-2019 09:32, Arnaud Loonstra wrote: Hi all, I'm trying to wrap my head around the ctypes API. I have a C structure I wish to create in Python and then return from python to C. So a python method is called from C and needs to return an object which we then process in C again. I have a binding to access and create the C methods and structures so in Python I can call the Zmsg() constructor. I now need to return this. My python test method is simply: def actor_test( *args, **kwargs): print("test") msg = Zmsg() frame = Zframe(b"Hello", 5) msg.prepend(frame) return msg the method is called from C as follows: PyObject *pReturn = PyObject_CallObject(pFunc, NULL); This correctly calls the method. However the returned object is of course a PyObject*. The debugger says it's "" PyObject [class] "" [super class] "" [meta type] "" ob_refcnt 1 Py_ssize_t However how I can I get it back to the original C type (zmsg_t *) Any help really appreciated. What I've found so far is that I can return the address of the ctypes object. msg = Zmsg() frame = Zframe(b"Hello", 5) msg.prepend(frame) return addressof(msg._as_parameter_.contents) In C I can then cast it back to the original type. PyObject *pReturn = PyObject_CallObject(pFunc, NULL); assert(pReturn); long bla = PyLong_AsLong(pReturn); zmsg_t* test = (zmsg_t *)bla; assert(test); char *hello = zmsg_popstr(test); assert(hello); assert(streq(hello, "Hello")); This works, I'm not sure if this is the right way. It also creates a complicated setup with the garbage collector. Anybody better ideas? Rg, Arnaud -- https://mail.python.org/mailman/listinfo/python-list
return a ctypes object to C
Hi all, I'm trying to wrap my head around the ctypes API. I have a C structure I wish to create in Python and then return from python to C. So a python method is called from C and needs to return an object which we then process in C again. I have a binding to access and create the C methods and structures so in Python I can call the Zmsg() constructor. I now need to return this. My python test method is simply: def actor_test( *args, **kwargs): print("test") msg = Zmsg() frame = Zframe(b"Hello", 5) msg.prepend(frame) return msg the method is called from C as follows: PyObject *pReturn = PyObject_CallObject(pFunc, NULL); This correctly calls the method. However the returned object is of course a PyObject*. The debugger says it's "" PyObject [class] "" [super class] "" [meta type] "" ob_refcnt 1 Py_ssize_t However how I can I get it back to the original C type (zmsg_t *) Any help really appreciated. Rg, Arnaud -- https://mail.python.org/mailman/listinfo/python-list