convert PyInt to C Int - python

i need to convert PyInt to C int. In my code
count=PyInt_FromSsize_t(PyList_Size(pValue))
pValue is a PyObject, PyList. the problem i was having is the PyList_Size is not returning me the correct list size (count is supposed to be 5, but it gave me 6 million), or there is a problem with data types since im in C code interfacing to python scripts. Ideally, i want count to be in a C int type.
i've found python/c APIs that return me long C data types... which is not what i want... anybody can point me to the correct method or APIs??

The PyInt_FromSsize_t() returns a full-fledged Python int object sitting in memory and returns its memory address — that is where the 6-million number is coming from. You just want to get the scalar returned by PyList_Size() and cast it to a C integer, I think:
count = (int) PyList_Size(pValue)
If the list could be very long you might want to think about making count a long instead, in which case you could cast to that specific type instead.
Note: a count of -1 means that Python encountered an exception while trying to measure the list length. Here are the docs you should read to know how to handle exceptions:
http://docs.python.org/c-api/intro.html#exceptions

Related

PyBytes_FromString different endianness

I have a python-wrapped C++ object whose underlying data is a container std::vector<T> that represents bits. I have a function that writes these bits to a PyBytes object. If the endianness is the same, then there is no issue. However if I wish to write the bytes in a different endianness, then I need to bitswap (or byteswap) each word.
Ideally, I could pass an output iterator to the PyBytes_FromString constructor, where the output operator just transforms the endianness of each word. This would be O(1) extra memory, which is the target.
Less ideally, I could somehow construct an empty PyBytes object, create the different-endianness char array manually and somehow assign that to the PyBytes object (basically reimplementing the PyBytes constructors). This would also be O(1) extra memory. Unfortunately, the way to do this would be to use _PyBytes_FromSize, but that's not available in the API.
The current way of doing this is to create an entire copy of the reversed words, just to then copy that representation over to the PyBytes objects representation.
I think the second option is the most practical way of doing this, but the only way I can see that working is by basically copying the _PyBytes_FromSize function into my source code which seems hacky. I'm new to the python-C api and am wondering if there's a cleaner way to do this.
PyBytes_FromStringAndSize lets you pass NULL as the first argument, in which case it returns an uninitialized bytes object (which you can edit). It's really just equivalent to _PyBytes_FromSize and would let you do your second option.
If you wanted to try your "output iterator" option instead, then the solution would be to call PyBytes_Type:
PyObject *result = PyObject_CallFunctionObjArgs((PyObject*)&PyBytes_Type, your_iterable, NULL);
Any iterable that returns values between 0 and 255 should work. You can pick the PyObject_Call* that you find easiest to use.
I suspect writing the iterable in C/C++ will be more trouble than writing the loop though.

Workflow: C pointer to Python array?

