Re: return a ctypes object to C

2019-11-07 Thread Arnaud Loonstra

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

2019-10-31 Thread Eryk Sun
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

2019-10-31 Thread Arnaud Loonstra

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

2019-10-31 Thread Thomas Jollans
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

2019-10-31 Thread Arnaud Loonstra

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

2019-10-30 Thread Arnaud Loonstra

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