Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0f81ab6

Browse files
committed
Finished implementing gc.get_referrents(): dealt with error and end
cases, wrote docs, added a test.
1 parent fb2ab4d commit 0f81ab6

4 files changed

Lines changed: 58 additions & 7 deletions

File tree

Doc/lib/libgc.tex

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ \section{\module{gc} ---
9999
\versionadded{2.2}
100100
\end{funcdesc}
101101

102+
\begin{funcdesc}{get_referrents}{*objs}
103+
Return a list of objects directly referred to by any of the arguments.
104+
The referrents returned are those objects visited by the arguments'
105+
C-level \cfunction{tp_traverse} methods (if any), and may not be all
106+
objects actually directly reachable. \cfunction{tp_traverse} methods
107+
are supported only by objects that support garbage collection, and are
108+
only required to visit objects that may be involved in a cycle. So,
109+
for example, if an integer is directly reachable from an argument, that
110+
integer object may or may not appear in the result list.
111+
112+
\versionadded{2.3}
113+
\end{funcdesc}
114+
102115
The following variable is provided for read-only access (you can
103116
mutate its value but should not rebind it):
104117

Lib/test/test_gc.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
def expect(actual, expected, name):
66
if actual != expected:
7-
raise TestFailed, "test_%s: actual %d, expected %d" % (
7+
raise TestFailed, "test_%s: actual %r, expected %r" % (
88
name, actual, expected)
99

1010
def expect_nonzero(actual, name):
@@ -304,6 +304,29 @@ def test_boom2():
304304
expect(gc.collect(), 4, "boom2")
305305
expect(len(gc.garbage), garbagelen, "boom2")
306306

307+
def test_get_referrents():
308+
alist = [1, 3, 5]
309+
got = gc.get_referrents(alist)
310+
got.sort()
311+
expect(got, alist, "get_referrents")
312+
313+
atuple = tuple(alist)
314+
got = gc.get_referrents(atuple)
315+
got.sort()
316+
expect(got, alist, "get_referrents")
317+
318+
adict = {1: 3, 5: 7}
319+
expected = [1, 3, 5, 7]
320+
got = gc.get_referrents(adict)
321+
got.sort()
322+
expect(got, expected, "get_referrents")
323+
324+
got = gc.get_referrents([1, 2], {3: 4}, (0, 0, 0))
325+
got.sort()
326+
expect(got, [0, 0] + range(5), "get_referrents")
327+
328+
expect(gc.get_referrents(1, 'a', 4j), [], "get_referrents")
329+
307330
def test_all():
308331
gc.collect() # Delete 2nd generation garbage
309332
run_test("lists", test_list)
@@ -324,6 +347,7 @@ def test_all():
324347
run_test("trashcan", test_trashcan)
325348
run_test("boom", test_boom)
326349
run_test("boom2", test_boom2)
350+
run_test("get_referrents", test_get_referrents)
327351

328352
def test():
329353
if verbose:

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ Core and builtins
4949
Extension modules
5050
-----------------
5151

52+
- New function gc.get_referrents(obj) returns a list of objects
53+
directly referenced by obj. In effect, it exposes what the object's
54+
tp_traverse slot does, and can be helpful when debugging memory
55+
leaks.
56+
5257
- The iconv module has been removed from this release.
5358

5459
- The platform-independent routines for packing floats in IEEE formats

Modules/gcmodule.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -857,12 +857,11 @@ gc_get_referrers(PyObject *self, PyObject *args)
857857
return result;
858858
}
859859

860+
/* Append obj to list; return true if error (out of memory), false if OK. */
860861
static int
861862
referrentsvisit(PyObject *obj, PyObject *list)
862863
{
863-
if (PyList_Append(list, obj) < 0)
864-
return 1;
865-
return 0;
864+
return PyList_Append(list, obj) < 0;
866865
}
867866

868867
PyDoc_STRVAR(gc_get_referrents__doc__,
@@ -874,13 +873,23 @@ gc_get_referrents(PyObject *self, PyObject *args)
874873
{
875874
int i;
876875
PyObject *result = PyList_New(0);
876+
877+
if (result == NULL)
878+
return NULL;
879+
877880
for (i = 0; i < PyTuple_GET_SIZE(args); i++) {
881+
traverseproc traverse;
878882
PyObject *obj = PyTuple_GET_ITEM(args, i);
879-
traverseproc traverse = obj->ob_type->tp_traverse;
880-
if (!traverse)
883+
884+
if (! PyObject_IS_GC(obj))
885+
continue;
886+
traverse = obj->ob_type->tp_traverse;
887+
if (! traverse)
881888
continue;
882-
if (traverse(obj, (visitproc)referrentsvisit, result))
889+
if (traverse(obj, (visitproc)referrentsvisit, result)) {
890+
Py_DECREF(result);
883891
return NULL;
892+
}
884893
}
885894
return result;
886895
}

0 commit comments

Comments
 (0)