File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -36,6 +36,8 @@ typedef struct _frame {
3636 non-generator frames. See the save_exc_state and swap_exc_state
3737 functions in ceval.c for details of their use. */
3838 PyObject * f_exc_type , * f_exc_value , * f_exc_traceback ;
39+ /* Borrowed referenced to a generator, or NULL */
40+ PyObject * f_gen ;
3941
4042 PyThreadState * f_tstate ;
4143 int f_lasti ; /* Last instruction if called */
@@ -84,6 +86,13 @@ PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
8486/* Return the line of code the frame is currently executing. */
8587PyAPI_FUNC (int ) PyFrame_GetLineNumber (PyFrameObject * );
8688
89+ /* Generator support */
90+ PyAPI_FUNC (PyObject * ) _PyFrame_YieldingFrom (PyFrameObject * );
91+ PyAPI_FUNC (PyObject * ) _PyFrame_GeneratorSend (PyFrameObject * , PyObject * , int exc );
92+ PyAPI_FUNC (PyObject * ) _PyFrame_Finalize (PyFrameObject * );
93+ PyAPI_FUNC (int ) _PyFrame_CloseIterator (PyObject * );
94+
95+
8796#ifdef __cplusplus
8897}
8998#endif
Original file line number Diff line number Diff line change @@ -33,6 +33,7 @@ PyAPI_DATA(PyTypeObject) PyGen_Type;
3333#define PyGen_CheckExact (op ) (Py_TYPE(op) == &PyGen_Type)
3434
3535PyAPI_FUNC (PyObject * ) PyGen_New (struct _frame * );
36+ /* Deprecated, kept for backwards compatibility. */
3637PyAPI_FUNC (int ) PyGen_NeedsFinalizing (PyGenObject * );
3738PyAPI_FUNC (int ) _PyGen_FetchStopIterationValue (PyObject * * );
3839PyObject * _PyGen_Send (PyGenObject * , PyObject * );
Original file line number Diff line number Diff line change 1+ import gc
2+ import sys
3+ import unittest
4+ import weakref
5+
6+ from test import support
7+
8+
9+ class FinalizationTest (unittest .TestCase ):
10+
11+ def test_frame_resurrect (self ):
12+ # A generator frame can be resurrected by a generator's finalization.
13+ def gen ():
14+ nonlocal frame
15+ try :
16+ yield
17+ finally :
18+ frame = sys ._getframe ()
19+
20+ g = gen ()
21+ wr = weakref .ref (g )
22+ next (g )
23+ del g
24+ support .gc_collect ()
25+ self .assertIs (wr (), None )
26+ self .assertTrue (frame )
27+ del frame
28+ support .gc_collect ()
29+
30+ def test_refcycle (self ):
31+ # A generator caught in a refcycle gets finalized anyway.
32+ old_garbage = gc .garbage [:]
33+ finalized = False
34+ def gen ():
35+ nonlocal finalized
36+ try :
37+ g = yield
38+ yield 1
39+ finally :
40+ finalized = True
41+
42+ g = gen ()
43+ next (g )
44+ g .send (g )
45+ self .assertGreater (sys .getrefcount (g ), 2 )
46+ self .assertFalse (finalized )
47+ del g
48+ support .gc_collect ()
49+ self .assertTrue (finalized )
50+ self .assertEqual (gc .garbage , old_garbage )
51+
52+
153tutorial_tests = """
254Let's try a simple generator:
355
@@ -1880,6 +1932,7 @@ def printsolution(self, x):
18801932# so this works as expected in both ways of running regrtest.
18811933def test_main (verbose = None ):
18821934 from test import support , test_generators
1935+ support .run_unittest (__name__ )
18831936 support .run_doctest (test_generators , verbose )
18841937
18851938# This part isn't needed for regrtest, but for running the test directly.
Original file line number Diff line number Diff line change @@ -764,7 +764,7 @@ class C(object): pass
764764 nfrees = len (x .f_code .co_freevars )
765765 extras = x .f_code .co_stacksize + x .f_code .co_nlocals + \
766766 ncells + nfrees - 1
767- check (x , vsize ('12P3i ' + CO_MAXBLOCKS * '3i' + 'P' + extras * 'P' ))
767+ check (x , vsize ('13P3i ' + CO_MAXBLOCKS * '3i' + 'P' + extras * 'P' ))
768768 # function
769769 def func (): pass
770770 check (func , size ('12P' ))
Original file line number Diff line number Diff line change @@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
1010Core and Builtins
1111-----------------
1212
13+ - Issue #17807: Generators can now be finalized even when they are part of
14+ a reference cycle.
15+
1316- Issue #1545463: At shutdown, defer finalization of codec modules so
1417 that stderr remains usable.
1518
Original file line number Diff line number Diff line change @@ -524,10 +524,7 @@ untrack_dicts(PyGC_Head *head)
524524static int
525525has_finalizer (PyObject * op )
526526{
527- if (PyGen_CheckExact (op ))
528- return PyGen_NeedsFinalizing ((PyGenObject * )op );
529- else
530- return op -> ob_type -> tp_del != NULL ;
527+ return op -> ob_type -> tp_del != NULL ;
531528}
532529
533530/* Move the objects in unreachable with __del__ methods into `finalizers`.
You can’t perform that action at this time.
0 commit comments