summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2010-11-21 03:44:04 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2010-11-21 03:44:04 (GMT)
commite0f04659cd717a031b42dcfd43ca07824b24f9b2 (patch)
tree63fbd71f11a93bb398b5d1f6c2d91b116bc7d78e
parentd3309df40b5335ebf225a359e5cb3b324801e221 (diff)
downloadcpython-e0f04659cd717a031b42dcfd43ca07824b24f9b2.zip
cpython-e0f04659cd717a031b42dcfd43ca07824b24f9b2.tar.gz
cpython-e0f04659cd717a031b42dcfd43ca07824b24f9b2.tar.bz2
Issue #10220: Add inspect.getgeneratorstate(). Initial patch by Rodolpho Eckhardt
-rw-r--r--Doc/library/inspect.rst22
-rw-r--r--Doc/whatsnew/3.2.rst8
-rw-r--r--Lib/inspect.py20
-rw-r--r--Lib/test/test_inspect.py47
-rw-r--r--Misc/NEWS3
5 files changed, 99 insertions, 1 deletions
diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
index 9a068da..810a95b 100644
--- a/Doc/library/inspect.rst
+++ b/Doc/library/inspect.rst
@@ -620,3 +620,25 @@ code execution::
# in which case the descriptor itself will
# have to do
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.
+
+
+
diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst
index 1bad544..dd47129 100644
--- a/Doc/whatsnew/3.2.rst
+++ b/Doc/whatsnew/3.2.rst
@@ -554,6 +554,14 @@ New, Improved, and Deprecated Modules
(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
===============
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 241cd08..e410dba 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1128,3 +1128,23 @@ def getattr_static(obj, attr, default=_sentinel):
if default is not _sentinel:
return default
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
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index cba6f13..97c47ac 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -887,12 +887,57 @@ class TestGetattrStatic(unittest.TestCase):
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():
run_unittest(
TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
TestInterpreterStack, TestClassesAndFunctions, TestPredicates,
TestGetcallargsFunctions, TestGetcallargsMethods,
- TestGetcallargsUnboundMethods, TestGetattrStatic
+ TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState
)
if __name__ == "__main__":
diff --git a/Misc/NEWS b/Misc/NEWS
index 04d624c..ca00d9b 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -32,6 +32,9 @@ Core and Builtins
Library
-------
+- Issue #10220: Added inspect.getgeneratorstate. Initial patch by
+ Rodolpho Eckhardt.
+
- Issue #10453: compileall now uses argparse instead of getopt, and thus
provides clean output when called with '-h'.