File tree 8 files changed +334
-244
lines changed
8 files changed +334
-244
lines changed Original file line number Diff line number Diff line change @@ -36,6 +36,8 @@ typedef struct _frame {
36
36
non-generator frames. See the save_exc_state and swap_exc_state
37
37
functions in ceval.c for details of their use. */
38
38
PyObject * f_exc_type , * f_exc_value , * f_exc_traceback ;
39
+ /* Borrowed referenced to a generator, or NULL */
40
+ PyObject * f_gen ;
39
41
40
42
PyThreadState * f_tstate ;
41
43
int f_lasti ; /* Last instruction if called */
@@ -84,6 +86,13 @@ PyAPI_FUNC(void) _PyFrame_DebugMallocStats(FILE *out);
84
86
/* Return the line of code the frame is currently executing. */
85
87
PyAPI_FUNC (int ) PyFrame_GetLineNumber (PyFrameObject * );
86
88
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
+
87
96
#ifdef __cplusplus
88
97
}
89
98
#endif
Original file line number Diff line number Diff line change @@ -33,6 +33,7 @@ PyAPI_DATA(PyTypeObject) PyGen_Type;
33
33
#define PyGen_CheckExact (op ) (Py_TYPE(op) == &PyGen_Type)
34
34
35
35
PyAPI_FUNC (PyObject * ) PyGen_New (struct _frame * );
36
+ /* Deprecated, kept for backwards compatibility. */
36
37
PyAPI_FUNC (int ) PyGen_NeedsFinalizing (PyGenObject * );
37
38
PyAPI_FUNC (int ) _PyGen_FetchStopIterationValue (PyObject * * );
38
39
PyObject * _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
+
1
53
tutorial_tests = """
2
54
Let's try a simple generator:
3
55
@@ -1880,6 +1932,7 @@ def printsolution(self, x):
1880
1932
# so this works as expected in both ways of running regrtest.
1881
1933
def test_main (verbose = None ):
1882
1934
from test import support , test_generators
1935
+ support .run_unittest (__name__ )
1883
1936
support .run_doctest (test_generators , verbose )
1884
1937
1885
1938
# 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
764
764
nfrees = len (x .f_code .co_freevars )
765
765
extras = x .f_code .co_stacksize + x .f_code .co_nlocals + \
766
766
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' ))
768
768
# function
769
769
def func (): pass
770
770
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?
10
10
Core and Builtins
11
11
-----------------
12
12
13
+ - Issue #17807: Generators can now be finalized even when they are part of
14
+ a reference cycle.
15
+
13
16
- Issue #1545463: At shutdown, defer finalization of codec modules so
14
17
that stderr remains usable.
15
18
Original file line number Diff line number Diff line change @@ -524,10 +524,7 @@ untrack_dicts(PyGC_Head *head)
524
524
static int
525
525
has_finalizer (PyObject * op )
526
526
{
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 ;
531
528
}
532
529
533
530
/* Move the objects in unreachable with __del__ methods into `finalizers`.
You can’t perform that action at this time.
0 commit comments