@@ -506,4 +506,83 @@ def b():
506506 assert gen_b .gi_yieldfrom .gi_code .co_name == 'q'
507507
508508 gen_b .send (None )
509- assert gen_b .gi_yieldfrom is None
509+ assert gen_b .gi_yieldfrom is None
510+
511+
512+ def test_generator_frame ():
513+ def gen ():
514+ a = 1
515+ yield sys ._getframe ()
516+ b = 2
517+
518+ g = gen ()
519+ assert not g .gi_running
520+ assert not g .gi_suspended
521+ assert g .gi_frame
522+ assert g .gi_frame .f_back is None
523+ assert g .gi_frame .f_globals == globals ()
524+ assert g .gi_frame .f_locals == {}
525+ assert g .gi_frame .f_lineno == gen .__code__ .co_firstlineno
526+ f = next (g )
527+ assert f
528+ assert not g .gi_running
529+ assert g .gi_suspended
530+ assert f is g .gi_frame
531+ assert f .f_back is None
532+ assert f .f_globals == globals ()
533+ assert f .f_locals == {'a' : 1 }
534+ assert f .f_lineno == gen .__code__ .co_firstlineno + 2
535+ try :
536+ next (g )
537+ assert False
538+ except StopIteration :
539+ pass
540+ assert not g .gi_running
541+ assert not g .gi_suspended
542+ assert not g .gi_frame
543+ # CPython is inconsistent here that the backref is set for a generator that finished. Let's assume it's just an implementation accident
544+ # assert f.f_back is None
545+ assert f .f_globals is globals ()
546+ assert f .f_locals == {'a' : 1 , 'b' : 2 }
547+ assert f .f_lineno == gen .__code__ .co_firstlineno + 3
548+
549+
550+ def test_generator_frame_in_running_generator ():
551+ def gen ():
552+ self = yield
553+ assert self .gi_running
554+ assert not self .gi_suspended
555+ assert self .gi_frame .f_lineno == gen .__code__ .co_firstlineno + 4
556+ assert self .gi_frame .f_globals == globals ()
557+ assert self .gi_frame .f_locals .get ('self' ) is self
558+ assert self .gi_frame is sys ._getframe ()
559+
560+ g = gen ()
561+ next (g )
562+ try :
563+ g .send (g )
564+ assert False
565+ except StopIteration :
566+ pass
567+
568+
569+ def test_generator_frame_in_generator_up_stack ():
570+ def validate (self ):
571+ assert self .gi_running
572+ assert not self .gi_suspended
573+ assert self .gi_frame .f_lineno == gen .__code__ .co_firstlineno + 2
574+ assert self .gi_frame .f_globals == globals ()
575+ assert self .gi_frame .f_locals .get ('self' ) is self
576+ assert self .gi_frame is sys ._getframe (1 )
577+
578+ def gen ():
579+ self = yield
580+ validate (self )
581+
582+ g = gen ()
583+ next (g )
584+ try :
585+ g .send (g )
586+ assert False
587+ except StopIteration :
588+ pass
0 commit comments