I am writing some code in C, which reads data in and stores it in a pointer of type;
uint8_t
This data I now want to make accessible in Python3.
For now I have figured out how to make my C code callable with the help of ctypes and I know it works since I am able to print my data out in the Python terminal, but not able to store it in a variable.
My problem lies in that I do not know how to transform this pointer into an array which can be stored and manipulated in Python, so therefore I ask, if someone has a simple example where they move for an example a 3 by 1 array from C into Python, and then are able to work with it there, it would benefit me a lot.
Okay, so I managed to figure it out, maybe not the smartest way, but atleast it works now. Since I return a pointer of the type, ``` u_int8 * ```` in C, I amble then in Python to use something like this:
g = (ctypes.c_float*5271).from_address(a)
And then g[0], g[:], etc. to get the data etc.

Method expects argument of type 'double *'?

I'm new to python and I'm trying to write some code using python wrappers for epanet which I believe are SWIG-wrapped. There is a method I need to use, as outlined below from the source. However I can't seem to get the method to accept any type of value for the 3rd argument "values:".. Anything I try I get the error: TypeError: in method 'ptrn_set', argument 3 of type 'double *'
How do I convert my value/values to 'double *' within Python? what is the solution?
Thankful for any help...
"""
ptrn_set(ph, index, values, len) -> int
Parameters
----------
ph: Handle
index: int
values: double *
len: int
"""
return _toolkit.ptrn_set(ph, index, values, len)
I found this here:
https://docs.python.org/2.4/lib/typesnumeric.html:
Floating point numbers are implemented using double in C
Did you try float?
Python itself does not support values of type double *. In C, that is a pointer-to-a-double-precision-floating-point-number. In Python, effectively every name is a pointer, but you can't have a (native) value that is a pointer.
From context, it looks like they actually want an array of doubles. They really ought to write that as double [], but double * is compatible with it. You could try
values = [1.0, 2.0]
_toolkit.ptrn_set(ph, index, values, len(values))
It's not very Pythonic to do that, but if it works, it works. If that doesn't work, see if your expanet python wrappers provide a way of constructing such values.
If your expanet Python wrappers don't provide a way to construct such values, you can try the cffi library, but it's quite tricky. I think x = ffi.new("double[10]") will give you an array of 10 doubles.
I know some time passed an you probably already solved it, but it might be useful for someone else.
you can use the following function to create an array that will be accepted by epanet:
def make_array(values):
dbl_arr = en.doubleArray(len(values))
for i in range(len(values)):
dbl_arr[i] = values[i]
return dbl_arr
the input is an array of float, like [1.2 , 0.8].
This assuming you imported the epanet python library as
from epanet import toolkit as en,
source: https://github.com/OpenWaterAnalytics/epanet-python/issues/57

How can I identify numpy's integer type?

What is the simplest way to identify whether a data point in numpy's array is an integer? Currently I use numpy.dtype(x[i]).type to return the type of the element i of array x and then
`if numpy.dtype(x[i]).type is numpy.int*`
to achieve this, where * can be 8, 32 or 64. But it may also return uint, thus this if way can return False. I wonder whether there exists a simple way to identify whether it is an integer, regardless of the exact int type is. And how about float?
this might help (this effectively tests for a signed integer, in a similar fashion 'u' would be unsigned integer, etc.):
x[i].dtype.kind == 'i'
You can use:
issubdtype(var, type)
Usage:
numpy.issubdtype(var_to_check, np.integer)
More information here How to determine if a number is any type of int (core or numpy, signed or not)?
Use either:
issubclass(x[i].dtype.type, np.integer)
or
np.issubdtype(x[i].dtype, np.integer)
Your code of np.dtype(x) is unlikely to do what you want - that doesn't get the dtype of x, but tries to interpret x as a description of a new dtype. If you have a possibly non-numpy object you want a dtype of, you can use np.asanyarray(x).dtype

c_int members of python ctypes struct are just ints?

I'm trying to make an 11-bit ID field for a CAN communication channel. I think I should be able to use:
import ctypes
class ID(ctypes.Union):
_fields_ = [('device', ctypes.c_int, 3), # 3 bits for device id
('message', ctypes.c_int, 8)] # 8 bits for message ID
The issue is what happens when I try to validate that an instance of this class is what I wanted. Specifically:
>>> x = ID()
>>> type(x.device)
<type 'int'>
Why is that an int and not a c_int? Likewise:
>>> x = ID()
>>> x.device.bit_length()
0
which is precisely what I didn't want.
EDIT:
Thanks for the help! I should definitely be using a struct.
I'm trying to make an object that represents the identifier and data sections of a CAN data frame. The convention I'm working with further divides the identifier frame into 3- and 8-bit segments, representing the device and message ID, respectively. what I'd like is a class representing the identifier frame, in which I can assign values to members corresponding to my convention's device and message IDs, and which serializes into an 11-bit ID value.
Maybe I need to take another look at the C library I'm using for the CAN channel--it may be that I can use a 16-bit struct of which I only use 11 bits.
Inside the Union, the device member is stored using 8 bits.
However, ctypes will automatically convert back and forth to native int types for you, using (a good approximation of) the usual C rules for converting between types. For example, try this:
>>> x.device = 257
>>> x.device
1
So, you don't have anything to fix here.
However, you do have a problem:
I'm trying to make an 11-bit ID field for a CAN communication channel.
A Union of an 8-bit int and a 3-bit int is 8 bits, just as in C. You want a Struct. See Structures and unions and the type references linked from there for details.
On top of that, while a Struct of a 3-bit int and an 8-bit int only has 11 bits of useful information, it will almost certainly take up at least 16 bits of memory, with 5 bits of padding.* You can only address memory a byte (8 bits) at a time. So… I'm not sure exactly what you were trying to do with this ID, but I suspect it's not going to work. If you explain your actual problem, ideally with some complete sample code, we can probably help.
* In fact, at least in current CPython versions, it will actually take up 32 bits of memory. See eryksun's comments for more details.

Categories

Resources