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 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
memoryview & ctypes: incorrect itemsize for empty array #76963
Comments
Take the following simple structure: class Foo(ctypes.Structure):
_fields_ = [('f', ctypes.uint32_t)] And construct some arrays with it: def get_array_view(N):
return memoryview((Foo * N)()) In most cases, this works as expected, returning the size of one item: >>> get_array_view(10).itemsize
4
>>> get_array_view(1).itemsize
4 But when N=0, it returns the wrong result >>> get_array_view(0).itemsize
0 Which contradicts its >>> get_array_view(0).format
'T{>I:one:}' This causes a downstream problem in numpy: >>> np.array(get_array_view(0))
RuntimeWarning: Item size computed from the PEP 3118 buffer format string does not match the actual item size. |
Pinging, as recommended by https://devguide.python.org/pullrequest/#reviewing. Ideally this and https://bugs.python.org/issue32780 would make the same patch release. |
Pinging again, for lack of a clearer path forward |
This issue is about the itemsize attribute of instances of the built-in memoryview class. Ctypes in only involved in providing format information. Hence the nosy additions. On Win10 with 3.8, ctypes has no uint attributes. Using 'c_int32' instead, I see the same behavior (itemsize 0 for empty structure). About itemsize, https://www.python.org/dev/peps/pep-3118/ says "This is a storage for the itemsize (in bytes) of each element of the shared memory. It is technically un-necessary as it can be obtained using PyBuffer_SizeFromFormat, however an exporter may know this information without parsing the format string and it is necessary to know the itemsize for proper interpretation of striding. Therefore, storing it is more convenient and faster." The first line could be seen as implying that itemsize is undefined if there are no items (and as justifying numbytes/numitems otherwise). The 0 return could be seen as equivalent to a None return from a python-coded function. If so, it is not a bug, and there might be code that would break if it is changed. On the other hand, the next lines imply that itemsize is *usually*, though not necessarily, a cache for PyBuffer_SizeFromFormat. This could be seen as implying that in the absence of other information, the itemsize should be calculated from the format, making 0 a bug. |
This is actually about memoryview.itemsize within ctypes. |
https://docs.python.org/3/library/stdtypes.html#typememoryview
says "itemsize The size in bytes of each element of the memoryview"
Revising the code example to use an empty array:
>>> import array, struct
>>> m = memoryview(array.array('H', [0])
>>> m.itemsize
2
I agree that itemsize should also be non-zero for ctype formats. |
I agree that it is a ctypes issue, itemsize should be equal to struct.calcsize(fmt), which is never 0 for normal PEP-3118 types like the one in the example. [Pedantically, I think that the grammar would allow for an empty record "T{}" that would have itemsize 0 but is of little use inside numpy.] |
I think you mean >>> import array
>>> memoryview(array.array('H', [])).itemsize
2 Your example is an array containing 0, not an empty array - but the conclusion is the same.
This obviously predicates on
It also allows for records of empty arrays, "T{(0)d:data:}". While these are of little use, they _are_ supported by both ctypes and numpy, so we should support them in the PEP-3118 interface used between them. |
Pinging again, now that the patch has undergone a revision with some cleanup thanks to @skrah |
…H-5576) The itemsize returned in a memoryview of a ctypes array is now computed from the item type, instead of dividing the total size by the length and assuming that the length is not zero.
…be 0 (pythonGH-5576) The itemsize returned in a memoryview of a ctypes array is now computed from the item type, instead of dividing the total size by the length and assuming that the length is not zero. (cherry picked from commit 84bc6a4) Co-authored-by: Eric Wieser <[email protected]>
…be 0 (pythonGH-5576) The itemsize returned in a memoryview of a ctypes array is now computed from the item type, instead of dividing the total size by the length and assuming that the length is not zero. (cherry picked from commit 84bc6a4) Co-authored-by: Eric Wieser <[email protected]>
… be 0 (GH-5576) (#100451) gh-76963: PEP3118 itemsize of an empty ctypes array should not be 0 (GH-5576) The itemsize returned in a memoryview of a ctypes array is now computed from the item type, instead of dividing the total size by the length and assuming that the length is not zero. (cherry picked from commit 84bc6a4) Co-authored-by: Eric Wieser <[email protected]>
… be 0 (GH-5576) (GH-100452) gh-76963: PEP3118 itemsize of an empty ctypes array should not be 0 (GH-5576) The itemsize returned in a memoryview of a ctypes array is now computed from the item type, instead of dividing the total size by the length and assuming that the length is not zero. (cherry picked from commit 84bc6a4) Co-authored-by: Eric Wieser <[email protected]>
Thanks for the fix that closed this. @eric-wieser do you remember where this impacted NumPy? I don't see the relevant issue or PR. |
I think the workaround in numpy needs to stay till after #5561 |
The reference in numpy is here: |
eric-wieser mannequin commentedFeb 6, 2018
•
edited by bedevere-bot
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs
The text was updated successfully, but these errors were encountered: