Issue #10220: Add inspect.getgeneratorstate(). Initial patch by Rodolpho Eckhardt
This commit is contained in:
parent
d3309df40b
commit
e0f04659cd
|
@ -620,3 +620,25 @@ code execution::
|
||||||
# in which case the descriptor itself will
|
# in which case the descriptor itself will
|
||||||
# have to do
|
# have to do
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
Current State of a Generator
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
When implementing coroutine schedulers and for other advanced uses of
|
||||||
|
generators, it is useful to determine whether a generator is currently
|
||||||
|
executing, is waiting to start or resume or execution, or has already
|
||||||
|
terminated. func:`getgeneratorstate` allows the current state of a
|
||||||
|
generator to be determined easily.
|
||||||
|
|
||||||
|
.. function:: 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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -554,6 +554,14 @@ New, Improved, and Deprecated Modules
|
||||||
(Contributed by R. David Murray, :issue:`10321`.)
|
(Contributed by R. David Murray, :issue:`10321`.)
|
||||||
|
|
||||||
|
|
||||||
|
* The :mod:`inspect` module has a new function :func:`getgenatorstate`
|
||||||
|
to easily identify the current state of a generator as one of
|
||||||
|
``GEN_CREATED``, ``GEN_RUNNING``, ``GEN_SUSPENDED`` or ``GEN_CLOSED``.
|
||||||
|
|
||||||
|
(Contributed by Rodolpho Eckhardt and Nick Coghlan, :issue:`10220`.)
|
||||||
|
|
||||||
|
.. XXX: Mention inspect.getattr_static (Michael Foord)
|
||||||
|
|
||||||
Multi-threading
|
Multi-threading
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
|
|
@ -1128,3 +1128,23 @@ def getattr_static(obj, attr, default=_sentinel):
|
||||||
if default is not _sentinel:
|
if default is not _sentinel:
|
||||||
return default
|
return default
|
||||||
raise AttributeError(attr)
|
raise AttributeError(attr)
|
||||||
|
|
||||||
|
|
||||||
|
GEN_CREATED, GEN_RUNNING, GEN_SUSPENDED, GEN_CLOSED = range(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
|
||||||
|
|
|
@ -887,12 +887,57 @@ class TestGetattrStatic(unittest.TestCase):
|
||||||
self.assertEqual(inspect.getattr_static(Something, 'foo'), 3)
|
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 _generatorstate(self):
|
||||||
|
return inspect.getgeneratorstate(self.generator)
|
||||||
|
|
||||||
|
def test_created(self):
|
||||||
|
self.assertEqual(self._generatorstate(), inspect.GEN_CREATED)
|
||||||
|
|
||||||
|
def test_suspended(self):
|
||||||
|
next(self.generator)
|
||||||
|
self.assertEqual(self._generatorstate(), inspect.GEN_SUSPENDED)
|
||||||
|
|
||||||
|
def test_closed_after_exhaustion(self):
|
||||||
|
for i in self.generator:
|
||||||
|
pass
|
||||||
|
self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
|
||||||
|
|
||||||
|
def test_closed_after_immediate_exception(self):
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
self.generator.throw(RuntimeError)
|
||||||
|
self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED)
|
||||||
|
|
||||||
|
def test_running(self):
|
||||||
|
# As mentioned on issue #10220, checking for the RUNNING state only
|
||||||
|
# makes sense inside the generator itself.
|
||||||
|
# The following generator checks for this by using the closure's
|
||||||
|
# reference to self and the generator state checking helper method
|
||||||
|
def running_check_generator():
|
||||||
|
for number in range(5):
|
||||||
|
self.assertEqual(self._generatorstate(), inspect.GEN_RUNNING)
|
||||||
|
yield number
|
||||||
|
self.assertEqual(self._generatorstate(), inspect.GEN_RUNNING)
|
||||||
|
self.generator = running_check_generator()
|
||||||
|
# Running up to the first yield
|
||||||
|
next(self.generator)
|
||||||
|
# Running after the first yield
|
||||||
|
next(self.generator)
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
run_unittest(
|
run_unittest(
|
||||||
TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
|
TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
|
||||||
TestInterpreterStack, TestClassesAndFunctions, TestPredicates,
|
TestInterpreterStack, TestClassesAndFunctions, TestPredicates,
|
||||||
TestGetcallargsFunctions, TestGetcallargsMethods,
|
TestGetcallargsFunctions, TestGetcallargsMethods,
|
||||||
TestGetcallargsUnboundMethods, TestGetattrStatic
|
TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -32,6 +32,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #10220: Added inspect.getgeneratorstate. Initial patch by
|
||||||
|
Rodolpho Eckhardt.
|
||||||
|
|
||||||
- Issue #10453: compileall now uses argparse instead of getopt, and thus
|
- Issue #10453: compileall now uses argparse instead of getopt, and thus
|
||||||
provides clean output when called with '-h'.
|
provides clean output when called with '-h'.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue