Index: Lib/inspect.py =================================================================== --- Lib/inspect.py (revision 86595) +++ Lib/inspect.py (working copy) @@ -1128,3 +1128,26 @@ if default is not _sentinel: return default raise AttributeError(attr) + + +GEN_CREATED = 1 +GEN_RUNNING = 2 +GEN_SUSPENDED = 3 +GEN_CLOSED = 4 + +def getgeneratorstate(generator): + """Get current state of a generator-iterator. + + Possible states are: + GEN_CREATED: Waiting to start execution. + GEN_RUNNING: Currently being executed by the interpreter. + GEN_SUSPENDED: Currently suspended at a yield expression. + GEN_CLOSED: Execution has completed. + """ + if generator.gi_running: + return GEN_RUNNING + if generator.gi_frame is None: + return GEN_CLOSED + if generator.gi_frame.f_lasti == -1: + return GEN_CREATED + return GEN_SUSPENDED Index: Lib/test/test_inspect.py =================================================================== --- Lib/test/test_inspect.py (revision 86595) +++ Lib/test/test_inspect.py (working copy) @@ -887,12 +887,46 @@ self.assertEqual(inspect.getattr_static(Something, 'foo'), 3) +class TestGetGeneratorState(unittest.TestCase): + + def setUp(self): + def number_generator(): + for number in range(5): + yield number + self.generator = number_generator() + + def testCreated(self): + self.assertEqual(inspect.getgeneratorstate(self.generator), inspect.GEN_CREATED) + + def testSuspended(self): + next(self.generator) + self.assertEqual(inspect.getgeneratorstate(self.generator), inspect.GEN_SUSPENDED) + + def testClosed(self): + for i in self.generator: + pass + self.assertEqual(inspect.getgeneratorstate(self.generator), inspect.GEN_CLOSED) + + def testRunning(self): + # As mentioned on issue #10220, checking for the RUNNING state is a bit tricky. + # The following generator checks for this between yield's, but to do so it must receive + # a self reference through a "send" call. + def running_check_generator(): + for number in range(5): + generator_self = yield number + self.assertEqual(inspect.getgeneratorstate(generator_self), inspect.GEN_RUNNING) + self.generator = running_check_generator() + next(self.generator) + # Sends a reference to the generator itself, in order to assert its state value. + self.generator.send(self.generator) + + def test_main(): run_unittest( TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases, TestInterpreterStack, TestClassesAndFunctions, TestPredicates, TestGetcallargsFunctions, TestGetcallargsMethods, - TestGetcallargsUnboundMethods, TestGetattrStatic + TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState ) if __name__ == "__main__":