Author: thomas.heller Date: Thu Jan 17 19:46:55 2008 New Revision: 60023 Modified: python/branches/py3k/ (props changed) python/branches/py3k/Lib/ctypes/__init__.py python/branches/py3k/Lib/ctypes/test/test_arrays.py python/branches/py3k/Lib/ctypes/test/test_structures.py python/branches/py3k/Modules/_ctypes/_ctypes.c python/branches/py3k/Modules/_ctypes/cfield.c Log: Merged revisions 60001,60003-60004,60008 via svnmerge from svn+ssh://[EMAIL PROTECTED]/python/trunk
........ r60001 | thomas.heller | 2008-01-16 20:16:27 +0100 (Mi, 16 Jan 2008) | 3 lines Convert the internal ctypes array type cache to a WeakValueDict so that array types do not live longer than needed. ........ r60003 | thomas.heller | 2008-01-16 20:37:33 +0100 (Mi, 16 Jan 2008) | 3 lines Raise a TypeError if conflicting positional and named arguments are passed to a Structure or Union constructor. ........ r60004 | thomas.heller | 2008-01-16 20:45:51 +0100 (Mi, 16 Jan 2008) | 3 lines Raise a TypeError instead of a ValueError when too many initializers are used in a Structure or Union constructor. ........ r60008 | thomas.heller | 2008-01-16 21:34:37 +0100 (Mi, 16 Jan 2008) | 3 lines Use 'g' instead of 'D' as the ctypes typecode for c_longdouble, for compliance with PEP 3118. ........ Modified: python/branches/py3k/Lib/ctypes/__init__.py ============================================================================== --- python/branches/py3k/Lib/ctypes/__init__.py (original) +++ python/branches/py3k/Lib/ctypes/__init__.py Thu Jan 17 19:46:55 2008 @@ -182,7 +182,7 @@ _check_size(c_double) class c_longdouble(_SimpleCData): - _type_ = "D" + _type_ = "g" if sizeof(c_longdouble) == sizeof(c_double): c_longdouble = c_double Modified: python/branches/py3k/Lib/ctypes/test/test_arrays.py ============================================================================== --- python/branches/py3k/Lib/ctypes/test/test_arrays.py (original) +++ python/branches/py3k/Lib/ctypes/test/test_arrays.py Thu Jan 17 19:46:55 2008 @@ -116,5 +116,19 @@ self.failUnlessEqual(sz[1:4:2], "o") self.failUnlessEqual(sz.value, "foo") + def test_cache(self): + # Array types are cached internally in the _ctypes extension, + # in a WeakValueDictionary. Make sure the array type is + # removed from the cache when the itemtype goes away. This + # test will not fail, but will show a leak in the testsuite. + + # Create a new type: + class my_int(c_int): + pass + # Create a new array type based on it: + t1 = my_int * 1 + t2 = my_int * 1 + self.failUnless(t1 is t2) + if __name__ == '__main__': unittest.main() Modified: python/branches/py3k/Lib/ctypes/test/test_structures.py ============================================================================== --- python/branches/py3k/Lib/ctypes/test/test_structures.py (original) +++ python/branches/py3k/Lib/ctypes/test/test_structures.py Thu Jan 17 19:46:55 2008 @@ -215,6 +215,15 @@ # too long self.assertRaises(ValueError, Person, "1234567", 5) + def test_conflicting_initializers(self): + class POINT(Structure): + _fields_ = [("x", c_int), ("y", c_int)] + # conflicting positional and keyword args + self.assertRaises(TypeError, POINT, 2, 3, x=4) + self.assertRaises(TypeError, POINT, 2, 3, y=4) + + # too many initializers + self.assertRaises(TypeError, POINT, 2, 3, 4) def test_keyword_initializers(self): class POINT(Structure): @@ -305,9 +314,9 @@ self.failUnlessEqual(cls, RuntimeError) if issubclass(Exception, object): self.failUnlessEqual(msg, - "(Phone) <type 'ValueError'>: too many initializers") + "(Phone) <type 'TypeError'>: too many initializers") else: - self.failUnlessEqual(msg, "(Phone) ValueError: too many initializers") + self.failUnlessEqual(msg, "(Phone) TypeError: too many initializers") def get_except(self, func, *args): Modified: python/branches/py3k/Modules/_ctypes/_ctypes.c ============================================================================== --- python/branches/py3k/Modules/_ctypes/_ctypes.c (original) +++ python/branches/py3k/Modules/_ctypes/_ctypes.c Thu Jan 17 19:46:55 2008 @@ -122,6 +122,7 @@ PyObject *PyExc_ArgError; static PyTypeObject Simple_Type; +PyObject *array_types_cache; char *conversion_mode_encoding = NULL; char *conversion_mode_errors = NULL; @@ -1112,7 +1113,7 @@ */ -static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOvtD"; +static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOvtg"; static PyObject * c_wchar_p_from_param(PyObject *type, PyObject *value) @@ -3535,7 +3536,7 @@ if (PyTuple_GET_SIZE(args) > PySequence_Length(fields)) { Py_DECREF(fields); - PyErr_SetString(PyExc_ValueError, + PyErr_SetString(PyExc_TypeError, "too many initializers"); return -1; } @@ -3556,6 +3557,21 @@ return IBUG("_fields_[i][0] failed"); } + if (kwds && PyDict_GetItem(kwds, name)) { + char *field = PyString_AsString(name); + if (field == NULL) { + PyErr_Clear(); + field = "???"; + } + PyErr_Format(PyExc_TypeError, + "duplicate values for field %s", + field); + Py_DECREF(pair); + Py_DECREF(name); + Py_DECREF(fields); + return -1; + } + val = PyTuple_GET_ITEM(args, i); if (-1 == PyObject_SetAttr(self, name, val)) { Py_DECREF(pair); @@ -3977,25 +3993,19 @@ PyObject * CreateArrayType(PyObject *itemtype, Py_ssize_t length) { - static PyObject *cache; PyObject *key; PyObject *result; char name[256]; - if (cache == NULL) { - cache = PyDict_New(); - if (cache == NULL) - return NULL; - } key = Py_BuildValue("(On)", itemtype, length); if (!key) return NULL; - result = PyDict_GetItem(cache, key); + result = PyObject_GetItem(array_types_cache, key); if (result) { - Py_INCREF(result); Py_DECREF(key); return result; - } + } else + PyErr_Clear(); if (!PyType_Check(itemtype)) { PyErr_SetString(PyExc_TypeError, @@ -4021,7 +4031,11 @@ ); if (!result) return NULL; - PyDict_SetItem(cache, key, result); + if (-1 == PyObject_SetItem(array_types_cache, key, result)) { + Py_DECREF(key); + Py_DECREF(result); + return NULL; + } Py_DECREF(key); return result; } @@ -4778,6 +4792,7 @@ init_ctypes(void) { PyObject *m; + PyObject *weakref; /* Note: ob_type is the metatype (the 'type'), defaults to PyType_Type, @@ -4790,6 +4805,16 @@ if (!m) return; + weakref = PyImport_ImportModule("weakref"); + if (weakref == NULL) + return; + array_types_cache = PyObject_CallMethod(weakref, + "WeakValueDictionary", + NULL); + if (array_types_cache == NULL) + return; + Py_DECREF(weakref); + if (PyType_Ready(&PyCArg_Type) < 0) return; Modified: python/branches/py3k/Modules/_ctypes/cfield.c ============================================================================== --- python/branches/py3k/Modules/_ctypes/cfield.c (original) +++ python/branches/py3k/Modules/_ctypes/cfield.c Thu Jan 17 19:46:55 2008 @@ -983,7 +983,7 @@ static PyObject * -D_set(void *ptr, PyObject *value, Py_ssize_t size) +g_set(void *ptr, PyObject *value, Py_ssize_t size) { long double x; @@ -999,7 +999,7 @@ } static PyObject * -D_get(void *ptr, Py_ssize_t size) +g_get(void *ptr, Py_ssize_t size) { long double val; memcpy(&val, ptr, sizeof(long double)); @@ -1630,7 +1630,7 @@ { 'B', B_set, B_get, &ffi_type_uchar}, { 'c', c_set, c_get, &ffi_type_schar}, { 'd', d_set, d_get, &ffi_type_double, d_set_sw, d_get_sw}, - { 'D', D_set, D_get, &ffi_type_longdouble}, + { 'g', g_set, g_get, &ffi_type_longdouble}, { 'f', f_set, f_get, &ffi_type_float, f_set_sw, f_get_sw}, { 'h', h_set, h_get, &ffi_type_sshort, h_set_sw, h_get_sw}, { 'H', H_set, H_get, &ffi_type_ushort, H_set_sw, H_get_sw}, _______________________________________________ Python-3000-checkins mailing list Python-3000-checkins@python.org http://mail.python.org/mailman/listinfo/python-3000-checkins