Issue #7051: Clarify behaviour of 'g' and 'G'-style formatting.
[python.git] / Lib / test / test_inspect.py
blobe4c4ee8039bbd89de7e7c1ed43e3930a21d44c35
1 import sys
2 import types
3 import unittest
4 import inspect
5 import datetime
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
13 import unicodedata
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]
29 import __builtin__
31 try:
32 1/0
33 except:
34 tb = sys.exc_traceback
36 git = mod.StupidGit()
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):
45 obj = eval(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:
51 continue
52 self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp))
54 def generator_function_example(self):
55 for i in xrange(2):
56 yield i
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
63 expected = 16
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')
85 else:
86 self.assertFalse(inspect.isgetsetdescriptor(type(tb.tb_frame).f_locals))
87 if hasattr(types, 'MemberDescriptorType'):
88 self.istest(inspect.ismemberdescriptor, 'datetime.timedelta.days')
89 else:
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):
105 return None
106 self.assertFalse(inspect.isclass(CustomGetattr()))
108 def test_get_slot_members(self):
109 class C(object):
110 __slots__ = ("a", "b")
112 x = C()
113 x.a = 42
114 members = dict(inspect.getmembers(x))
115 self.assertTrue('a' in members)
116 self.assertTrue('b' not in members)
119 class TestInterpreterStack(IsTestBase):
120 def __init__(self, *args, **kwargs):
121 unittest.TestCase.__init__(self, *args, **kwargs)
123 git.abuse(7, 8, 9)
125 def test_abuse_done(self):
126 self.istest(inspect.istraceback, 'git.ex[2]')
127 self.istest(inspect.isframe, 'mod.fr')
129 def test_stack(self):
130 self.assertTrue(len(mod.st) >= 5)
131 self.assertEqual(mod.st[0][1:],
132 (modfile, 16, 'eggs', [' st = inspect.stack()\n'], 0))
133 self.assertEqual(mod.st[1][1:],
134 (modfile, 9, 'spam', [' eggs(b + d, c + f)\n'], 0))
135 self.assertEqual(mod.st[2][1:],
136 (modfile, 43, 'argue', [' spam(a, b, c)\n'], 0))
137 self.assertEqual(mod.st[3][1:],
138 (modfile, 39, 'abuse', [' self.argue(a, b, c)\n'], 0))
140 def test_trace(self):
141 self.assertEqual(len(git.tr), 3)
142 self.assertEqual(git.tr[0][1:], (modfile, 43, 'argue',
143 [' spam(a, b, c)\n'], 0))
144 self.assertEqual(git.tr[1][1:], (modfile, 9, 'spam',
145 [' eggs(b + d, c + f)\n'], 0))
146 self.assertEqual(git.tr[2][1:], (modfile, 18, 'eggs',
147 [' q = y / 0\n'], 0))
149 def test_frame(self):
150 args, varargs, varkw, locals = inspect.getargvalues(mod.fr)
151 self.assertEqual(args, ['x', 'y'])
152 self.assertEqual(varargs, None)
153 self.assertEqual(varkw, None)
154 self.assertEqual(locals, {'x': 11, 'p': 11, 'y': 14})
155 self.assertEqual(inspect.formatargvalues(args, varargs, varkw, locals),
156 '(x=11, y=14)')
158 def test_previous_frame(self):
159 args, varargs, varkw, locals = inspect.getargvalues(mod.fr.f_back)
160 self.assertEqual(args, ['a', 'b', 'c', 'd', ['e', ['f']]])
161 self.assertEqual(varargs, 'g')
162 self.assertEqual(varkw, 'h')
163 self.assertEqual(inspect.formatargvalues(args, varargs, varkw, locals),
164 '(a=7, b=8, c=9, d=3, (e=4, (f=5,)), *g=(), **h={})')
166 class GetSourceBase(unittest.TestCase):
167 # Subclasses must override.
168 fodderFile = None
170 def __init__(self, *args, **kwargs):
171 unittest.TestCase.__init__(self, *args, **kwargs)
173 with open(inspect.getsourcefile(self.fodderFile)) as fp:
174 self.source = fp.read()
176 def sourcerange(self, top, bottom):
177 lines = self.source.split("\n")
178 return "\n".join(lines[top-1:bottom]) + "\n"
180 def assertSourceEqual(self, obj, top, bottom):
181 self.assertEqual(inspect.getsource(obj),
182 self.sourcerange(top, bottom))
184 class TestRetrievingSourceCode(GetSourceBase):
185 fodderFile = mod
187 def test_getclasses(self):
188 classes = inspect.getmembers(mod, inspect.isclass)
189 self.assertEqual(classes,
190 [('FesteringGob', mod.FesteringGob),
191 ('MalodorousPervert', mod.MalodorousPervert),
192 ('ParrotDroppings', mod.ParrotDroppings),
193 ('StupidGit', mod.StupidGit)])
194 tree = inspect.getclasstree([cls[1] for cls in classes], 1)
195 self.assertEqual(tree,
196 [(mod.ParrotDroppings, ()),
197 (mod.StupidGit, ()),
198 [(mod.MalodorousPervert, (mod.StupidGit,)),
199 [(mod.FesteringGob, (mod.MalodorousPervert,
200 mod.ParrotDroppings))
205 def test_getfunctions(self):
206 functions = inspect.getmembers(mod, inspect.isfunction)
207 self.assertEqual(functions, [('eggs', mod.eggs),
208 ('spam', mod.spam)])
210 def test_getdoc(self):
211 self.assertEqual(inspect.getdoc(mod), 'A module docstring.')
212 self.assertEqual(inspect.getdoc(mod.StupidGit),
213 'A longer,\n\nindented\n\ndocstring.')
214 self.assertEqual(inspect.getdoc(git.abuse),
215 'Another\n\ndocstring\n\ncontaining\n\ntabs')
217 def test_cleandoc(self):
218 self.assertEqual(inspect.cleandoc('An\n indented\n docstring.'),
219 'An\nindented\ndocstring.')
221 def test_getcomments(self):
222 self.assertEqual(inspect.getcomments(mod), '# line 1\n')
223 self.assertEqual(inspect.getcomments(mod.StupidGit), '# line 20\n')
225 def test_getmodule(self):
226 # Check actual module
227 self.assertEqual(inspect.getmodule(mod), mod)
228 # Check class (uses __module__ attribute)
229 self.assertEqual(inspect.getmodule(mod.StupidGit), mod)
230 # Check a method (no __module__ attribute, falls back to filename)
231 self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod)
232 # Do it again (check the caching isn't broken)
233 self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod)
234 # Check a builtin
235 self.assertEqual(inspect.getmodule(str), sys.modules["__builtin__"])
236 # Check filename override
237 self.assertEqual(inspect.getmodule(None, modfile), mod)
239 def test_getsource(self):
240 self.assertSourceEqual(git.abuse, 29, 39)
241 self.assertSourceEqual(mod.StupidGit, 21, 46)
243 def test_getsourcefile(self):
244 self.assertEqual(inspect.getsourcefile(mod.spam), modfile)
245 self.assertEqual(inspect.getsourcefile(git.abuse), modfile)
247 def test_getfile(self):
248 self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__)
250 def test_getmodule_recursion(self):
251 from types import ModuleType
252 name = '__inspect_dummy'
253 m = sys.modules[name] = ModuleType(name)
254 m.__file__ = "<string>" # hopefully not a real filename...
255 m.__loader__ = "dummy" # pretend the filename is understood by a loader
256 exec "def x(): pass" in m.__dict__
257 self.assertEqual(inspect.getsourcefile(m.x.func_code), '<string>')
258 del sys.modules[name]
259 inspect.getmodule(compile('a=10','','single'))
261 class TestDecorators(GetSourceBase):
262 fodderFile = mod2
264 def test_wrapped_decorator(self):
265 self.assertSourceEqual(mod2.wrapped, 14, 17)
267 def test_replacing_decorator(self):
268 self.assertSourceEqual(mod2.gone, 9, 10)
270 class TestOneliners(GetSourceBase):
271 fodderFile = mod2
272 def test_oneline_lambda(self):
273 # Test inspect.getsource with a one-line lambda function.
274 self.assertSourceEqual(mod2.oll, 25, 25)
276 def test_threeline_lambda(self):
277 # Test inspect.getsource with a three-line lambda function,
278 # where the second and third lines are _not_ indented.
279 self.assertSourceEqual(mod2.tll, 28, 30)
281 def test_twoline_indented_lambda(self):
282 # Test inspect.getsource with a two-line lambda function,
283 # where the second line _is_ indented.
284 self.assertSourceEqual(mod2.tlli, 33, 34)
286 def test_onelinefunc(self):
287 # Test inspect.getsource with a regular one-line function.
288 self.assertSourceEqual(mod2.onelinefunc, 37, 37)
290 def test_manyargs(self):
291 # Test inspect.getsource with a regular function where
292 # the arguments are on two lines and _not_ indented and
293 # the body on the second line with the last arguments.
294 self.assertSourceEqual(mod2.manyargs, 40, 41)
296 def test_twolinefunc(self):
297 # Test inspect.getsource with a regular function where
298 # the body is on two lines, following the argument list and
299 # continued on the next line by a \\.
300 self.assertSourceEqual(mod2.twolinefunc, 44, 45)
302 def test_lambda_in_list(self):
303 # Test inspect.getsource with a one-line lambda function
304 # defined in a list, indented.
305 self.assertSourceEqual(mod2.a[1], 49, 49)
307 def test_anonymous(self):
308 # Test inspect.getsource with a lambda function defined
309 # as argument to another function.
310 self.assertSourceEqual(mod2.anonymous, 55, 55)
312 class TestBuggyCases(GetSourceBase):
313 fodderFile = mod2
315 def test_with_comment(self):
316 self.assertSourceEqual(mod2.with_comment, 58, 59)
318 def test_multiline_sig(self):
319 self.assertSourceEqual(mod2.multiline_sig[0], 63, 64)
321 def test_nested_class(self):
322 self.assertSourceEqual(mod2.func69().func71, 71, 72)
324 def test_one_liner_followed_by_non_name(self):
325 self.assertSourceEqual(mod2.func77, 77, 77)
327 def test_one_liner_dedent_non_name(self):
328 self.assertSourceEqual(mod2.cls82.func83, 83, 83)
330 def test_with_comment_instead_of_docstring(self):
331 self.assertSourceEqual(mod2.func88, 88, 90)
333 def test_method_in_dynamic_class(self):
334 self.assertSourceEqual(mod2.method_in_dynamic_class, 95, 97)
336 @unittest.skipIf(
337 not hasattr(unicodedata, '__file__') or
338 unicodedata.__file__[-4:] in (".pyc", ".pyo"),
339 "unicodedata is not an external binary module")
340 def test_findsource_binary(self):
341 self.assertRaises(IOError, inspect.getsource, unicodedata)
342 self.assertRaises(IOError, inspect.findsource, unicodedata)
344 # Helper for testing classify_class_attrs.
345 def attrs_wo_objs(cls):
346 return [t[:3] for t in inspect.classify_class_attrs(cls)]
348 class TestClassesAndFunctions(unittest.TestCase):
349 def test_classic_mro(self):
350 # Test classic-class method resolution order.
351 class A: pass
352 class B(A): pass
353 class C(A): pass
354 class D(B, C): pass
356 expected = (D, B, A, C)
357 got = inspect.getmro(D)
358 self.assertEqual(expected, got)
360 def test_newstyle_mro(self):
361 # The same w/ new-class MRO.
362 class A(object): pass
363 class B(A): pass
364 class C(A): pass
365 class D(B, C): pass
367 expected = (D, B, C, A, object)
368 got = inspect.getmro(D)
369 self.assertEqual(expected, got)
371 def assertArgSpecEquals(self, routine, args_e, varargs_e = None,
372 varkw_e = None, defaults_e = None,
373 formatted = None):
374 args, varargs, varkw, defaults = inspect.getargspec(routine)
375 self.assertEqual(args, args_e)
376 self.assertEqual(varargs, varargs_e)
377 self.assertEqual(varkw, varkw_e)
378 self.assertEqual(defaults, defaults_e)
379 if formatted is not None:
380 self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults),
381 formatted)
383 def test_getargspec(self):
384 self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted = '(x, y)')
386 self.assertArgSpecEquals(mod.spam,
387 ['a', 'b', 'c', 'd', ['e', ['f']]],
388 'g', 'h', (3, (4, (5,))),
389 '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)')
391 def test_getargspec_method(self):
392 class A(object):
393 def m(self):
394 pass
395 self.assertArgSpecEquals(A.m, ['self'])
397 def test_getargspec_sublistofone(self):
398 def sublistOfOne((foo,)): return 1
399 self.assertArgSpecEquals(sublistOfOne, [['foo']])
401 def fakeSublistOfOne((foo)): return 1
402 self.assertArgSpecEquals(fakeSublistOfOne, ['foo'])
404 def test_classify_oldstyle(self):
405 class A:
406 def s(): pass
407 s = staticmethod(s)
409 def c(cls): pass
410 c = classmethod(c)
412 def getp(self): pass
413 p = property(getp)
415 def m(self): pass
417 def m1(self): pass
419 datablob = '1'
421 attrs = attrs_wo_objs(A)
422 self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
423 self.assertTrue(('c', 'class method', A) in attrs, 'missing class method')
424 self.assertTrue(('p', 'property', A) in attrs, 'missing property')
425 self.assertTrue(('m', 'method', A) in attrs, 'missing plain method')
426 self.assertTrue(('m1', 'method', A) in attrs, 'missing plain method')
427 self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
429 class B(A):
430 def m(self): pass
432 attrs = attrs_wo_objs(B)
433 self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
434 self.assertTrue(('c', 'class method', A) in attrs, 'missing class method')
435 self.assertTrue(('p', 'property', A) in attrs, 'missing property')
436 self.assertTrue(('m', 'method', B) in attrs, 'missing plain method')
437 self.assertTrue(('m1', 'method', A) in attrs, 'missing plain method')
438 self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
441 class C(A):
442 def m(self): pass
443 def c(self): pass
445 attrs = attrs_wo_objs(C)
446 self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
447 self.assertTrue(('c', 'method', C) in attrs, 'missing plain method')
448 self.assertTrue(('p', 'property', A) in attrs, 'missing property')
449 self.assertTrue(('m', 'method', C) in attrs, 'missing plain method')
450 self.assertTrue(('m1', 'method', A) in attrs, 'missing plain method')
451 self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
453 class D(B, C):
454 def m1(self): pass
456 attrs = attrs_wo_objs(D)
457 self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
458 self.assertTrue(('c', 'class method', A) in attrs, 'missing class method')
459 self.assertTrue(('p', 'property', A) in attrs, 'missing property')
460 self.assertTrue(('m', 'method', B) in attrs, 'missing plain method')
461 self.assertTrue(('m1', 'method', D) in attrs, 'missing plain method')
462 self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
464 # Repeat all that, but w/ new-style classes.
465 def test_classify_newstyle(self):
466 class A(object):
468 def s(): pass
469 s = staticmethod(s)
471 def c(cls): pass
472 c = classmethod(c)
474 def getp(self): pass
475 p = property(getp)
477 def m(self): pass
479 def m1(self): pass
481 datablob = '1'
483 attrs = attrs_wo_objs(A)
484 self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
485 self.assertTrue(('c', 'class method', A) in attrs, 'missing class method')
486 self.assertTrue(('p', 'property', A) in attrs, 'missing property')
487 self.assertTrue(('m', 'method', A) in attrs, 'missing plain method')
488 self.assertTrue(('m1', 'method', A) in attrs, 'missing plain method')
489 self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
491 class B(A):
493 def m(self): pass
495 attrs = attrs_wo_objs(B)
496 self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
497 self.assertTrue(('c', 'class method', A) in attrs, 'missing class method')
498 self.assertTrue(('p', 'property', A) in attrs, 'missing property')
499 self.assertTrue(('m', 'method', B) in attrs, 'missing plain method')
500 self.assertTrue(('m1', 'method', A) in attrs, 'missing plain method')
501 self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
504 class C(A):
506 def m(self): pass
507 def c(self): pass
509 attrs = attrs_wo_objs(C)
510 self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
511 self.assertTrue(('c', 'method', C) in attrs, 'missing plain method')
512 self.assertTrue(('p', 'property', A) in attrs, 'missing property')
513 self.assertTrue(('m', 'method', C) in attrs, 'missing plain method')
514 self.assertTrue(('m1', 'method', A) in attrs, 'missing plain method')
515 self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
517 class D(B, C):
519 def m1(self): pass
521 attrs = attrs_wo_objs(D)
522 self.assertTrue(('s', 'static method', A) in attrs, 'missing static method')
523 self.assertTrue(('c', 'method', C) in attrs, 'missing plain method')
524 self.assertTrue(('p', 'property', A) in attrs, 'missing property')
525 self.assertTrue(('m', 'method', B) in attrs, 'missing plain method')
526 self.assertTrue(('m1', 'method', D) in attrs, 'missing plain method')
527 self.assertTrue(('datablob', 'data', A) in attrs, 'missing data')
529 def test_main():
530 run_unittest(TestDecorators, TestRetrievingSourceCode, TestOneliners,
531 TestBuggyCases,
532 TestInterpreterStack, TestClassesAndFunctions, TestPredicates)
534 if __name__ == "__main__":
535 test_main()