Skip to content

Commit 175421b

Browse files
pablogsalmethane
authored andcommitted
bpo-36016: Add generation option to gc.getobjects() (GH-11909)
1 parent df5cdc1 commit 175421b

File tree

6 files changed

+112
-14
lines changed

6 files changed

+112
-14
lines changed

Doc/library/gc.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,14 @@ The :mod:`gc` module provides the following functions:
6363
Return the debugging flags currently set.
6464

6565

66-
.. function:: get_objects()
66+
.. function:: get_objects(generation=None)
6767

6868
Returns a list of all objects tracked by the collector, excluding the list
69-
returned.
69+
returned. If *generation* is not None, return only the objects tracked by
70+
the collector that are in that generation.
7071

72+
.. versionchanged:: 3.8
73+
New *generation* parameter.
7174

7275
.. function:: get_stats()
7376

Doc/whatsnew/3.8.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,15 @@ gettext
163163
Added :func:`~gettext.pgettext` and its variants.
164164
(Contributed by Franz Glasner, Éric Araujo, and Cheryl Sabella in :issue:`2504`.)
165165

166+
167+
gc
168+
--
169+
170+
:func:`~gc.get_objects` can now receive an optional *generation* parameter
171+
indicating a generation to get objects from. Contributed in
172+
:issue:`36016` by Pablo Galindo.
173+
174+
166175
gzip
167176
----
168177

Lib/test/test_gc.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,38 @@ def test_freeze(self):
766766
gc.unfreeze()
767767
self.assertEqual(gc.get_freeze_count(), 0)
768768

769+
def test_get_objects(self):
770+
gc.collect()
771+
l = []
772+
l.append(l)
773+
self.assertIn(l, gc.get_objects(generation=0))
774+
self.assertNotIn(l, gc.get_objects(generation=1))
775+
self.assertNotIn(l, gc.get_objects(generation=2))
776+
gc.collect(generation=0)
777+
self.assertNotIn(l, gc.get_objects(generation=0))
778+
self.assertIn(l, gc.get_objects(generation=1))
779+
self.assertNotIn(l, gc.get_objects(generation=2))
780+
gc.collect(generation=1)
781+
self.assertNotIn(l, gc.get_objects(generation=0))
782+
self.assertNotIn(l, gc.get_objects(generation=1))
783+
self.assertIn(l, gc.get_objects(generation=2))
784+
gc.collect(generation=2)
785+
self.assertNotIn(l, gc.get_objects(generation=0))
786+
self.assertNotIn(l, gc.get_objects(generation=1))
787+
self.assertIn(l, gc.get_objects(generation=2))
788+
del l
789+
gc.collect()
790+
791+
def test_get_objects_arguments(self):
792+
gc.collect()
793+
self.assertEqual(len(gc.get_objects()),
794+
len(gc.get_objects(generation=None)))
795+
796+
self.assertRaises(ValueError, gc.get_objects, 1000)
797+
self.assertRaises(ValueError, gc.get_objects, -1000)
798+
self.assertRaises(TypeError, gc.get_objects, "1")
799+
self.assertRaises(TypeError, gc.get_objects, 1.234)
800+
769801

770802
class GCCallbackTests(unittest.TestCase):
771803
def setUp(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
``gc.get_objects`` can now receive an optional parameter indicating a
2+
generation to get objects from. Patch by Pablo Galindo.

Modules/clinic/gcmodule.c.h

Lines changed: 25 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/gcmodule.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,27 +1502,61 @@ gc_get_referents(PyObject *self, PyObject *args)
15021502

15031503
/*[clinic input]
15041504
gc.get_objects
1505+
generation: Py_ssize_t(accept={int, NoneType}, c_default="-1") = None
1506+
Generation to extract the objects from.
15051507
15061508
Return a list of objects tracked by the collector (excluding the list returned).
1509+
1510+
If generation is not None, return only the objects tracked by the collector
1511+
that are in that generation.
15071512
[clinic start generated code]*/
15081513

15091514
static PyObject *
1510-
gc_get_objects_impl(PyObject *module)
1511-
/*[clinic end generated code: output=fcb95d2e23e1f750 input=9439fe8170bf35d8]*/
1515+
gc_get_objects_impl(PyObject *module, Py_ssize_t generation)
1516+
/*[clinic end generated code: output=48b35fea4ba6cb0e input=ef7da9df9806754c]*/
15121517
{
15131518
int i;
15141519
PyObject* result;
15151520

15161521
result = PyList_New(0);
1517-
if (result == NULL)
1522+
if (result == NULL) {
15181523
return NULL;
1524+
}
1525+
1526+
/* If generation is passed, we extract only that generation */
1527+
if (generation != -1) {
1528+
if (generation >= NUM_GENERATIONS) {
1529+
PyErr_Format(PyExc_ValueError,
1530+
"generation parameter must be less than the number of "
1531+
"available generations (%i)",
1532+
NUM_GENERATIONS);
1533+
goto error;
1534+
}
1535+
1536+
if (generation < 0) {
1537+
PyErr_SetString(PyExc_ValueError,
1538+
"generation parameter cannot be negative");
1539+
goto error;
1540+
}
1541+
1542+
if (append_objects(result, GEN_HEAD(generation))) {
1543+
goto error;
1544+
}
1545+
1546+
return result;
1547+
}
1548+
1549+
/* If generation is not passed or None, get all objects from all generations */
15191550
for (i = 0; i < NUM_GENERATIONS; i++) {
15201551
if (append_objects(result, GEN_HEAD(i))) {
1521-
Py_DECREF(result);
1522-
return NULL;
1552+
goto error;
15231553
}
15241554
}
15251555
return result;
1556+
1557+
error:
1558+
Py_DECREF(result);
1559+
return NULL;
15261560
}
15271561

15281562
/*[clinic input]

0 commit comments

Comments
 (0)