FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

bpo-46417: Add _PyType_GetSubclasses() function by vstinner · Pull Request #30761 · python/cpython · GitHub

/ cpython Public
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .c  (2) .h  (1) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
11 changes: 6 additions & 5 deletions Include/internal/pycore_object.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,12 @@ static inline PyObject **_PyObject_ManagedDictPointer(PyObject *obj)
return ((PyObject **)obj)-3;
}

PyObject ** _PyObject_DictPointer(PyObject *);
int _PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg);
void _PyObject_ClearInstanceAttributes(PyObject *self);
void _PyObject_FreeInstanceAttributes(PyObject *self);
int _PyObject_IsInstanceDictEmpty(PyObject *);
extern PyObject ** _PyObject_DictPointer(PyObject *);
extern int _PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg);
extern void _PyObject_ClearInstanceAttributes(PyObject *self);
extern void _PyObject_FreeInstanceAttributes(PyObject *self);
extern int _PyObject_IsInstanceDictEmpty(PyObject *);
extern PyObject* _PyType_GetSubclasses(PyTypeObject *);

#ifdef __cplusplus
}
Expand Down
18 changes: 9 additions & 9 deletions Modules/_abc.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#endif

#include "Python.h"
#include "pycore_object.h" // _PyType_GetSubclasses()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "clinic/_abc.c.h"

Expand Down Expand Up @@ -493,21 +494,20 @@ set_collection_flag_recursive(PyTypeObject *child, unsigned long flag)
{
return;
}

child->tp_flags &= ~COLLECTION_FLAGS;
child->tp_flags |= flag;
PyObject *grandchildren = child->tp_subclasses;

PyObject *grandchildren = _PyType_GetSubclasses(child);
if (grandchildren == NULL) {
return;
}
assert(PyDict_CheckExact(grandchildren));
Py_ssize_t i = 0;
while (PyDict_Next(grandchildren, &i, NULL, &grandchildren)) {
assert(PyWeakref_CheckRef(grandchildren));
PyObject *grandchild = PyWeakref_GET_OBJECT(grandchildren);
if (PyType_Check(grandchild)) {
set_collection_flag_recursive((PyTypeObject *)grandchild, flag);
}

for (Py_ssize_t i = 0; i < PyList_GET_SIZE(grandchildren); i++) {
PyObject *grandchild = PyList_GET_ITEM(grandchildren, i);
set_collection_flag_recursive((PyTypeObject *)grandchild, flag);
}
Py_DECREF(grandchildren);
}

/*[clinic input]
Expand Down
100 changes: 60 additions & 40 deletions Objects/typeobject.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -687,27 +687,28 @@ static int recurse_down_subclasses(PyTypeObject *type, PyObject *name,
static int
mro_hierarchy(PyTypeObject *type, PyObject *temp)
{
int res;
PyObject *new_mro, *old_mro;
PyObject *tuple;
PyObject *subclasses;
Py_ssize_t i, n;

res = mro_internal(type, &old_mro);
if (res <= 0)
PyObject *old_mro;
int res = mro_internal(type, &old_mro);
if (res <= 0) {
/* error / reentrance */
return res;
new_mro = type->tp_mro;
}
PyObject *new_mro = type->tp_mro;

if (old_mro != NULL)
PyObject *tuple;
if (old_mro != NULL) {
tuple = PyTuple_Pack(3, type, new_mro, old_mro);
else
}
else {
tuple = PyTuple_Pack(2, type, new_mro);
}

if (tuple != NULL)
if (tuple != NULL) {
res = PyList_Append(temp, tuple);
else
}
else {
res = -1;
}
Py_XDECREF(tuple);

if (res < 0) {
Expand All @@ -727,15 +728,18 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
Finally, this makes things simple avoiding the need to deal
with dictionary iterators and weak references.
*/
subclasses = type___subclasses___impl(type);
if (subclasses == NULL)
PyObject *subclasses = _PyType_GetSubclasses(type);
if (subclasses == NULL) {
return -1;
n = PyList_GET_SIZE(subclasses);
for (i = 0; i < n; i++) {
}

Py_ssize_t n = PyList_GET_SIZE(subclasses);
for (Py_ssize_t i = 0; i < n; i++) {
PyTypeObject *subclass = _PyType_CAST(PyList_GET_ITEM(subclasses, i));
res = mro_hierarchy(subclass, temp);
if (res < 0)
if (res < 0) {
break;
}
}
Py_DECREF(subclasses);

Expand Down Expand Up @@ -4124,6 +4128,42 @@ type_dealloc(PyTypeObject *type)
Py_TYPE(type)->tp_free((PyObject *)type);
}


PyObject*
_PyType_GetSubclasses(PyTypeObject *self)
{
PyObject *list = PyList_New(0);
if (list == NULL) {
return NULL;
}

// Hold a strong reference to tp_subclasses while iterating on it
PyObject *dict = Py_XNewRef(self->tp_subclasses);
if (dict == NULL) {
return list;
}
assert(PyDict_CheckExact(dict));

Py_ssize_t i = 0;
PyObject *ref; // borrowed ref
while (PyDict_Next(dict, &i, NULL, &ref)) {
assert(PyWeakref_CheckRef(ref));
PyObject *obj = PyWeakref_GET_OBJECT(ref); // borrowed ref
if (obj == Py_None) {
continue;
}
assert(PyType_Check(obj));
if (PyList_Append(list, obj) < 0) {
Py_CLEAR(list);
goto done;
}
}
done:
Py_DECREF(dict);
return list;
}


/*[clinic input]
type.__subclasses__

Expand All @@ -4134,28 +4174,7 @@ static PyObject *
type___subclasses___impl(PyTypeObject *self)
/*[clinic end generated code: output=eb5eb54485942819 input=5af66132436f9a7b]*/
{
PyObject *list, *raw, *ref;
Py_ssize_t i;

list = PyList_New(0);
if (list == NULL)
return NULL;
raw = self->tp_subclasses;
if (raw == NULL)
return list;
assert(PyDict_CheckExact(raw));
i = 0;
while (PyDict_Next(raw, &i, NULL, &ref)) {
assert(PyWeakref_CheckRef(ref));
ref = PyWeakref_GET_OBJECT(ref);
if (ref != Py_None) {
if (PyList_Append(list, ref) < 0) {
Py_DECREF(list);
return NULL;
}
}
}
return list;
return _PyType_GetSubclasses(self);
}

static PyObject *
Expand All @@ -4165,6 +4184,7 @@ type_prepare(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
return PyDict_New();
}


/*
Merge the __dict__ of aclass into dict, and recursively also all
the __dict__s of aclass's base classes. The order of merging isn't
Expand Down

Back | FazBrowse Home | New Git URL