Hi, Guido van Rossum wrote: > On Tue, May 27, 2008 at 9:47 AM, Stefan Behnel <[EMAIL PROTECTED]> wrote: >> Could this function get a public interface? I do not think Cython is the only >> case where C code wants to modify a type after its creation, and copying the >> code over seems like a hack to me. >> > I'm fine with giving it a public interface. Please submit a patch with > docs included.
Straight forward patch is attached (against 3.0a5). Works for me in Cython. I thought about a name like "Taint(t)" or "ClearTypeCache(t)", but then went with the coward solution of calling the function PyType_Modified() as it was (almost) named internally. BTW, I noticed that the code in typeobject.c uses "DECREF before set" two times, like this: method_cache[h].version = type->tp_version_tag; method_cache[h].value = res; /* borrowed */ Py_INCREF(name); Py_DECREF(method_cache[h].name); method_cache[h].name = name; During the call to Py_DECREF, the cache content is incorrect, so can't this run into the same problem that Py_CLEAR() aims to solve? I attached a patch for that, too, just in case. Stefan
--- Include/object.h.ORIG 2008-05-27 21:34:30.000000000 +0200 +++ Include/object.h 2008-05-27 21:22:22.000000000 +0200 @@ -428,6 +428,7 @@ PyObject *, PyObject *); PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *); PyAPI_FUNC(unsigned int) PyType_ClearCache(void); +PyAPI_FUNC(void) PyType_Modified(PyTypeObject *); /* Generic operations on objects */ PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); --- Objects/typeobject.c.ORIG 2008-05-27 21:35:05.000000000 +0200 +++ Objects/typeobject.c 2008-05-27 21:33:45.000000000 +0200 @@ -33,7 +33,6 @@ static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP]; static unsigned int next_version_tag = 0; -static void type_modified(PyTypeObject *); unsigned int PyType_ClearCache(void) @@ -48,12 +47,12 @@ } next_version_tag = 0; /* mark all version tags as invalid */ - type_modified(&PyBaseObject_Type); + PyType_Modified(&PyBaseObject_Type); return cur_version_tag; } -static void -type_modified(PyTypeObject *type) +void +PyType_Modified(PyTypeObject *type) { /* Invalidate any cached data for the specified type and all subclasses. This function is called after the base @@ -87,7 +86,7 @@ ref = PyList_GET_ITEM(raw, i); ref = PyWeakref_GET_OBJECT(ref); if (ref != Py_None) { - type_modified((PyTypeObject *)ref); + PyType_Modified((PyTypeObject *)ref); } } } @@ -173,7 +172,7 @@ Py_INCREF(Py_None); } /* mark all version tags as invalid */ - type_modified(&PyBaseObject_Type); + PyType_Modified(&PyBaseObject_Type); return 1; } bases = type->tp_bases; @@ -313,7 +312,7 @@ return -1; } - type_modified(type); + PyType_Modified(type); return PyDict_SetItemString(type->tp_dict, "__module__", value); } @@ -341,7 +340,7 @@ int res = PyDict_SetItemString(type->tp_dict, "__abstractmethods__", value); if (res == 0) { - type_modified(type); + PyType_Modified(type); if (value && PyObject_IsTrue(value)) { type->tp_flags |= Py_TPFLAGS_IS_ABSTRACT; } @@ -1520,7 +1519,7 @@ from the custom MRO */ type_mro_modified(type, type->tp_bases); - type_modified(type); + PyType_Modified(type); return 0; } @@ -5734,7 +5733,7 @@ update_subclasses() recursion below, but carefully: they each have their own conditions on which to stop recursing into subclasses. */ - type_modified(type); + PyType_Modified(type); init_slotdefs(); pp = ptrs; --- Doc/c-api/type.rst.ORIG 2008-05-27 21:35:14.000000000 +0200 +++ Doc/c-api/type.rst 2008-05-27 21:44:20.000000000 +0200 @@ -38,6 +38,13 @@ Clears the internal lookup cache. Return the current version tag. +.. cfunction:: void PyType_Modified(PyTypeObject *type) + + Invalidates the internal lookup cache for the type and all of its + subtypes. This function must be called after any manual + modification of the attributes or base classes of the type. + + .. cfunction:: int PyType_HasFeature(PyObject *o, int feature) Return true if the type object *o* sets the feature *feature*. Type features
--- Objects/typeobject.c.NEW 2008-05-27 22:26:18.000000000 +0200 +++ Objects/typeobject.c 2008-05-27 22:28:55.000000000 +0200 @@ -148,7 +148,7 @@ cannot be done, 1 if Py_TPFLAGS_VALID_VERSION_TAG. */ Py_ssize_t i, n; - PyObject *bases; + PyObject *bases, *tmp; if (PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) return 1; @@ -167,9 +167,10 @@ are borrowed reference */ for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) { method_cache[i].value = NULL; - Py_XDECREF(method_cache[i].name); - method_cache[i].name = Py_None; + tmp = method_cache[i].name; Py_INCREF(Py_None); + method_cache[i].name = Py_None; + Py_XDECREF(tmp); } /* mark all version tags as invalid */ PyType_Modified(&PyBaseObject_Type); @@ -2254,7 +2255,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) { Py_ssize_t i, n; - PyObject *mro, *res, *base, *dict; + PyObject *mro, *res, *base, *dict, *tmp; unsigned int h; if (MCACHE_CACHEABLE_NAME(name) && @@ -2292,9 +2293,10 @@ h = MCACHE_HASH_METHOD(type, name); method_cache[h].version = type->tp_version_tag; method_cache[h].value = res; /* borrowed */ + tmp = method_cache[h].name; Py_INCREF(name); - Py_DECREF(method_cache[h].name); method_cache[h].name = name; + Py_DECREF(tmp); } return res; }
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com