From: Facundo Batista Date: Mon, 18 Feb 2008 03:43:43 +0000 (+0000) Subject: Issue #1916. Added isgenerator() and isgeneratorfunction() to X-Git-Tag: v2.6a1~140 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=759bfc6207e7979d4eaeed2a2ae611e1804aef55;p=python Issue #1916. Added isgenerator() and isgeneratorfunction() to inspect.py. Thanks Javi Mansilla for patch review and corrections. --- diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 7893b69246..fb927839e4 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -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) diff --git a/Lib/inspect.py b/Lib/inspect.py index 8ae50fc246..42f2c310bb 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -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 ' __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): diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 0537d7ebd6..33bcfb4f79 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -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') diff --git a/Misc/NEWS b/Misc/NEWS index a722195c52..1289844b95 100644 --- 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.