Index: Lib/ctypes/test/test_arrays.py =================================================================== --- Lib/ctypes/test/test_arrays.py (revision 59887) +++ Lib/ctypes/test/test_arrays.py (working copy) @@ -116,5 +116,36 @@ self.failUnlessEqual(sz[1:4:2], "o") self.failUnlessEqual(sz.value, "foo") + def test_parameter(self): + tp = c_double * 3 + # We can pass 'None' as an Array parameter: the foreign + # function will receive a NULL pointer: + param = tp.from_param(None) + self.failUnlessEqual(None, tp.from_param(None)) + + # We can pass a tuple of the correct size as an Array parameter: + param = tp.from_param((1, 2, 3)) + self.failUnlessEqual(type(param), tp) + + # ValueError: tuple must have exactly 3 items + self.assertRaises(ValueError, lambda: tp.from_param((1, 2))) + + # TypeError: float expected instead of NoneType instance + self.assertRaises(TypeError, lambda: tp.from_param((None, None, None))) + + # Of course, we can also pass an Array instance: + array = tp(1, 2, 3) + param = tp.from_param(array) + self.failUnless(param is array) + + # We can also pass pointers to the array itemtype: + ptr = pointer(c_double(3.14)) + param = tp.from_param(ptr) + self.failUnless(param is ptr) + + # Pointers to other types are not accepted: + self.failUnlessRaises(TypeError, lambda: tp.from_param(pointer(c_float(3.14)))) + + if __name__ == '__main__': unittest.main() Index: Modules/_ctypes/_ctypes.c =================================================================== --- Modules/_ctypes/_ctypes.c (revision 59887) +++ Modules/_ctypes/_ctypes.c (working copy) @@ -1058,6 +1058,55 @@ return (PyObject *)result; } +static PyObject * +ArrayType_from_param(PyObject *type, PyObject *value) +{ + StgDictObject *dict; + + /* Accept None as a NULL pointer */ + if (value == Py_None) { + Py_INCREF(Py_None); + return Py_None; + } + + dict = PyType_stgdict(type); + assert(dict); + + /* Accept a tuple with the correct size */ + if (PyTuple_CheckExact(value)) { + if (dict->length == PyTuple_GET_SIZE(value)) + return PyObject_CallObject(type, value); + PyErr_Format(PyExc_ValueError, +#if (PY_VERSION_HEX < 0x02050000) + "tuple must have exactly %d items", +#else + "tuple must have exactly %zd items", +#endif + dict->length); + return NULL; + } + + /* Accept pointers to the array's item type */ + if (PointerObject_Check(value)) { + StgDictObject *vdict = PyObject_stgdict(value); + if (vdict && PyObject_IsSubclass(dict->proto, vdict->proto)) { + Py_INCREF(value); + return value; + } + } + + /* Other types */ + return CDataType_from_param(type, value); +} + + +static PyMethodDef ArrayType_methods[] = { + { "from_param", ArrayType_from_param, METH_O, from_param_doc }, + { "from_address", CDataType_from_address, METH_O, from_address_doc }, + { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc }, + { NULL, NULL }, +}; + PyTypeObject ArrayType_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_ctypes.ArrayType", /* tp_name */ @@ -1086,7 +1135,7 @@ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - CDataType_methods, /* tp_methods */ + ArrayType_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */