From: <pj...@us...> - 2011-03-17 22:18:44
|
Revision: 7242 http://jython.svn.sourceforge.net/jython/?rev=7242&view=rev Author: pjenvey Date: 2011-03-17 22:18:37 +0000 (Thu, 17 Mar 2011) Log Message: ----------- update inspect/test_inspect to 2.6 we now pass test_inspect's test_getargspec_method and all of its test_excluding_predicates Modified Paths: -------------- trunk/jython/Lib/inspect.py trunk/jython/Lib/test/test_inspect.py Modified: trunk/jython/Lib/inspect.py =================================================================== --- trunk/jython/Lib/inspect.py 2011-03-16 05:44:13 UTC (rev 7241) +++ trunk/jython/Lib/inspect.py 2011-03-17 22:18:37 UTC (rev 7242) @@ -7,8 +7,9 @@ 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,12 +29,27 @@ __author__ = 'Ka-Ping Yee <pi...@lf...>' __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 _jython = sys.platform.startswith('java') if _jython: _ReflectedFunctionType = type(os.listdir) +# These constants are from Include/code.h. +CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 0x1, 0x2, 0x4, 0x8 +CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40 +# See Include/object.h +TPFLAGS_IS_ABSTRACT = 1 << 20 + # ----------------------------------------------------------- type-checking def ismodule(object): """Return true if the object is a module. @@ -139,6 +155,32 @@ 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.""" + return bool((isfunction(object) or ismethod(object)) and + object.func_code.co_flags & CO_GENERATOR) + +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. @@ -202,6 +244,10 @@ or ismethoddescriptor(object) or (_jython and isinstance(object, _ReflectedFunctionType))) +def isabstract(object): + """Return true if the object is an abstract base class (ABC).""" + return isinstance(object, type) and object.__flags__ & TPFLAGS_IS_ABSTRACT + 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.""" @@ -213,6 +259,8 @@ results.sort() return results +Attribute = namedtuple('Attribute', 'name kind defining_class object') + def classify_class_attrs(cls): """Return list of attribute-descriptor tuples. @@ -279,7 +327,7 @@ else: kind = "data" - result.append((name, kind, homecls, obj)) + result.append(Attribute(name, kind, homecls, obj)) return result @@ -374,15 +422,18 @@ raise TypeError('arg is not a module, class, method, ' 'function, traceback, frame, or code object') +ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type') + def getmoduleinfo(path): """Get the module name, suffix, mode, and module type for a given file.""" filename = os.path.basename(path) - suffixes = map(lambda (suffix, mode, mtype): - (-len(suffix), suffix, mode, mtype), imp.get_suffixes()) + suffixes = map(lambda info: + (-len(info[0]), info[0], info[1], info[2]), + imp.get_suffixes()) suffixes.sort() # try longest suffixes first, in case they overlap for neglen, suffix, mode, mtype in suffixes: if filename[neglen:] == suffix: - return filename[:neglen], suffix, mode, mtype + return ModuleInfo(filename[:neglen], suffix, mode, mtype) def getmodulename(path): """Return the module name for a given file, or None.""" @@ -581,7 +632,9 @@ self.passline = False self.last = 1 - def tokeneater(self, type, token, (srow, scol), (erow, ecol), line): + def tokeneater(self, type, token, srow_scol, erow_ecol, line): + srow, scol = srow_scol + erow, ecol = erow_ecol if not self.started: # look for the first "def", "class" or "lambda" if token in ("def", "class", "lambda"): @@ -679,8 +732,7 @@ 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): """Get information about the arguments accepted by a code object. @@ -742,8 +794,10 @@ varkw = None if co.co_flags & CO_VARKEYWORDS: varkw = co.co_varnames[nargs] - return args, varargs, varkw + return Arguments(args, varargs, varkw) +ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults') + def getargspec(func): """Get the names and default values of a function's arguments. @@ -758,8 +812,10 @@ if not isfunction(func): raise TypeError('arg is not a Python function') args, varargs, varkw = getargs(func.func_code) - return args, varargs, varkw, func.func_defaults + return ArgSpec(args, varargs, varkw, func.func_defaults) +ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals') + def getargvalues(frame): """Get information about arguments passed into a particular frame. @@ -768,7 +824,7 @@ 'varargs' and 'varkw' are the names of the * and ** arguments or None. 'locals' is the locals dictionary of the given frame.""" args, varargs, varkw = getargs(frame.f_code) - return args, varargs, varkw, frame.f_locals + return ArgInfo(args, varargs, varkw, frame.f_locals) def joinseq(seq): if len(seq) == 1: @@ -834,6 +890,9 @@ return '(' + string.join(specs, ', ') + ')' # -------------------------------------------------- stack frame extraction + +Traceback = namedtuple('Traceback', 'filename lineno function code_context index') + def getframeinfo(frame, context=1): """Get information about a frame or traceback object. @@ -865,7 +924,7 @@ else: lines = index = None - return (filename, lineno, frame.f_code.co_name, lines, index) + return Traceback(filename, lineno, frame.f_code.co_name, lines, index) def getlineno(frame): """Get the line number from a frame object, allowing for optimization.""" @@ -894,7 +953,10 @@ tb = tb.tb_next return framelist -currentframe = sys._getframe +if hasattr(sys, '_getframe'): + currentframe = sys._getframe +else: + currentframe = lambda _=None: None def stack(context=1): """Return a list of records for the stack above the caller's frame.""" Modified: trunk/jython/Lib/test/test_inspect.py =================================================================== --- trunk/jython/Lib/test/test_inspect.py 2011-03-16 05:44:13 UTC (rev 7241) +++ trunk/jython/Lib/test/test_inspect.py 2011-03-17 22:18:37 UTC (rev 7242) @@ -4,19 +4,24 @@ import inspect import datetime -from test.test_support import TESTFN, run_unittest, is_jython +from test.test_support import is_jython, run_unittest, _check_py3k_warnings -from test import inspect_fodder as mod -from test import inspect_fodder2 as mod2 -from test import test_support +with _check_py3k_warnings( + ("tuple parameter unpacking has been removed", SyntaxWarning), + quiet=True): + from test import inspect_fodder as mod + 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 +# NOTE: There are some additional tests relating to interaction with +# zipimport in the test_zipimport_support test module. + modfile = mod.__file__ if modfile.endswith(('c', 'o')): modfile = modfile[:-1] @@ -26,7 +31,7 @@ import __builtin__ try: - 1/0 + 1 // 0 except: tb = sys.exc_traceback @@ -44,27 +49,37 @@ 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_sixteen(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 16 such functions + expected = 16 err_msg = "There are %d (not %d) is* functions" % (count, expected) self.assertEqual(count, expected, err_msg) + def test_excluding_predicates(self): - #XXX: Jython's PySystemState needs more work before this - #will be doable. - if not test_support.is_jython: + # XXX: Jython's PySystemState needs more work before this will + # be doable. + if not is_jython: self.istest(inspect.isbuiltin, 'sys.exit') self.istest(inspect.isbuiltin, '[].append') self.istest(inspect.isclass, 'mod.StupidGit') @@ -77,11 +92,12 @@ 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') - #XXX: This detail of PyFrames is not yet supported in Jython - elif not test_support.is_jython: + else: self.failIf(inspect.isgetsetdescriptor(type(tb.tb_frame).f_locals)) if hasattr(types, 'MemberDescriptorType'): self.istest(inspect.ismemberdescriptor, 'datetime.timedelta.days') @@ -120,7 +136,7 @@ self.assertEqual(git.tr[1][1:], (modfile, 9, 'spam', [' eggs(b + d, c + f)\n'], 0)) self.assertEqual(git.tr[2][1:], (modfile, 18, 'eggs', - [' q = y / 0\n'], 0)) + [' q = y // 0\n'], 0)) def test_frame(self): args, varargs, varkw, locals = inspect.getargvalues(mod.fr) @@ -194,6 +210,10 @@ self.assertEqual(inspect.getdoc(git.abuse), 'Another\n\ndocstring\n\ncontaining\n\ntabs') + def test_cleandoc(self): + self.assertEqual(inspect.cleandoc('An\n indented\n docstring.'), + 'An\nindented\ndocstring.') + def test_getcomments(self): self.assertEqual(inspect.getcomments(mod), '# line 1\n') self.assertEqual(inspect.getcomments(mod.StupidGit), '# line 20\n') @@ -224,9 +244,9 @@ self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__) def test_getmodule_recursion(self): - from new import module + from types import ModuleType name = '__inspect_dummy' - m = sys.modules[name] = module(name) + m = sys.modules[name] = ModuleType(name) m.__file__ = "<string>" # hopefully not a real filename... m.__loader__ = "dummy" # pretend the filename is understood by a loader exec "def x(): pass" in m.__dict__ @@ -357,7 +377,6 @@ 'g', 'h', (3, (4, (5,))), '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)') - @na_for_jython def test_getargspec_method(self): class A(object): def m(self): @@ -366,11 +385,14 @@ @na_for_jython def test_getargspec_sublistofone(self): - def sublistOfOne((foo,)): return 1 - self.assertArgSpecEquals(sublistOfOne, [['foo']]) + with _check_py3k_warnings( + ("tuple parameter unpacking has been removed", SyntaxWarning), + ("parenthesized argument names are invalid", SyntaxWarning)): + exec 'def sublistOfOne((foo,)): return 1' + self.assertArgSpecEquals(sublistOfOne, [['foo']]) - def fakeSublistOfOne((foo)): return 1 - self.assertArgSpecEquals(fakeSublistOfOne, ['foo']) + exec 'def fakeSublistOfOne((foo)): return 1' + self.assertArgSpecEquals(fakeSublistOfOne, ['foo']) def test_classify_oldstyle(self): class A: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |