Finished implementing gc.get_referrents(): dealt with error and end
cases, wrote docs, added a test.
This commit is contained in:
parent
fb2ab4d5ae
commit
0f81ab6d88
|
@ -99,6 +99,19 @@ objects, call \function{collect()} before calling
|
|||
\versionadded{2.2}
|
||||
\end{funcdesc}
|
||||
|
||||
\begin{funcdesc}{get_referrents}{*objs}
|
||||
Return a list of objects directly referred to by any of the arguments.
|
||||
The referrents returned are those objects visited by the arguments'
|
||||
C-level \cfunction{tp_traverse} methods (if any), and may not be all
|
||||
objects actually directly reachable. \cfunction{tp_traverse} methods
|
||||
are supported only by objects that support garbage collection, and are
|
||||
only required to visit objects that may be involved in a cycle. So,
|
||||
for example, if an integer is directly reachable from an argument, that
|
||||
integer object may or may not appear in the result list.
|
||||
|
||||
\versionadded{2.3}
|
||||
\end{funcdesc}
|
||||
|
||||
The following variable is provided for read-only access (you can
|
||||
mutate its value but should not rebind it):
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import gc
|
|||
|
||||
def expect(actual, expected, name):
|
||||
if actual != expected:
|
||||
raise TestFailed, "test_%s: actual %d, expected %d" % (
|
||||
raise TestFailed, "test_%s: actual %r, expected %r" % (
|
||||
name, actual, expected)
|
||||
|
||||
def expect_nonzero(actual, name):
|
||||
|
@ -304,6 +304,29 @@ def test_boom2():
|
|||
expect(gc.collect(), 4, "boom2")
|
||||
expect(len(gc.garbage), garbagelen, "boom2")
|
||||
|
||||
def test_get_referrents():
|
||||
alist = [1, 3, 5]
|
||||
got = gc.get_referrents(alist)
|
||||
got.sort()
|
||||
expect(got, alist, "get_referrents")
|
||||
|
||||
atuple = tuple(alist)
|
||||
got = gc.get_referrents(atuple)
|
||||
got.sort()
|
||||
expect(got, alist, "get_referrents")
|
||||
|
||||
adict = {1: 3, 5: 7}
|
||||
expected = [1, 3, 5, 7]
|
||||
got = gc.get_referrents(adict)
|
||||
got.sort()
|
||||
expect(got, expected, "get_referrents")
|
||||
|
||||
got = gc.get_referrents([1, 2], {3: 4}, (0, 0, 0))
|
||||
got.sort()
|
||||
expect(got, [0, 0] + range(5), "get_referrents")
|
||||
|
||||
expect(gc.get_referrents(1, 'a', 4j), [], "get_referrents")
|
||||
|
||||
def test_all():
|
||||
gc.collect() # Delete 2nd generation garbage
|
||||
run_test("lists", test_list)
|
||||
|
@ -324,6 +347,7 @@ def test_all():
|
|||
run_test("trashcan", test_trashcan)
|
||||
run_test("boom", test_boom)
|
||||
run_test("boom2", test_boom2)
|
||||
run_test("get_referrents", test_get_referrents)
|
||||
|
||||
def test():
|
||||
if verbose:
|
||||
|
|
|
@ -49,6 +49,11 @@ Core and builtins
|
|||
Extension modules
|
||||
-----------------
|
||||
|
||||
- New function gc.get_referrents(obj) returns a list of objects
|
||||
directly referenced by obj. In effect, it exposes what the object's
|
||||
tp_traverse slot does, and can be helpful when debugging memory
|
||||
leaks.
|
||||
|
||||
- The iconv module has been removed from this release.
|
||||
|
||||
- The platform-independent routines for packing floats in IEEE formats
|
||||
|
|
|
@ -857,12 +857,11 @@ gc_get_referrers(PyObject *self, PyObject *args)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Append obj to list; return true if error (out of memory), false if OK. */
|
||||
static int
|
||||
referrentsvisit(PyObject *obj, PyObject *list)
|
||||
{
|
||||
if (PyList_Append(list, obj) < 0)
|
||||
return 1;
|
||||
return 0;
|
||||
return PyList_Append(list, obj) < 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(gc_get_referrents__doc__,
|
||||
|
@ -874,14 +873,24 @@ gc_get_referrents(PyObject *self, PyObject *args)
|
|||
{
|
||||
int i;
|
||||
PyObject *result = PyList_New(0);
|
||||
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
|
||||
traverseproc traverse;
|
||||
PyObject *obj = PyTuple_GET_ITEM(args, i);
|
||||
traverseproc traverse = obj->ob_type->tp_traverse;
|
||||
|
||||
if (! PyObject_IS_GC(obj))
|
||||
continue;
|
||||
traverse = obj->ob_type->tp_traverse;
|
||||
if (! traverse)
|
||||
continue;
|
||||
if (traverse(obj, (visitproc)referrentsvisit, result))
|
||||
if (traverse(obj, (visitproc)referrentsvisit, result)) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue