mirror of
https://github.com/python/cpython.git
synced 2026-02-05 17:35:34 +00:00
gh-142966: Make ctypes.POINTER.set_type also reset format (GH-142967)
Make the deprecated set_type method resets the format, using the same code as in type initialization. Implementation note: this was done in PyCPointerType_init after calling PyCPointerType_SetProto, but was forgotten after in PyCPointerType_set_type_impl's call to PyCPointerType_SetProto. With this change, setting the format is conceptually part of setting proto (i.e. the pointed-to type). Co-authored-by: AN Long <aisk@users.noreply.github.com>
This commit is contained in:
parent
933540e332
commit
9181d776da
3 changed files with 44 additions and 25 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import ctypes
|
||||
import unittest
|
||||
from ctypes import Structure, POINTER, pointer, c_char_p
|
||||
from ctypes import Structure, POINTER, pointer, c_char_p, c_int
|
||||
|
||||
# String-based "incomplete pointers" were implemented in ctypes 0.6.3 (2003, when
|
||||
# ctypes was an external project). They made obsolete by the current
|
||||
|
|
@ -50,6 +50,29 @@ class cell(Structure):
|
|||
lpcell.set_type(cell)
|
||||
self.assertIs(POINTER(cell), lpcell)
|
||||
|
||||
def test_set_type_updates_format(self):
|
||||
# gh-142966: set_type should update StgInfo.format
|
||||
# to match the element type's format
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
lp = POINTER("node")
|
||||
|
||||
class node(Structure):
|
||||
_fields_ = [("value", c_int)]
|
||||
|
||||
# Get the expected format before set_type
|
||||
node_format = memoryview(node()).format
|
||||
expected_format = "&" + node_format
|
||||
|
||||
lp.set_type(node)
|
||||
|
||||
# Create instance to check format via memoryview
|
||||
n = node(42)
|
||||
p = lp(n)
|
||||
actual_format = memoryview(p).format
|
||||
|
||||
# After set_type, the pointer's format should be "&<element_format>"
|
||||
self.assertEqual(actual_format, expected_format)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Fix :func:`!ctypes.POINTER.set_type` not updating the format string to match the type.
|
||||
|
|
@ -1258,11 +1258,30 @@ PyCPointerType_SetProto(ctypes_state *st, PyObject *self, StgInfo *stginfo, PyOb
|
|||
return -1;
|
||||
}
|
||||
Py_XSETREF(stginfo->proto, Py_NewRef(proto));
|
||||
|
||||
// Set the format string for the pointer type based on element type.
|
||||
// If info->format is NULL, this is a pointer to an incomplete type.
|
||||
// We create a generic format string 'pointer to bytes' in this case.
|
||||
char *new_format = NULL;
|
||||
STGINFO_LOCK(info);
|
||||
if (info->pointer_type == NULL) {
|
||||
Py_XSETREF(info->pointer_type, Py_NewRef(self));
|
||||
}
|
||||
const char *current_format = info->format ? info->format : "B";
|
||||
if (info->shape != NULL) {
|
||||
// pointer to an array: the shape needs to be prefixed
|
||||
new_format = _ctypes_alloc_format_string_with_shape(
|
||||
info->ndim, info->shape, "&", current_format);
|
||||
} else {
|
||||
new_format = _ctypes_alloc_format_string("&", current_format);
|
||||
}
|
||||
PyMem_Free(stginfo->format);
|
||||
stginfo->format = new_format;
|
||||
STGINFO_UNLOCK();
|
||||
|
||||
if (new_format == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1314,35 +1333,11 @@ PyCPointerType_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
return -1;
|
||||
}
|
||||
if (proto) {
|
||||
const char *current_format;
|
||||
if (PyCPointerType_SetProto(st, self, stginfo, proto) < 0) {
|
||||
Py_DECREF(proto);
|
||||
return -1;
|
||||
}
|
||||
StgInfo *iteminfo;
|
||||
if (PyStgInfo_FromType(st, proto, &iteminfo) < 0) {
|
||||
Py_DECREF(proto);
|
||||
return -1;
|
||||
}
|
||||
/* PyCPointerType_SetProto has verified proto has a stginfo. */
|
||||
assert(iteminfo);
|
||||
/* If iteminfo->format is NULL, then this is a pointer to an
|
||||
incomplete type. We create a generic format string
|
||||
'pointer to bytes' in this case. XXX Better would be to
|
||||
fix the format string later...
|
||||
*/
|
||||
current_format = iteminfo->format ? iteminfo->format : "B";
|
||||
if (iteminfo->shape != NULL) {
|
||||
/* pointer to an array: the shape needs to be prefixed */
|
||||
stginfo->format = _ctypes_alloc_format_string_with_shape(
|
||||
iteminfo->ndim, iteminfo->shape, "&", current_format);
|
||||
} else {
|
||||
stginfo->format = _ctypes_alloc_format_string("&", current_format);
|
||||
}
|
||||
Py_DECREF(proto);
|
||||
if (stginfo->format == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue