8000 BUG: Cannot convert ctypes struct into numpy array · Issue #10528 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

BUG: Cannot convert ctypes struct into numpy array #10528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By 8000 clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
eric-wieser opened this issue Feb 6, 2018 · 1 comment · Fixed by python/cpython#5561
Closed

BUG: Cannot convert ctypes struct into numpy array #10528

eric-wieser opened this issue Feb 6, 2018 · 1 comment · Fixed by python/cpython#5561

Comments

@eric-wieser
Copy link
Member
eric-wieser commented Feb 6, 2018

This seems like a bug inherited from ctypes, so maybe we need a workaround:

Start off with a very simple struct:

class foo(ctypes.Structure):
    _fields_ = [('a', ctypes.c_uint8), ('b', ctypes.c_uint32)]
f = foo()

We'd expect this to insert padding, and it does:

>>> memoryview(f).itemsize  # ok
8

But that padding doesn't show up in the format string:

>>> memoryview(f).format
'T{<B:a:<I:b:}'

The docs for struct say that

No padding is added when using non-native size and alignment, e.g. with ‘<’, ‘>’ "

So this format has size 5, which contradicts itemsize.

Sure enough, we catch this in our PEP3118 parser:

>>> np.array(f)
RuntimeWarning: Item size computed from the PEP 3118 buffer format string does not match the actual item size.
Out[45]: array(<__main__.foo object at 0x7f2715469bf8>, dtype=object)

I suspect there's already an issue for this - perhaps we need a PEP3118 tag.

The fix would be to special case ctypes objects in the array constructor, and not call memoryview on them because it doesn't actually work.


Worse yet, numpy doesn't stand a chance with an unpadded struct:

class foo(ctypes.Structure):
    _fields_ = [('a', ctypes.c_uint8), ('b', ctypes.c_uint32)]
    _pack_ = 1
f = foo()
>>> memoryview(f).itemsize  # ok
5
>>> memoryview(f).format  # WAT
'B'
@eric-wieser
Copy link
Member Author

Bug filed at https://bugs.python.org/issue32780, patch at python/cpython#5561. cc @ahaldane, since you've found PEP3118 to be vague in the past.

eric-wieser added a commit to eric-wieser/numpy that referenced this issue Jun 8, 2018
…ype(ctype_obj))

Fixes numpygh-10528
Fixes numpygh-10978
Fixes numpygh-11150

A warning is thrown when ctypes misbehaves, in order to not hide issues that need fixing upstream
mdickinson pushed a commit to python/cpython that referenced this issue Feb 5, 2023
The summary of this diff is that it:

* adds a `_ctypes_alloc_format_padding` function to append strings like `37x` to a format string to indicate 37 padding bytes
* removes the branches that amount to "give up on producing a valid format string if the struct is packed"
* combines the resulting adjacent `if (isStruct) {`s now that neither is `if (isStruct && !isPacked) {`
* invokes `_ctypes_alloc_format_padding` to add padding between structure fields, and after the last structure field. The computation used for the total size is unchanged from ctypes already used.

This patch does not affect any existing aligment computation; all it does is use subtraction to deduce the amount of paddnig introduced by the existing code.

---

Without this fix, it would never include padding bytes - an assumption that was only
valid in the case when `_pack_` was set - and this case was explicitly not implemented.

This should allow conversion from ctypes structs to numpy structs

Fixes numpy/numpy#10528
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
3CF8
None yet
Development

Successfully merging a pull request may close this issue.

1 participant
0