fix to work on python <= 2.1
[python/dscho.git] / Lib / test / test_inspect.py
blob9da66942870281dc2b35d37d6b70d0e83c17b563
1 source = '''# line 1
2 'A module docstring.'
4 import sys, inspect
5 # line 5
7 # line 7
8 def spam(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h):
9 eggs(b + d, c + f)
11 # line 11
12 def eggs(x, y):
13 "A docstring."
14 global fr, st
15 fr = inspect.currentframe()
16 st = inspect.stack()
17 p = x
18 q = y / 0
20 # line 20
21 class StupidGit:
22 """A longer,
24 indented
26 docstring."""
27 # line 27
29 def abuse(self, a, b, c):
30 """Another
32 \tdocstring
34 containing
36 \ttabs
38 """
39 self.argue(a, b, c)
40 # line 40
41 def argue(self, a, b, c):
42 try:
43 spam(a, b, c)
44 except:
45 self.ex = sys.exc_info()
46 self.tr = inspect.trace()
48 # line 48
49 class MalodorousPervert(StupidGit):
50 pass
52 class ParrotDroppings:
53 pass
55 class FesteringGob(MalodorousPervert, ParrotDroppings):
56 pass
57 '''
59 # Functions tested in this suite:
60 # ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode,
61 # isbuiltin, isroutine, getmembers, getdoc, getfile, getmodule,
62 # getsourcefile, getcomments, getsource, getclasstree, getargspec,
63 # getargvalues, formatargspec, formatargvalues, currentframe, stack, trace
64 # isdatadescriptor
66 from test.test_support import TestFailed, TESTFN
67 import sys, imp, os, string
69 def test(assertion, message, *args):
70 if not assertion:
71 raise TestFailed, message % args
73 import inspect
75 file = open(TESTFN, 'w')
76 file.write(source)
77 file.close()
79 # Note that load_source creates file TESTFN+'c' or TESTFN+'o'.
80 mod = imp.load_source('testmod', TESTFN)
81 files_to_clean_up = [TESTFN, TESTFN + 'c', TESTFN + 'o']
83 def istest(func, exp):
84 obj = eval(exp)
85 test(func(obj), '%s(%s)' % (func.__name__, exp))
86 for other in [inspect.isbuiltin, inspect.isclass, inspect.iscode,
87 inspect.isframe, inspect.isfunction, inspect.ismethod,
88 inspect.ismodule, inspect.istraceback]:
89 if other is not func:
90 test(not other(obj), 'not %s(%s)' % (other.__name__, exp))
92 git = mod.StupidGit()
93 try:
94 1/0
95 except:
96 tb = sys.exc_traceback
98 istest(inspect.isbuiltin, 'sys.exit')
99 istest(inspect.isbuiltin, '[].append')
100 istest(inspect.isclass, 'mod.StupidGit')
101 istest(inspect.iscode, 'mod.spam.func_code')
102 istest(inspect.isframe, 'tb.tb_frame')
103 istest(inspect.isfunction, 'mod.spam')
104 istest(inspect.ismethod, 'mod.StupidGit.abuse')
105 istest(inspect.ismethod, 'git.argue')
106 istest(inspect.ismodule, 'mod')
107 istest(inspect.istraceback, 'tb')
108 import __builtin__
109 istest(inspect.isdatadescriptor, '__builtin__.file.closed')
110 istest(inspect.isdatadescriptor, '__builtin__.file.softspace')
111 test(inspect.isroutine(mod.spam), 'isroutine(mod.spam)')
112 test(inspect.isroutine([].count), 'isroutine([].count)')
114 classes = inspect.getmembers(mod, inspect.isclass)
115 test(classes ==
116 [('FesteringGob', mod.FesteringGob),
117 ('MalodorousPervert', mod.MalodorousPervert),
118 ('ParrotDroppings', mod.ParrotDroppings),
119 ('StupidGit', mod.StupidGit)], 'class list')
120 tree = inspect.getclasstree(map(lambda x: x[1], classes), 1)
121 test(tree ==
122 [(mod.ParrotDroppings, ()),
123 (mod.StupidGit, ()),
124 [(mod.MalodorousPervert, (mod.StupidGit,)),
125 [(mod.FesteringGob, (mod.MalodorousPervert, mod.ParrotDroppings))
128 ], 'class tree')
130 functions = inspect.getmembers(mod, inspect.isfunction)
131 test(functions == [('eggs', mod.eggs), ('spam', mod.spam)], 'function list')
133 test(inspect.getdoc(mod) == 'A module docstring.', 'getdoc(mod)')
134 test(inspect.getcomments(mod) == '# line 1\n', 'getcomments(mod)')
135 test(inspect.getmodule(mod.StupidGit) == mod, 'getmodule(mod.StupidGit)')
136 test(inspect.getfile(mod.StupidGit) == TESTFN, 'getfile(mod.StupidGit)')
137 test(inspect.getsourcefile(mod.spam) == TESTFN, 'getsourcefile(mod.spam)')
138 test(inspect.getsourcefile(git.abuse) == TESTFN, 'getsourcefile(git.abuse)')
140 def sourcerange(top, bottom):
141 lines = string.split(source, '\n')
142 return string.join(lines[top-1:bottom], '\n') + '\n'
144 test(inspect.getsource(git.abuse) == sourcerange(29, 39),
145 'getsource(git.abuse)')
146 test(inspect.getsource(mod.StupidGit) == sourcerange(21, 46),
147 'getsource(mod.StupidGit)')
148 test(inspect.getdoc(mod.StupidGit) ==
149 'A longer,\n\nindented\n\ndocstring.', 'getdoc(mod.StupidGit)')
150 test(inspect.getdoc(git.abuse) ==
151 'Another\n\ndocstring\n\ncontaining\n\ntabs', 'getdoc(git.abuse)')
152 test(inspect.getcomments(mod.StupidGit) == '# line 20\n',
153 'getcomments(mod.StupidGit)')
155 git.abuse(7, 8, 9)
157 istest(inspect.istraceback, 'git.ex[2]')
158 istest(inspect.isframe, 'mod.fr')
160 test(len(git.tr) == 3, 'trace() length')
161 test(git.tr[0][1:] == (TESTFN, 46, 'argue',
162 [' self.tr = inspect.trace()\n'], 0),
163 'trace() row 2')
164 test(git.tr[1][1:] == (TESTFN, 9, 'spam', [' eggs(b + d, c + f)\n'], 0),
165 'trace() row 2')
166 test(git.tr[2][1:] == (TESTFN, 18, 'eggs', [' q = y / 0\n'], 0),
167 'trace() row 3')
169 test(len(mod.st) >= 5, 'stack() length')
170 test(mod.st[0][1:] ==
171 (TESTFN, 16, 'eggs', [' st = inspect.stack()\n'], 0),
172 'stack() row 1')
173 test(mod.st[1][1:] ==
174 (TESTFN, 9, 'spam', [' eggs(b + d, c + f)\n'], 0),
175 'stack() row 2')
176 test(mod.st[2][1:] ==
177 (TESTFN, 43, 'argue', [' spam(a, b, c)\n'], 0),
178 'stack() row 3')
179 test(mod.st[3][1:] ==
180 (TESTFN, 39, 'abuse', [' self.argue(a, b, c)\n'], 0),
181 'stack() row 4')
183 args, varargs, varkw, locals = inspect.getargvalues(mod.fr)
184 test(args == ['x', 'y'], 'mod.fr args')
185 test(varargs == None, 'mod.fr varargs')
186 test(varkw == None, 'mod.fr varkw')
187 test(locals == {'x': 11, 'p': 11, 'y': 14}, 'mod.fr locals')
188 test(inspect.formatargvalues(args, varargs, varkw, locals) ==
189 '(x=11, y=14)', 'mod.fr formatted argvalues')
191 args, varargs, varkw, locals = inspect.getargvalues(mod.fr.f_back)
192 test(args == ['a', 'b', 'c', 'd', ['e', ['f']]], 'mod.fr.f_back args')
193 test(varargs == 'g', 'mod.fr.f_back varargs')
194 test(varkw == 'h', 'mod.fr.f_back varkw')
195 test(inspect.formatargvalues(args, varargs, varkw, locals) ==
196 '(a=7, b=8, c=9, d=3, (e=4, (f=5,)), *g=(), **h={})',
197 'mod.fr.f_back formatted argvalues')
199 for fname in files_to_clean_up:
200 try:
201 os.unlink(fname)
202 except:
203 pass
205 # Test classic-class method resolution order.
206 class A: pass
207 class B(A): pass
208 class C(A): pass
209 class D(B, C): pass
211 expected = (D, B, A, C)
212 got = inspect.getmro(D)
213 test(expected == got, "expected %r mro, got %r", expected, got)
215 # The same w/ new-class MRO.
216 class A(object): pass
217 class B(A): pass
218 class C(A): pass
219 class D(B, C): pass
221 expected = (D, B, C, A, object)
222 got = inspect.getmro(D)
223 test(expected == got, "expected %r mro, got %r", expected, got)
225 # Test classify_class_attrs.
226 def attrs_wo_objs(cls):
227 return [t[:3] for t in inspect.classify_class_attrs(cls)]
229 class A:
230 def s(): pass
231 s = staticmethod(s)
233 def c(cls): pass
234 c = classmethod(c)
236 def getp(self): pass
237 p = property(getp)
239 def m(self): pass
241 def m1(self): pass
243 datablob = '1'
245 attrs = attrs_wo_objs(A)
246 test(('s', 'static method', A) in attrs, 'missing static method')
247 test(('c', 'class method', A) in attrs, 'missing class method')
248 test(('p', 'property', A) in attrs, 'missing property')
249 test(('m', 'method', A) in attrs, 'missing plain method')
250 test(('m1', 'method', A) in attrs, 'missing plain method')
251 test(('datablob', 'data', A) in attrs, 'missing data')
253 class B(A):
254 def m(self): pass
256 attrs = attrs_wo_objs(B)
257 test(('s', 'static method', A) in attrs, 'missing static method')
258 test(('c', 'class method', A) in attrs, 'missing class method')
259 test(('p', 'property', A) in attrs, 'missing property')
260 test(('m', 'method', B) in attrs, 'missing plain method')
261 test(('m1', 'method', A) in attrs, 'missing plain method')
262 test(('datablob', 'data', A) in attrs, 'missing data')
265 class C(A):
266 def m(self): pass
267 def c(self): pass
269 attrs = attrs_wo_objs(C)
270 test(('s', 'static method', A) in attrs, 'missing static method')
271 test(('c', 'method', C) in attrs, 'missing plain method')
272 test(('p', 'property', A) in attrs, 'missing property')
273 test(('m', 'method', C) in attrs, 'missing plain method')
274 test(('m1', 'method', A) in attrs, 'missing plain method')
275 test(('datablob', 'data', A) in attrs, 'missing data')
277 class D(B, C):
278 def m1(self): pass
280 attrs = attrs_wo_objs(D)
281 test(('s', 'static method', A) in attrs, 'missing static method')
282 test(('c', 'class method', A) in attrs, 'missing class method')
283 test(('p', 'property', A) in attrs, 'missing property')
284 test(('m', 'method', B) in attrs, 'missing plain method')
285 test(('m1', 'method', D) in attrs, 'missing plain method')
286 test(('datablob', 'data', A) in attrs, 'missing data')
288 # Repeat all that, but w/ new-style classes.
290 class A(object):
292 def s(): pass
293 s = staticmethod(s)
295 def c(cls): pass
296 c = classmethod(c)
298 def getp(self): pass
299 p = property(getp)
301 def m(self): pass
303 def m1(self): pass
305 datablob = '1'
307 attrs = attrs_wo_objs(A)
308 test(('s', 'static method', A) in attrs, 'missing static method')
309 test(('c', 'class method', A) in attrs, 'missing class method')
310 test(('p', 'property', A) in attrs, 'missing property')
311 test(('m', 'method', A) in attrs, 'missing plain method')
312 test(('m1', 'method', A) in attrs, 'missing plain method')
313 test(('datablob', 'data', A) in attrs, 'missing data')
315 class B(A):
317 def m(self): pass
319 attrs = attrs_wo_objs(B)
320 test(('s', 'static method', A) in attrs, 'missing static method')
321 test(('c', 'class method', A) in attrs, 'missing class method')
322 test(('p', 'property', A) in attrs, 'missing property')
323 test(('m', 'method', B) in attrs, 'missing plain method')
324 test(('m1', 'method', A) in attrs, 'missing plain method')
325 test(('datablob', 'data', A) in attrs, 'missing data')
328 class C(A):
330 def m(self): pass
331 def c(self): pass
333 attrs = attrs_wo_objs(C)
334 test(('s', 'static method', A) in attrs, 'missing static method')
335 test(('c', 'method', C) in attrs, 'missing plain method')
336 test(('p', 'property', A) in attrs, 'missing property')
337 test(('m', 'method', C) in attrs, 'missing plain method')
338 test(('m1', 'method', A) in attrs, 'missing plain method')
339 test(('datablob', 'data', A) in attrs, 'missing data')
341 class D(B, C):
343 def m1(self): pass
345 attrs = attrs_wo_objs(D)
346 test(('s', 'static method', A) in attrs, 'missing static method')
347 test(('c', 'method', C) in attrs, 'missing plain method')
348 test(('p', 'property', A) in attrs, 'missing property')
349 test(('m', 'method', B) in attrs, 'missing plain method')
350 test(('m1', 'method', D) in attrs, 'missing plain method')
351 test(('datablob', 'data', A) in attrs, 'missing data')
353 args, varargs, varkw, defaults = inspect.getargspec(mod.eggs)
354 test(args == ['x', 'y'], 'mod.eggs args')
355 test(varargs == None, 'mod.eggs varargs')
356 test(varkw == None, 'mod.eggs varkw')
357 test(defaults == None, 'mod.eggs defaults')
358 test(inspect.formatargspec(args, varargs, varkw, defaults) ==
359 '(x, y)', 'mod.eggs formatted argspec')
360 args, varargs, varkw, defaults = inspect.getargspec(mod.spam)
361 test(args == ['a', 'b', 'c', 'd', ['e', ['f']]], 'mod.spam args')
362 test(varargs == 'g', 'mod.spam varargs')
363 test(varkw == 'h', 'mod.spam varkw')
364 test(defaults == (3, (4, (5,))), 'mod.spam defaults')
365 test(inspect.formatargspec(args, varargs, varkw, defaults) ==
366 '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)',
367 'mod.spam formatted argspec')
368 args, varargs, varkw, defaults = inspect.getargspec(A.m)
369 test(args == ['self'], 'A.m args')
370 test(varargs is None, 'A.m varargs')
371 test(varkw is None, 'A.m varkw')
372 test(defaults is None, 'A.m defaults')