]> granicus.if.org Git - python/commitdiff
Issue #1916. Added isgenerator() and isgeneratorfunction() to
authorFacundo Batista <facundobatista@gmail.com>
Mon, 18 Feb 2008 03:43:43 +0000 (03:43 +0000)
committerFacundo Batista <facundobatista@gmail.com>
Mon, 18 Feb 2008 03:43:43 +0000 (03:43 +0000)
inspect.py.  Thanks Javi Mansilla for patch review and
corrections.

Doc/library/inspect.rst
Lib/inspect.py
Lib/test/test_inspect.py
Misc/NEWS

index 7893b69246e238b70a05e797f6681834a5b97207..fb927839e43b4269a0c3c0b536c848329156fbfb 100644 (file)
@@ -28,7 +28,7 @@ Types and members
 -----------------
 
 The :func:`getmembers` function retrieves the members of an object such as a
-class or module. The eleven functions whose names begin with "is" are mainly
+class or module. The fifteen functions whose names begin with "is" are mainly
 provided as convenient choices for the second argument to :func:`getmembers`.
 They also help you determine when you can expect to find the following special
 attributes:
@@ -81,6 +81,35 @@ attributes:
 +-----------+-----------------+---------------------------+-------+
 |           | func_name       | (same as __name__)        |       |
 +-----------+-----------------+---------------------------+-------+
+| generator | __iter__        | defined to support        |       |
+|           |                 | iteration over container  |       |
++-----------+-----------------+---------------------------+-------+
+|           | close           | raises new GeneratorExit  |       |
+|           |                 | exception inside the      |       |
+|           |                 | generator to terminate    |       |
+|           |                 | the iteration             |       |
++-----------+-----------------+---------------------------+-------+
+|           | gi_code         | code object               |       |
++-----------+-----------------+---------------------------+-------+
+|           | gi_frame        | frame object or possibly  |       |
+|           |                 | None once the generator   |       |
+|           |                 | has been exhausted        |       |
++-----------+-----------------+---------------------------+-------+
+|           | gi_running      | set to 1 when generator   |       |
+|           |                 | is executing, 0 otherwise |       |
++-----------+-----------------+---------------------------+-------+
+|           | next            | return the next item from |       |
+|           |                 | the container             |       |
++-----------+-----------------+---------------------------+-------+
+|           | send            | resumes the generator and |       |
+|           |                 | "sends" a value that      |       |
+|           |                 | becomes the result of the |       |
+|           |                 | current yield-expression  |       |
++-----------+-----------------+---------------------------+-------+
+|           | throw           | used to raise an          |       |
+|           |                 | exception inside the      |       |
+|           |                 | generator                 |       |
++-----------+-----------------+---------------------------+-------+
 | traceback | tb_frame        | frame object at this      |       |
 |           |                 | level                     |       |
 +-----------+-----------------+---------------------------+-------+
@@ -246,6 +275,13 @@ Note:
 
    Return true if the object is a Python function or unnamed (:term:`lambda`) function.
 
+.. function:: isgeneratorfunction(object)
+
+   Return true if the object is a Python generator function.
+
+.. function:: isgenerator(object)
+
+   Return true if the object is a generator.
 
 .. function:: istraceback(object)
 
index 8ae50fc246203619bc4ef5a70d95c00e15d735e7..42f2c310bba5864fc705d343d7bfe20ce5b47f33 100644 (file)
@@ -7,8 +7,9 @@ It also provides some help for examining source code and class layout.
 
 Here are some of the useful functions provided by this module:
 
-    ismodule(), isclass(), ismethod(), isfunction(), istraceback(),
-        isframe(), iscode(), isbuiltin(), isroutine() - check object types
+    ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),
+        isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),
+        isroutine() - check object types
     getmembers() - get members of an object that satisfy a given condition
 
     getfile(), getsourcefile(), getsource() - find an object's source code
@@ -28,9 +29,19 @@ Here are some of the useful functions provided by this module:
 __author__ = 'Ka-Ping Yee <ping@lfw.org>'
 __date__ = '1 Jan 2001'
 
-import sys, os, types, string, re, dis, imp, tokenize, linecache
+import sys
+import os
+import types
+import string
+import re
+import dis
+import imp
+import tokenize
+import linecache
 from operator import attrgetter
 from collections import namedtuple
+from compiler.consts import (CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS,
+    CO_VARKEYWORDS, CO_GENERATOR)
 
 # ----------------------------------------------------------- type-checking
 def ismodule(object):
