self.assertEqual(func(None), None)
self.assertEqual(func(input=None), None)
+ def test_invalid_paramflags(self):
+ proto = CFUNCTYPE(c_int, c_char_p)
+ with self.assertRaises(ValueError):
+ func = proto(("myprintf", testdll), ((1, "fmt"), (1, "arg1")))
+
+ def test_invalid_setattr_argtypes(self):
+ proto = CFUNCTYPE(c_int, c_char_p)
+ func = proto(("myprintf", testdll), ((1, "fmt"),))
+
+ with self.assertRaisesRegex(TypeError, "_argtypes_ must be a sequence of types"):
+ func.argtypes = 123
+ self.assertEqual(func.argtypes, (c_char_p,))
+
+ with self.assertRaisesRegex(ValueError, "paramflags must have the same length as argtypes"):
+ func.argtypes = (c_char_p, c_int)
+ self.assertEqual(func.argtypes, (c_char_p,))
+
+ def test_paramflags_outarg(self):
+ proto = CFUNCTYPE(c_int, c_char_p, c_int)
+ with self.assertRaisesRegex(TypeError, "must be a pointer type"):
+ func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out")))
+
+ proto = CFUNCTYPE(c_int, c_char_p, c_void_p)
+ func = proto(("myprintf", testdll), ((1, "fmt"), (2, "out")))
+ with self.assertRaisesRegex(TypeError, "must be a pointer type"):
+ func.argtypes = (c_char_p, c_int)
def test_int_pointer_arg(self):
func = testdll._testfunc_p_p
PyCFuncPtr_Type
*/
+static int
+_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes);
+
static int
PyCFuncPtr_set_errcheck(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
{
}
static int
-PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ignored))
+PyCFuncPtr_set_argtypes(PyCFuncPtrObject *self, PyObject *value, void *Py_UNUSED(ignored))
{
- PyObject *converters;
-
- if (ob == NULL || ob == Py_None) {
+ if (value == NULL || value == Py_None) {
Py_CLEAR(self->converters);
Py_CLEAR(self->argtypes);
} else {
- ctypes_state *st = get_module_state_by_def(Py_TYPE(Py_TYPE(self)));
- converters = converters_from_argtypes(st, ob);
+ PyTypeObject *type = Py_TYPE(self);
+ ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
+ PyObject *converters = converters_from_argtypes(st, value);
if (!converters)
return -1;
+
+ /* Verify paramflags again due to constraints with argtypes */
+ if (!_validate_paramflags(st, type, self->paramflags, value)) {
+ Py_DECREF(converters);
+ return -1;
+ }
Py_XSETREF(self->converters, converters);
- Py_INCREF(ob);
- Py_XSETREF(self->argtypes, ob);
+ Py_INCREF(value);
+ Py_XSETREF(self->argtypes, value);
}
return 0;
}
/* Returns 1 on success, 0 on error */
static int
-_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags)
+_validate_paramflags(ctypes_state *st, PyTypeObject *type, PyObject *paramflags, PyObject *argtypes)
{
Py_ssize_t i, len;
- PyObject *argtypes;
StgInfo *info;
if (PyStgInfo_FromType(st, (PyObject *)type, &info) < 0) {
"abstract class");
return 0;
}
- argtypes = info->argtypes;
+ if (argtypes == NULL) {
+ argtypes = info->argtypes;
+ }
- if (paramflags == NULL || info->argtypes == NULL)
+ if (paramflags == NULL || argtypes == NULL) {
return 1;
+ }
if (!PyTuple_Check(paramflags)) {
PyErr_SetString(PyExc_TypeError,
}
len = PyTuple_GET_SIZE(paramflags);
- if (len != PyTuple_GET_SIZE(info->argtypes)) {
+ if (len != PyTuple_GET_SIZE(argtypes)) {
PyErr_SetString(PyExc_ValueError,
"paramflags must have the same length as argtypes");
return 0;
#endif
#undef USE_DLERROR
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
- if (!_validate_paramflags(st, type, paramflags)) {
+ if (!_validate_paramflags(st, type, paramflags, NULL)) {
Py_DECREF(ftuple);
return NULL;
}
paramflags = NULL;
ctypes_state *st = get_module_state_by_def(Py_TYPE(type));
- if (!_validate_paramflags(st, type, paramflags)) {
+ if (!_validate_paramflags(st, type, paramflags, NULL)) {
return NULL;
}
self = (PyCFuncPtrObject *)generic_pycdata_new(st, type, args, kwds);