7 from test
.test_support
import TESTFN
, run_unittest
9 from test
import inspect_fodder
as mod
10 from test
import inspect_fodder2
as mod2
12 # C module for test_findsource_binary
15 # Functions tested in this suite:
16 # ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode,
17 # isbuiltin, isroutine, isgenerator, isgeneratorfunction, getmembers,
18 # getdoc, getfile, getmodule, getsourcefile, getcomments, getsource,
19 # getclasstree, getargspec, getargvalues, formatargspec, formatargvalues,
20 # currentframe, stack, trace, isdatadescriptor
22 # NOTE: There are some additional tests relating to interaction with
23 # zipimport in the test_zipimport_support test module.
25 modfile
= mod
.__file
__
26 if modfile
.endswith(('c', 'o')):
27 modfile
= modfile
[:-1]
34 tb
= sys
.exc_traceback
38 class IsTestBase(unittest
.TestCase
):
39 predicates
= set([inspect
.isbuiltin
, inspect
.isclass
, inspect
.iscode
,
40 inspect
.isframe
, inspect
.isfunction
, inspect
.ismethod
,
41 inspect
.ismodule
, inspect
.istraceback
,
42 inspect
.isgenerator
, inspect
.isgeneratorfunction
])
44 def istest(self
, predicate
, exp
):
46 self
.assertTrue(predicate(obj
), '%s(%s)' % (predicate
.__name
__, exp
))
48 for other
in self
.predicates
- set([predicate
]):
49 if predicate
== inspect
.isgeneratorfunction
and\
50 other
== inspect
.isfunction
:
52 self
.assertFalse(other(obj
), 'not %s(%s)' % (other
.__name
__, exp
))
54 def generator_function_example(self
):
58 class TestPredicates(IsTestBase
):
59 def test_sixteen(self
):
60 count
= len(filter(lambda x
:x
.startswith('is'), dir(inspect
)))
61 # This test is here for remember you to update Doc/library/inspect.rst
62 # which claims there are 16 such functions
64 err_msg
= "There are %d (not %d) is* functions" % (count
, expected
)
65 self
.assertEqual(count
, expected
, err_msg
)
68 def test_excluding_predicates(self
):
69 self
.istest(inspect
.isbuiltin
, 'sys.exit')
70 self
.istest(inspect
.isbuiltin
, '[].append')
71 self
.istest(inspect
.iscode
, 'mod.spam.func_code')
72 self
.istest(inspect
.isframe
, 'tb.tb_frame')
73 self
.istest(inspect
.isfunction
, 'mod.spam')
74 self
.istest(inspect
.ismethod
, 'mod.StupidGit.abuse')
75 self
.istest(inspect
.ismethod
, 'git.argue')
76 self
.istest(inspect
.ismodule
, 'mod')
77 self
.istest(inspect
.istraceback
, 'tb')
78 self
.istest(inspect
.isdatadescriptor
, '__builtin__.file.closed')
79 self
.istest(inspect
.isdatadescriptor
, '__builtin__.file.softspace')
80 self
.istest(inspect
.isgenerator
, '(x for x in xrange(2))')
81 self
.istest(inspect
.isgeneratorfunction
, 'generator_function_example')
82 if hasattr(types
, 'GetSetDescriptorType'):
83 self
.istest(inspect
.isgetsetdescriptor
,
84 'type(tb.tb_frame).f_locals')
86 self
.assertFalse(inspect
.isgetsetdescriptor(type(tb
.tb_frame
).f_locals
))
87 if hasattr(types
, 'MemberDescriptorType'):
88 self
.istest(inspect
.ismemberdescriptor
, 'datetime.timedelta.days')
90 self
.assertFalse(inspect
.ismemberdescriptor(datetime
.timedelta
.days
))
92 def test_isroutine(self
):
93 self
.assertTrue(inspect
.isroutine(mod
.spam
))
94 self
.assertTrue(inspect
.isroutine([].count
))
96 def test_isclass(self
):
97 self
.istest(inspect
.isclass
, 'mod.StupidGit')
98 self
.assertTrue(inspect
.isclass(list))
100 class newstyle(object): pass
101 self
.assertTrue(inspect
.isclass(newstyle
))
103 class CustomGetattr(object):
104 def __getattr__(self
, attr
):
106 self
.assertFalse(inspect
.isclass(CustomGetattr()))
108 def test_get_slot_members(self
):
110 __slots__
= ("a", "b")
114 members
= dict(inspect
.getmembers(x
))
115 self
.assertTrue('a' in members
)
116 self
.assertTrue('b' not in members
)
118 def test_isabstract(self
):
119 from abc
import ABCMeta
, abstractmethod
121 class AbstractClassExample(object):
122 __metaclass__
= ABCMeta
128 class ClassExample(AbstractClassExample
):
134 # Test general behaviour.
135 self
.assertTrue(inspect
.isabstract(AbstractClassExample
))
136 self
.assertFalse(inspect
.isabstract(ClassExample
))
137 self
.assertFalse(inspect
.isabstract(a
))
138 self
.assertFalse(inspect
.isabstract(int))
139 self
.assertFalse(inspect
.isabstract(5))
142 class TestInterpreterStack(IsTestBase
):
143 def __init__(self
, *args
, **kwargs
):
144 unittest
.TestCase
.__init
__(self
, *args
, **kwargs
)
148 def test_abuse_done(self
):
149 self
.istest(inspect
.istraceback
, 'git.ex[2]')
150 self
.istest(inspect
.isframe
, 'mod.fr')
152 def test_stack(self
):
153 self
.assertTrue(len(mod
.st
) >= 5)
154 self
.assertEqual(mod
.st
[0][1:],
155 (modfile
, 16, 'eggs', [' st = inspect.stack()\n'], 0))
156 self
.assertEqual(mod
.st
[1][1:],
157 (modfile
, 9, 'spam', [' eggs(b + d, c + f)\n'], 0))
158 self
.assertEqual(mod
.st
[2][1:],
159 (modfile
, 43, 'argue', [' spam(a, b, c)\n'], 0))
160 self
.assertEqual(mod
.st
[3][1:],
161 (modfile
, 39, 'abuse', [' self.argue(a, b, c)\n'], 0))
163 def test_trace(self
):
164 self
.assertEqual(len(git
.tr
), 3)
165 self
.assertEqual(git
.tr
[0][1:], (modfile
, 43, 'argue',
166 [' spam(a, b, c)\n'], 0))
167 self
.assertEqual(git
.tr
[1][1:], (modfile
, 9, 'spam',
168 [' eggs(b + d, c + f)\n'], 0))
169 self
.assertEqual(git
.tr
[2][1:], (modfile
, 18, 'eggs',
170 [' q = y / 0\n'], 0))
172 def test_frame(self
):
173 args
, varargs
, varkw
, locals = inspect
.getargvalues(mod
.fr
)
174 self
.assertEqual(args
, ['x', 'y'])
175 self
.assertEqual(varargs
, None)
176 self
.assertEqual(varkw
, None)
177 self
.assertEqual(locals, {'x': 11, 'p': 11, 'y': 14})
178 self
.assertEqual(inspect
.formatargvalues(args
, varargs
, varkw
, locals),
181 def test_previous_frame(self
):
182 args
, varargs
, varkw
, locals = inspect
.getargvalues(mod
.fr
.f_back
)
183 self
.assertEqual(args
, ['a', 'b', 'c', 'd', ['e', ['f']]])
184 self
.assertEqual(varargs
, 'g')
185 self
.assertEqual(varkw
, 'h')
186 self
.assertEqual(inspect
.formatargvalues(args
, varargs
, varkw
, locals),
187 '(a=7, b=8, c=9, d=3, (e=4, (f=5,)), *g=(), **h={})')
189 class GetSourceBase(unittest
.TestCase
):
190 # Subclasses must override.
193 def __init__(self
, *args
, **kwargs
):
194 unittest
.TestCase
.__init
__(self
, *args
, **kwargs
)
196 with
open(inspect
.getsourcefile(self
.fodderFile
)) as fp
:
197 self
.source
= fp
.read()
199 def sourcerange(self
, top
, bottom
):
200 lines
= self
.source
.split("\n")
201 return "\n".join(lines
[top
-1:bottom
]) + "\n"
203 def assertSourceEqual(self
, obj
, top
, bottom
):
204 self
.assertEqual(inspect
.getsource(obj
),
205 self
.sourcerange(top
, bottom
))
207 class TestRetrievingSourceCode(GetSourceBase
):
210 def test_getclasses(self
):
211 classes
= inspect
.getmembers(mod
, inspect
.isclass
)
212 self
.assertEqual(classes
,
213 [('FesteringGob', mod
.FesteringGob
),
214 ('MalodorousPervert', mod
.MalodorousPervert
),
215 ('ParrotDroppings', mod
.ParrotDroppings
),
216 ('StupidGit', mod
.StupidGit
)])
217 tree
= inspect
.getclasstree([cls
[1] for cls
in classes
], 1)
218 self
.assertEqual(tree
,
219 [(mod
.ParrotDroppings
, ()),
221 [(mod
.MalodorousPervert
, (mod
.StupidGit
,)),
222 [(mod
.FesteringGob
, (mod
.MalodorousPervert
,
223 mod
.ParrotDroppings
))
228 def test_getfunctions(self
):
229 functions
= inspect
.getmembers(mod
, inspect
.isfunction
)
230 self
.assertEqual(functions
, [('eggs', mod
.eggs
),
233 def test_getdoc(self
):
234 self
.assertEqual(inspect
.getdoc(mod
), 'A module docstring.')
235 self
.assertEqual(inspect
.getdoc(mod
.StupidGit
),
236 'A longer,\n\nindented\n\ndocstring.')
237 self
.assertEqual(inspect
.getdoc(git
.abuse
),
238 'Another\n\ndocstring\n\ncontaining\n\ntabs')
240 def test_cleandoc(self
):
241 self
.assertEqual(inspect
.cleandoc('An\n indented\n docstring.'),
242 'An\nindented\ndocstring.')
244 def test_getcomments(self
):
245 self
.assertEqual(inspect
.getcomments(mod
), '# line 1\n')
246 self
.assertEqual(inspect
.getcomments(mod
.StupidGit
), '# line 20\n')
248 def test_getmodule(self
):
249 # Check actual module
250 self
.assertEqual(inspect
.getmodule(mod
), mod
)
251 # Check class (uses __module__ attribute)
252 self
.assertEqual(inspect
.getmodule(mod
.StupidGit
), mod
)
253 # Check a method (no __module__ attribute, falls back to filename)
254 self
.assertEqual(inspect
.getmodule(mod
.StupidGit
.abuse
), mod
)
255 # Do it again (check the caching isn't broken)
256 self
.assertEqual(inspect
.getmodule(mod
.StupidGit
.abuse
), mod
)
258 self
.assertEqual(inspect
.getmodule(str), sys
.modules
["__builtin__"])
259 # Check filename override
260 self
.assertEqual(inspect
.getmodule(None, modfile
), mod
)
262 def test_getsource(self
):
263 self
.assertSourceEqual(git
.abuse
, 29, 39)
264 self
.assertSourceEqual(mod
.StupidGit
, 21, 46)
266 def test_getsourcefile(self
):
267 self
.assertEqual(inspect
.getsourcefile(mod
.spam
), modfile
)
268 self
.assertEqual(inspect
.getsourcefile(git
.abuse
), modfile
)
270 def test_getfile(self
):
271 self
.assertEqual(inspect
.getfile(mod
.StupidGit
), mod
.__file
__)
273 def test_getmodule_recursion(self
):
274 from types
import ModuleType
275 name
= '__inspect_dummy'
276 m
= sys
.modules
[name
] = ModuleType(name
)
277 m
.__file
__ = "<string>" # hopefully not a real filename...
278 m
.__loader
__ = "dummy" # pretend the filename is understood by a loader
279 exec "def x(): pass" in m
.__dict
__
280 self
.assertEqual(inspect
.getsourcefile(m
.x
.func_code
), '<string>')
281 del sys
.modules
[name
]
282 inspect
.getmodule(compile('a=10','','single'))
284 class TestDecorators(GetSourceBase
):
287 def test_wrapped_decorator(self
):
288 self
.assertSourceEqual(mod2
.wrapped
, 14, 17)
290 def test_replacing_decorator(self
):
291 self
.assertSourceEqual(mod2
.gone
, 9, 10)
293 class TestOneliners(GetSourceBase
):
295 def test_oneline_lambda(self
):
296 # Test inspect.getsource with a one-line lambda function.
297 self
.assertSourceEqual(mod2
.oll
, 25, 25)
299 def test_threeline_lambda(self
):
300 # Test inspect.getsource with a three-line lambda function,
301 # where the second and third lines are _not_ indented.
302 self
.assertSourceEqual(mod2
.tll
, 28, 30)
304 def test_twoline_indented_lambda(self
):
305 # Test inspect.getsource with a two-line lambda function,
306 # where the second line _is_ indented.
307 self
.assertSourceEqual(mod2
.tlli
, 33, 34)
309 def test_onelinefunc(self
):
310 # Test inspect.getsource with a regular one-line function.
311 self
.assertSourceEqual(mod2
.onelinefunc
, 37, 37)
313 def test_manyargs(self
):
314 # Test inspect.getsource with a regular function where
315 # the arguments are on two lines and _not_ indented and
316 # the body on the second line with the last arguments.
317 self
.assertSourceEqual(mod2
.manyargs
, 40, 41)
319 def test_twolinefunc(self
):
320 # Test inspect.getsource with a regular function where
321 # the body is on two lines, following the argument list and
322 # continued on the next line by a \\.
323 self
.assertSourceEqual(mod2
.twolinefunc
, 44, 45)
325 def test_lambda_in_list(self
):
326 # Test inspect.getsource with a one-line lambda function
327 # defined in a list, indented.
328 self
.assertSourceEqual(mod2
.a
[1], 49, 49)
330 def test_anonymous(self
):
331 # Test inspect.getsource with a lambda function defined
332 # as argument to another function.
333 self
.assertSourceEqual(mod2
.anonymous
, 55, 55)
335 class TestBuggyCases(GetSourceBase
):
338 def test_with_comment(self
):
339 self
.assertSourceEqual(mod2
.with_comment
, 58, 59)
341 def test_multiline_sig(self
):
342 self
.assertSourceEqual(mod2
.multiline_sig
[0], 63, 64)
344 def test_nested_class(self
):
345 self
.assertSourceEqual(mod2
.func69().func71
, 71, 72)
347 def test_one_liner_followed_by_non_name(self
):
348 self
.assertSourceEqual(mod2
.func77
, 77, 77)
350 def test_one_liner_dedent_non_name(self
):
351 self
.assertSourceEqual(mod2
.cls82
.func83
, 83, 83)
353 def test_with_comment_instead_of_docstring(self
):
354 self
.assertSourceEqual(mod2
.func88
, 88, 90)
356 def test_method_in_dynamic_class(self
):
357 self
.assertSourceEqual(mod2
.method_in_dynamic_class
, 95, 97)
360 not hasattr(unicodedata
, '__file__') or
361 unicodedata
.__file
__[-4:] in (".pyc", ".pyo"),
362 "unicodedata is not an external binary module")
363 def test_findsource_binary(self
):
364 self
.assertRaises(IOError, inspect
.getsource
, unicodedata
)
365 self
.assertRaises(IOError, inspect
.findsource
, unicodedata
)
367 # Helper for testing classify_class_attrs.
368 def attrs_wo_objs(cls
):
369 return [t
[:3] for t
in inspect
.classify_class_attrs(cls
)]
371 class TestClassesAndFunctions(unittest
.TestCase
):
372 def test_classic_mro(self
):
373 # Test classic-class method resolution order.
379 expected
= (D
, B
, A
, C
)
380 got
= inspect
.getmro(D
)
381 self
.assertEqual(expected
, got
)
383 def test_newstyle_mro(self
):
384 # The same w/ new-class MRO.
385 class A(object): pass
390 expected
= (D
, B
, C
, A
, object)
391 got
= inspect
.getmro(D
)
392 self
.assertEqual(expected
, got
)
394 def assertArgSpecEquals(self
, routine
, args_e
, varargs_e
= None,
395 varkw_e
= None, defaults_e
= None,
397 args
, varargs
, varkw
, defaults
= inspect
.getargspec(routine
)
398 self
.assertEqual(args
, args_e
)
399 self
.assertEqual(varargs
, varargs_e
)
400 self
.assertEqual(varkw
, varkw_e
)
401 self
.assertEqual(defaults
, defaults_e
)
402 if formatted
is not None:
403 self
.assertEqual(inspect
.formatargspec(args
, varargs
, varkw
, defaults
),
406 def test_getargspec(self
):
407 self
.assertArgSpecEquals(mod
.eggs
, ['x', 'y'], formatted
= '(x, y)')
409 self
.assertArgSpecEquals(mod
.spam
,
410 ['a', 'b', 'c', 'd', ['e', ['f']]],
411 'g', 'h', (3, (4, (5,))),
412 '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)')
414 def test_getargspec_method(self
):
418 self
.assertArgSpecEquals(A
.m
, ['self'])
420 def test_getargspec_sublistofone(self
):
421 def sublistOfOne((foo
,)): return 1
422 self
.assertArgSpecEquals(sublistOfOne
, [['foo']])
424 def fakeSublistOfOne((foo
)): return 1
425 self
.assertArgSpecEquals(fakeSublistOfOne
, ['foo'])
427 def test_classify_oldstyle(self
):
444 attrs
= attrs_wo_objs(A
)
445 self
.assertTrue(('s', 'static method', A
) in attrs
, 'missing static method')
446 self
.assertTrue(('c', 'class method', A
) in attrs
, 'missing class method')
447 self
.assertTrue(('p', 'property', A
) in attrs
, 'missing property')
448 self
.assertTrue(('m', 'method', A
) in attrs
, 'missing plain method')
449 self
.assertTrue(('m1', 'method', A
) in attrs
, 'missing plain method')
450 self
.assertTrue(('datablob', 'data', A
) in attrs
, 'missing data')
455 attrs
= attrs_wo_objs(B
)
456 self
.assertTrue(('s', 'static method', A
) in attrs
, 'missing static method')
457 self
.assertTrue(('c', 'class method', A
) in attrs
, 'missing class method')
458 self
.assertTrue(('p', 'property', A
) in attrs
, 'missing property')
459 self
.assertTrue(('m', 'method', B
) in attrs
, 'missing plain method')
460 self
.assertTrue(('m1', 'method', A
) in attrs
, 'missing plain method')
461 self
.assertTrue(('datablob', 'data', A
) in attrs
, 'missing data')
468 attrs
= attrs_wo_objs(C
)
469 self
.assertTrue(('s', 'static method', A
) in attrs
, 'missing static method')
470 self
.assertTrue(('c', 'method', C
) in attrs
, 'missing plain method')
471 self
.assertTrue(('p', 'property', A
) in attrs
, 'missing property')
472 self
.assertTrue(('m', 'method', C
) in attrs
, 'missing plain method')
473 self
.assertTrue(('m1', 'method', A
) in attrs
, 'missing plain method')
474 self
.assertTrue(('datablob', 'data', A
) in attrs
, 'missing data')
479 attrs
= attrs_wo_objs(D
)
480 self
.assertTrue(('s', 'static method', A
) in attrs
, 'missing static method')
481 self
.assertTrue(('c', 'class method', A
) in attrs
, 'missing class method')
482 self
.assertTrue(('p', 'property', A
) in attrs
, 'missing property')
483 self
.assertTrue(('m', 'method', B
) in attrs
, 'missing plain method')
484 self
.assertTrue(('m1', 'method', D
) in attrs
, 'missing plain method')
485 self
.assertTrue(('datablob', 'data', A
) in attrs
, 'missing data')
487 # Repeat all that, but w/ new-style classes.
488 def test_classify_newstyle(self
):
506 attrs
= attrs_wo_objs(A
)
507 self
.assertTrue(('s', 'static method', A
) in attrs
, 'missing static method')
508 self
.assertTrue(('c', 'class method', A
) in attrs
, 'missing class method')
509 self
.assertTrue(('p', 'property', A
) in attrs
, 'missing property')
510 self
.assertTrue(('m', 'method', A
) in attrs
, 'missing plain method')
511 self
.assertTrue(('m1', 'method', A
) in attrs
, 'missing plain method')
512 self
.assertTrue(('datablob', 'data', A
) in attrs
, 'missing data')
518 attrs
= attrs_wo_objs(B
)
519 self
.assertTrue(('s', 'static method', A
) in attrs
, 'missing static method')
520 self
.assertTrue(('c', 'class method', A
) in attrs
, 'missing class method')
521 self
.assertTrue(('p', 'property', A
) in attrs
, 'missing property')
522 self
.assertTrue(('m', 'method', B
) in attrs
, 'missing plain method')
523 self
.assertTrue(('m1', 'method', A
) in attrs
, 'missing plain method')
524 self
.assertTrue(('datablob', 'data', A
) in attrs
, 'missing data')
532 attrs
= attrs_wo_objs(C
)
533 self
.assertTrue(('s', 'static method', A
) in attrs
, 'missing static method')
534 self
.assertTrue(('c', 'method', C
) in attrs
, 'missing plain method')
535 self
.assertTrue(('p', 'property', A
) in attrs
, 'missing property')
536 self
.assertTrue(('m', 'method', C
) in attrs
, 'missing plain method')
537 self
.assertTrue(('m1', 'method', A
) in attrs
, 'missing plain method')
538 self
.assertTrue(('datablob', 'data', A
) in attrs
, 'missing data')
544 attrs
= attrs_wo_objs(D
)
545 self
.assertTrue(('s', 'static method', A
) in attrs
, 'missing static method')
546 self
.assertTrue(('c', 'method', C
) in attrs
, 'missing plain method')
547 self
.assertTrue(('p', 'property', A
) in attrs
, 'missing property')
548 self
.assertTrue(('m', 'method', B
) in attrs
, 'missing plain method')
549 self
.assertTrue(('m1', 'method', D
) in attrs
, 'missing plain method')
550 self
.assertTrue(('datablob', 'data', A
) in attrs
, 'missing data')
553 run_unittest(TestDecorators
, TestRetrievingSourceCode
, TestOneliners
,
555 TestInterpreterStack
, TestClassesAndFunctions
, TestPredicates
)
557 if __name__
== "__main__":