@@ -137,6 +148,33 @@ def isfunction(object):
         func_name       (same as __name__)"""
     return isinstance(object, types.FunctionType)
 
+def isgeneratorfunction(object):
+    """Return true if the object is a user-defined generator function.
+
+    Generator function objects provides same attributes as functions.
+
+    See isfunction.__doc__ for attributes listing."""
+    if (isfunction(object) or ismethod(object)) and \
+        object.func_code.co_flags & CO_GENERATOR:
+        return True
+
+def isgenerator(object):
+    """Return true if the object is a generator.
+
+    Generator objects provide these attributes:
+        __iter__        defined to support interation over container
+        close           raises a new GeneratorExit exception inside the
+                        generator to terminate the iteration
+        gi_code         code object
+        gi_frame        frame object or possibly None once the generator has
+                        been exhausted
+        gi_running      set to 1 when generator is executing, 0 otherwise
+        next            return the next item from the container
+        send            resumes the generator and "sends" a value that becomes
+                        the result of the current yield-expression
+        throw           used to raise an exception inside the generator"""
+    return isinstance(object, types.GeneratorType)
+
 def istraceback(object):
     """Return true if the object is a traceback.
 
@@ -199,6 +237,10 @@ def isroutine(object):
             or ismethod(object)
             or ismethoddescriptor(object))
 
+def isgenerator(object):
+    """Return true if the object is a generator object."""
+    return isinstance(object, types.GeneratorType)
+
 def getmembers(object, predicate=None):
     """Return all members of an object as (name, value) pairs sorted by name.
     Optionally, only return members that satisfy a given predicate."""
@@ -671,9 +713,6 @@ def getclasstree(classes, unique=0):
     return walktree(roots, children, None)
 
 # ------------------------------------------------ argument list extraction
-# These constants are from Python's compile.h.
-CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
-
 Arguments = namedtuple('Arguments', 'args varargs keywords')
 
 def getargs(co):
index 0537d7ebd6b205e64da0c3fc61b476f293771ad7..33bcfb4f794f15db1c77516805efc2dc08dfb4df 100644 (file)
@@ -11,10 +11,10 @@ from test import inspect_fodder2 as mod2
 
 # Functions tested in this suite:
 # ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode,
-# isbuiltin, isroutine, getmembers, getdoc, getfile, getmodule,
-# getsourcefile, getcomments, getsource, getclasstree, getargspec,
-# getargvalues, formatargspec, formatargvalues, currentframe, stack, trace
-# isdatadescriptor
+# isbuiltin, isroutine, isgenerator, isgeneratorfunction, getmembers,
+# getdoc, getfile, getmodule, getsourcefile, getcomments, getsource,
+# getclasstree, getargspec, getargvalues, formatargspec, formatargvalues,
+# currentframe, stack, trace, isdatadescriptor
 
 modfile = mod.__file__
 if modfile.endswith(('c', 'o')):
@@ -32,23 +32,33 @@ git = mod.StupidGit()
 class IsTestBase(unittest.TestCase):
     predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode,
                       inspect.isframe, inspect.isfunction, inspect.ismethod,
-                      inspect.ismodule, inspect.istraceback])
+                      inspect.ismodule, inspect.istraceback,
+                      inspect.isgenerator, inspect.isgeneratorfunction])
 
     def istest(self, predicate, exp):
         obj = eval(exp)
         self.failUnless(predicate(obj), '%s(%s)' % (predicate.__name__, exp))
 
         for other in self.predicates - set([predicate]):
+            if predicate == inspect.isgeneratorfunction and\
+               other == inspect.isfunction:
+                continue
             self.failIf(other(obj), 'not %s(%s)' % (other.__name__, exp))
 
+def generator_function_example(self):
+    for i in xrange(2):
+        yield i
+
 class TestPredicates(IsTestBase):
-    def test_thirteen(self):
+    def test_fifteen(self):
         count = len(filter(lambda x:x.startswith('is'), dir(inspect)))
-        # Doc/lib/libinspect.tex claims there are 13 such functions
-        expected = 13
+        # This test is here for remember you to update Doc/library/inspect.rst
+        # which claims there are 15 such functions
+        expected = 15
         err_msg = "There are %d (not %d) is* functions" % (count, expected)
         self.assertEqual(count, expected, err_msg)
 
+
     def test_excluding_predicates(self):
         self.istest(inspect.isbuiltin, 'sys.exit')
         self.istest(inspect.isbuiltin, '[].append')
@@ -62,6 +72,8 @@ class TestPredicates(IsTestBase):
         self.istest(inspect.istraceback, 'tb')
         self.istest(inspect.isdatadescriptor, '__builtin__.file.closed')
         self.istest(inspect.isdatadescriptor, '__builtin__.file.softspace')
+        self.istest(inspect.isgenerator, '(x for x in xrange(2))')
+        self.istest(inspect.isgeneratorfunction, 'generator_function_example')
         if hasattr(types, 'GetSetDescriptorType'):
             self.istest(inspect.isgetsetdescriptor,
                         'type(tb.tb_frame).f_locals')
index a722195c52c38bdbf3a57c174d9ab220c7513ba0..1289844b955d47d26a1c45a1ddc7296bc02304ef 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -414,6 +414,8 @@ Core and builtins
 Library
 -------
 
+- Issue #1916. Added isgenerator() and isgeneratorfunction() to inspect.py.
+
 - ctypes instances that are not or do not contain pointers can now be
   pickled.