source: python/trunk/Lib/test/test_inspect.py

Last change on this file was 391, checked in by dmik, 11 years ago

python: Merge vendor 2.7.6 to trunk.

  • Property svn:eol-style set to native
File size: 33.4 KB
Line 
1import re
2import sys
3import types
4import unittest
5import inspect
6import linecache
7import datetime
8from UserList import UserList
9from UserDict import UserDict
10
11from test.test_support import run_unittest, check_py3k_warnings
12
13with check_py3k_warnings(
14 ("tuple parameter unpacking has been removed", SyntaxWarning),
15 quiet=True):
16 from test import inspect_fodder as mod
17 from test import inspect_fodder2 as mod2
18
19# C module for test_findsource_binary
20import unicodedata
21
22# Functions tested in this suite:
23# ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode,
24# isbuiltin, isroutine, isgenerator, isgeneratorfunction, getmembers,
25# getdoc, getfile, getmodule, getsourcefile, getcomments, getsource,
26# getclasstree, getargspec, getargvalues, formatargspec, formatargvalues,
27# currentframe, stack, trace, isdatadescriptor
28
29# NOTE: There are some additional tests relating to interaction with
30# zipimport in the test_zipimport_support test module.
31
32modfile = mod.__file__
33if modfile.endswith(('c', 'o')):
34 modfile = modfile[:-1]
35
36import __builtin__
37
38try:
39 1 // 0
40except:
41 tb = sys.exc_traceback
42
43git = mod.StupidGit()
44
45class IsTestBase(unittest.TestCase):
46 predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode,
47 inspect.isframe, inspect.isfunction, inspect.ismethod,
48 inspect.ismodule, inspect.istraceback,
49 inspect.isgenerator, inspect.isgeneratorfunction])
50
51 def istest(self, predicate, exp):
52 obj = eval(exp)
53 self.assertTrue(predicate(obj), '%s(%s)' % (predicate.__name__, exp))
54
55 for other in self.predicates - set([predicate]):
56 if predicate == inspect.isgeneratorfunction and\
57 other == inspect.isfunction:
58 continue
59 self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp))
60
61def generator_function_example(self):
62 for i in xrange(2):
63 yield i
64
65class TestPredicates(IsTestBase):
66 def test_sixteen(self):
67 count = len(filter(lambda x:x.startswith('is'), dir(inspect)))
68 # This test is here for remember you to update Doc/library/inspect.rst
69 # which claims there are 16 such functions
70 expected = 16
71 err_msg = "There are %d (not %d) is* functions" % (count, expected)
72 self.assertEqual(count, expected, err_msg)
73
74
75 def test_excluding_predicates(self):
76 self.istest(inspect.isbuiltin, 'sys.exit')
77 self.istest(inspect.isbuiltin, '[].append')
78 self.istest(inspect.iscode, 'mod.spam.func_code')
79 self.istest(inspect.isframe, 'tb.tb_frame')
80 self.istest(inspect.isfunction, 'mod.spam')
81 self.istest(inspect.ismethod, 'mod.StupidGit.abuse')
82 self.istest(inspect.ismethod, 'git.argue')
83 self.istest(inspect.ismodule, 'mod')
84 self.istest(inspect.istraceback, 'tb')
85 self.istest(inspect.isdatadescriptor, '__builtin__.file.closed')
86 self.istest(inspect.isdatadescriptor, '__builtin__.file.softspace')
87 self.istest(inspect.isgenerator, '(x for x in xrange(2))')
88 self.istest(inspect.isgeneratorfunction, 'generator_function_example')
89 if hasattr(types, 'GetSetDescriptorType'):
90 self.istest(inspect.isgetsetdescriptor,
91 'type(tb.tb_frame).f_locals')
92 else:
93 self.assertFalse(inspect.isgetsetdescriptor(type(tb.tb_frame).f_locals))
94 if hasattr(types, 'MemberDescriptorType'):
95 self.istest(inspect.ismemberdescriptor, 'datetime.timedelta.days')
96 else:
97 self.assertFalse(inspect.ismemberdescriptor(datetime.timedelta.days))
98
99 def test_isroutine(self):
100 self.assertTrue(inspect.isroutine(mod.spam))
101 self.assertTrue(inspect.isroutine([].count))
102
103 def test_isclass(self):
104 self.istest(inspect.isclass, 'mod.StupidGit')
105 self.assertTrue(inspect.isclass(list))
106
107 class newstyle(object): pass
108 self.assertTrue(inspect.isclass(newstyle))
109
110 class CustomGetattr(object):
111 def __getattr__(self, attr):
112 return None
113 self.assertFalse(inspect.isclass(CustomGetattr()))
114
115 def test_get_slot_members(self):
116 class C(object):
117 __slots__ = ("a", "b")
118
119 x = C()
120 x.a = 42
121 members = dict(inspect.getmembers(x))
122 self.assertIn('a', members)
123 self.assertNotIn('b', members)
124
125 def test_isabstract(self):
126 from abc import ABCMeta, abstractmethod
127
128 class AbstractClassExample(object):
129 __metaclass__ = ABCMeta
130
131 @abstractmethod
132 def foo(self):
133 pass
134
135 class ClassExample(AbstractClassExample):
136 def foo(self):
137 pass
138
139 a = ClassExample()
140
141 # Test general behaviour.
142 self.assertTrue(inspect.isabstract(AbstractClassExample))
143 self.assertFalse(inspect.isabstract(ClassExample))
144 self.assertFalse(inspect.isabstract(a))
145 self.assertFalse(inspect.isabstract(int))
146 self.assertFalse(inspect.isabstract(5))
147
148
149class TestInterpreterStack(IsTestBase):
150 def __init__(self, *args, **kwargs):
151 unittest.TestCase.__init__(self, *args, **kwargs)
152
153 git.abuse(7, 8, 9)
154
155 def test_abuse_done(self):
156 self.istest(inspect.istraceback, 'git.ex[2]')
157 self.istest(inspect.isframe, 'mod.fr')
158
159 def test_stack(self):
160 self.assertTrue(len(mod.st) >= 5)
161 self.assertEqual(mod.st[0][1:],
162 (modfile, 16, 'eggs', [' st = inspect.stack()\n'], 0))
163 self.assertEqual(mod.st[1][1:],
164 (modfile, 9, 'spam', [' eggs(b + d, c + f)\n'], 0))
165 self.assertEqual(mod.st[2][1:],
166 (modfile, 43, 'argue', [' spam(a, b, c)\n'], 0))
167 self.assertEqual(mod.st[3][1:],
168 (modfile, 39, 'abuse', [' self.argue(a, b, c)\n'], 0))
169
170 def test_trace(self):
171 self.assertEqual(len(git.tr), 3)
172 self.assertEqual(git.tr[0][1:], (modfile, 43, 'argue',
173 [' spam(a, b, c)\n'], 0))
174 self.assertEqual(git.tr[1][1:], (modfile, 9, 'spam',
175 [' eggs(b + d, c + f)\n'], 0))
176 self.assertEqual(git.tr[2][1:], (modfile, 18, 'eggs',
177 [' q = y // 0\n'], 0))
178
179 def test_frame(self):
180 args, varargs, varkw, locals = inspect.getargvalues(mod.fr)
181 self.assertEqual(args, ['x', 'y'])
182 self.assertEqual(varargs, None)
183 self.assertEqual(varkw, None)
184 self.assertEqual(locals, {'x': 11, 'p': 11, 'y': 14})
185 self.assertEqual(inspect.formatargvalues(args, varargs, varkw, locals),
186 '(x=11, y=14)')
187
188 def test_previous_frame(self):
189 args, varargs, varkw, locals = inspect.getargvalues(mod.fr.f_back)
190 self.assertEqual(args, ['a', 'b', 'c', 'd', ['e', ['f']]])
191 self.assertEqual(varargs, 'g')
192 self.assertEqual(varkw, 'h')
193 self.assertEqual(inspect.formatargvalues(args, varargs, varkw, locals),
194 '(a=7, b=8, c=9, d=3, (e=4, (f=5,)), *g=(), **h={})')
195
196class GetSourceBase(unittest.TestCase):
197 # Subclasses must override.
198 fodderFile = None
199
200 def __init__(self, *args, **kwargs):
201 unittest.TestCase.__init__(self, *args, **kwargs)
202
203 with open(inspect.getsourcefile(self.fodderFile)) as fp:
204 self.source = fp.read()
205
206 def sourcerange(self, top, bottom):
207 lines = self.source.split("\n")
208 return "\n".join(lines[top-1:bottom]) + "\n"
209
210 def assertSourceEqual(self, obj, top, bottom):
211 self.assertEqual(inspect.getsource(obj),
212 self.sourcerange(top, bottom))
213
214class TestRetrievingSourceCode(GetSourceBase):
215 fodderFile = mod
216
217 def test_getclasses(self):
218 classes = inspect.getmembers(mod, inspect.isclass)
219 self.assertEqual(classes,
220 [('FesteringGob', mod.FesteringGob),
221 ('MalodorousPervert', mod.MalodorousPervert),
222 ('ParrotDroppings', mod.ParrotDroppings),
223 ('StupidGit', mod.StupidGit),
224 ('Tit', mod.MalodorousPervert),
225 ])
226 tree = inspect.getclasstree([cls[1] for cls in classes])
227 self.assertEqual(tree,
228 [(mod.ParrotDroppings, ()),
229 [(mod.FesteringGob, (mod.MalodorousPervert,
230 mod.ParrotDroppings))
231 ],
232 (mod.StupidGit, ()),
233 [(mod.MalodorousPervert, (mod.StupidGit,)),
234 [(mod.FesteringGob, (mod.MalodorousPervert,
235 mod.ParrotDroppings))
236 ]
237 ]
238 ])
239 tree = inspect.getclasstree([cls[1] for cls in classes], True)
240 self.assertEqual(tree,
241 [(mod.ParrotDroppings, ()),
242 (mod.StupidGit, ()),
243 [(mod.MalodorousPervert, (mod.StupidGit,)),
244 [(mod.FesteringGob, (mod.MalodorousPervert,
245 mod.ParrotDroppings))
246 ]
247 ]
248 ])
249
250 def test_getfunctions(self):
251 functions = inspect.getmembers(mod, inspect.isfunction)
252 self.assertEqual(functions, [('eggs', mod.eggs),
253 ('spam', mod.spam)])
254
255 @unittest.skipIf(sys.flags.optimize >= 2,
256 "Docstrings are omitted with -O2 and above")
257 def test_getdoc(self):
258 self.assertEqual(inspect.getdoc(mod), 'A module docstring.')
259 self.assertEqual(inspect.getdoc(mod.StupidGit),
260 'A longer,\n\nindented\n\ndocstring.')
261 self.assertEqual(inspect.getdoc(git.abuse),
262 'Another\n\ndocstring\n\ncontaining\n\ntabs')
263
264 def test_cleandoc(self):
265 self.assertEqual(inspect.cleandoc('An\n indented\n docstring.'),
266 'An\nindented\ndocstring.')
267
268 def test_getcomments(self):
269 self.assertEqual(inspect.getcomments(mod), '# line 1\n')
270 self.assertEqual(inspect.getcomments(mod.StupidGit), '# line 20\n')
271
272 def test_getmodule(self):
273 # Check actual module
274 self.assertEqual(inspect.getmodule(mod), mod)
275 # Check class (uses __module__ attribute)
276 self.assertEqual(inspect.getmodule(mod.StupidGit), mod)
277 # Check a method (no __module__ attribute, falls back to filename)
278 self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod)
279 # Do it again (check the caching isn't broken)
280 self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod)
281 # Check a builtin
282 self.assertEqual(inspect.getmodule(str), sys.modules["__builtin__"])
283 # Check filename override
284 self.assertEqual(inspect.getmodule(None, modfile), mod)
285
286 def test_getsource(self):
287 self.assertSourceEqual(git.abuse, 29, 39)
288 self.assertSourceEqual(mod.StupidGit, 21, 46)
289
290 def test_getsourcefile(self):
291 self.assertEqual(inspect.getsourcefile(mod.spam), modfile)
292 self.assertEqual(inspect.getsourcefile(git.abuse), modfile)
293 fn = "_non_existing_filename_used_for_sourcefile_test.py"
294 co = compile("None", fn, "exec")
295 self.assertEqual(inspect.getsourcefile(co), None)
296 linecache.cache[co.co_filename] = (1, None, "None", co.co_filename)
297 self.assertEqual(inspect.getsourcefile(co), fn)
298
299 def test_getfile(self):
300 self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__)
301
302 def test_getmodule_recursion(self):
303 from types import ModuleType
304 name = '__inspect_dummy'
305 m = sys.modules[name] = ModuleType(name)
306 m.__file__ = "<string>" # hopefully not a real filename...
307 m.__loader__ = "dummy" # pretend the filename is understood by a loader
308 exec "def x(): pass" in m.__dict__
309 self.assertEqual(inspect.getsourcefile(m.x.func_code), '<string>')
310 del sys.modules[name]
311 inspect.getmodule(compile('a=10','','single'))
312
313 def test_proceed_with_fake_filename(self):
314 '''doctest monkeypatches linecache to enable inspection'''
315 fn, source = '<test>', 'def x(): pass\n'
316 getlines = linecache.getlines
317 def monkey(filename, module_globals=None):
318 if filename == fn:
319 return source.splitlines(True)
320 else:
321 return getlines(filename, module_globals)
322 linecache.getlines = monkey
323 try:
324 ns = {}
325 exec compile(source, fn, 'single') in ns
326 inspect.getsource(ns["x"])
327 finally:
328 linecache.getlines = getlines
329
330class TestDecorators(GetSourceBase):
331 fodderFile = mod2
332
333 def test_wrapped_decorator(self):
334 self.assertSourceEqual(mod2.wrapped, 14, 17)
335
336 def test_replacing_decorator(self):
337 self.assertSourceEqual(mod2.gone, 9, 10)
338
339class TestOneliners(GetSourceBase):
340 fodderFile = mod2
341 def test_oneline_lambda(self):
342 # Test inspect.getsource with a one-line lambda function.
343 self.assertSourceEqual(mod2.oll, 25, 25)
344
345 def test_threeline_lambda(self):
346 # Test inspect.getsource with a three-line lambda function,
347 # where the second and third lines are _not_ indented.
348 self.assertSourceEqual(mod2.tll, 28, 30)
349
350 def test_twoline_indented_lambda(self):
351 # Test inspect.getsource with a two-line lambda function,
352 # where the second line _is_ indented.
353 self.assertSourceEqual(mod2.tlli, 33, 34)
354
355 def test_onelinefunc(self):
356 # Test inspect.getsource with a regular one-line function.
357 self.assertSourceEqual(mod2.onelinefunc, 37, 37)
358
359 def test_manyargs(self):
360 # Test inspect.getsource with a regular function where
361 # the arguments are on two lines and _not_ indented and
362 # the body on the second line with the last arguments.
363 self.assertSourceEqual(mod2.manyargs, 40, 41)
364
365 def test_twolinefunc(self):
366 # Test inspect.getsource with a regular function where
367 # the body is on two lines, following the argument list and
368 # continued on the next line by a \\.
369 self.assertSourceEqual(mod2.twolinefunc, 44, 45)
370
371 def test_lambda_in_list(self):
372 # Test inspect.getsource with a one-line lambda function
373 # defined in a list, indented.
374 self.assertSourceEqual(mod2.a[1], 49, 49)
375
376 def test_anonymous(self):
377 # Test inspect.getsource with a lambda function defined
378 # as argument to another function.
379 self.assertSourceEqual(mod2.anonymous, 55, 55)
380
381class TestBuggyCases(GetSourceBase):
382 fodderFile = mod2
383
384 def test_with_comment(self):
385 self.assertSourceEqual(mod2.with_comment, 58, 59)
386
387 def test_multiline_sig(self):
388 self.assertSourceEqual(mod2.multiline_sig[0], 63, 64)
389
390 def test_nested_class(self):
391 self.assertSourceEqual(mod2.func69().func71, 71, 72)
392
393 def test_one_liner_followed_by_non_name(self):
394 self.assertSourceEqual(mod2.func77, 77, 77)
395
396 def test_one_liner_dedent_non_name(self):
397 self.assertSourceEqual(mod2.cls82.func83, 83, 83)
398
399 def test_with_comment_instead_of_docstring(self):
400 self.assertSourceEqual(mod2.func88, 88, 90)
401
402 def test_method_in_dynamic_class(self):
403 self.assertSourceEqual(mod2.method_in_dynamic_class, 95, 97)
404
405 @unittest.skipIf(
406 not hasattr(unicodedata, '__file__') or
407 unicodedata.__file__[-4:] in (".pyc", ".pyo"),
408 "unicodedata is not an external binary module")
409 def test_findsource_binary(self):
410 self.assertRaises(IOError, inspect.getsource, unicodedata)
411 self.assertRaises(IOError, inspect.findsource, unicodedata)
412
413 def test_findsource_code_in_linecache(self):
414 lines = ["x=1"]
415 co = compile(lines[0], "_dynamically_created_file", "exec")
416 self.assertRaises(IOError, inspect.findsource, co)
417 self.assertRaises(IOError, inspect.getsource, co)
418 linecache.cache[co.co_filename] = (1, None, lines, co.co_filename)
419 self.assertEqual(inspect.findsource(co), (lines,0))
420 self.assertEqual(inspect.getsource(co), lines[0])
421
422 def test_findsource_without_filename(self):
423 for fname in ['', '<string>']:
424 co = compile('x=1', fname, "exec")
425 self.assertRaises(IOError, inspect.findsource, co)
426 self.assertRaises(IOError, inspect.getsource, co)
427
428
429class _BrokenDataDescriptor(object):
430 """
431 A broken data descriptor. See bug #1785.
432 """
433 def __get__(*args):
434 raise AssertionError("should not __get__ data descriptors")
435
436 def __set__(*args):
437 raise RuntimeError
438
439 def __getattr__(*args):
440 raise AssertionError("should not __getattr__ data descriptors")
441
442
443class _BrokenMethodDescriptor(object):
444 """
445 A broken method descriptor. See bug #1785.
446 """
447 def __get__(*args):
448 raise AssertionError("should not __get__ method descriptors")
449
450 def __getattr__(*args):
451 raise AssertionError("should not __getattr__ method descriptors")
452
453
454# Helper for testing classify_class_attrs.
455def attrs_wo_objs(cls):
456 return [t[:3] for t in inspect.classify_class_attrs(cls)]
457
458
459class TestClassesAndFunctions(unittest.TestCase):
460 def test_classic_mro(self):
461 # Test classic-class method resolution order.
462 class A: pass
463 class B(A): pass
464 class C(A): pass
465 class D(B, C): pass
466
467 expected = (D, B, A, C)
468 got = inspect.getmro(D)
469 self.assertEqual(expected, got)
470
471 def test_newstyle_mro(self):
472 # The same w/ new-class MRO.
473 class A(object): pass
474 class B(A): pass
475 class C(A): pass
476 class D(B, C): pass
477
478 expected = (D, B, C, A, object)
479 got = inspect.getmro(D)
480 self.assertEqual(expected, got)
481
482 def assertArgSpecEquals(self, routine, args_e, varargs_e = None,
483 varkw_e = None, defaults_e = None,
484 formatted = None):
485 args, varargs, varkw, defaults = inspect.getargspec(routine)
486 self.assertEqual(args, args_e)
487 self.assertEqual(varargs, varargs_e)
488 self.assertEqual(varkw, varkw_e)
489 self.assertEqual(defaults, defaults_e)
490 if formatted is not None:
491 self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults),
492 formatted)
493
494 def test_getargspec(self):
495 self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted = '(x, y)')
496
497 self.assertArgSpecEquals(mod.spam,
498 ['a', 'b', 'c', 'd', ['e', ['f']]],
499 'g', 'h', (3, (4, (5,))),
500 '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)')
501
502 def test_getargspec_method(self):
503 class A(object):
504 def m(self):
505 pass
506 self.assertArgSpecEquals(A.m, ['self'])
507
508 def test_getargspec_sublistofone(self):
509 with check_py3k_warnings(
510 ("tuple parameter unpacking has been removed", SyntaxWarning),
511 ("parenthesized argument names are invalid", SyntaxWarning)):
512 exec 'def sublistOfOne((foo,)): return 1'
513 self.assertArgSpecEquals(sublistOfOne, [['foo']])
514
515 exec 'def fakeSublistOfOne((foo)): return 1'
516 self.assertArgSpecEquals(fakeSublistOfOne, ['foo'])
517
518
519 def _classify_test(self, newstyle):
520 """Helper for testing that classify_class_attrs finds a bunch of
521 different kinds of attributes on a given class.
522 """
523 if newstyle:
524 base = object
525 else:
526 class base:
527 pass
528
529 class A(base):
530 def s(): pass
531 s = staticmethod(s)
532
533 def c(cls): pass
534 c = classmethod(c)
535
536 def getp(self): pass
537 p = property(getp)
538
539 def m(self): pass
540
541 def m1(self): pass
542
543 datablob = '1'
544
545 dd = _BrokenDataDescriptor()
546 md = _BrokenMethodDescriptor()
547
548 attrs = attrs_wo_objs(A)
549 self.assertIn(('s', 'static method', A), attrs, 'missing static method')
550 self.assertIn(('c', 'class method', A), attrs, 'missing class method')
551 self.assertIn(('p', 'property', A), attrs, 'missing property')
552 self.assertIn(('m', 'method', A), attrs, 'missing plain method')
553 self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
554 self.assertIn(('datablob', 'data', A), attrs, 'missing data')
555 self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
556 self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
557
558 class B(A):
559 def m(self): pass
560
561 attrs = attrs_wo_objs(B)
562 self.assertIn(('s', 'static method', A), attrs, 'missing static method')
563 self.assertIn(('c', 'class method', A), attrs, 'missing class method')
564 self.assertIn(('p', 'property', A), attrs, 'missing property')
565 self.assertIn(('m', 'method', B), attrs, 'missing plain method')
566 self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
567 self.assertIn(('datablob', 'data', A), attrs, 'missing data')
568 self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
569 self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
570
571
572 class C(A):
573 def m(self): pass
574 def c(self): pass
575
576 attrs = attrs_wo_objs(C)
577 self.assertIn(('s', 'static method', A), attrs, 'missing static method')
578 self.assertIn(('c', 'method', C), attrs, 'missing plain method')
579 self.assertIn(('p', 'property', A), attrs, 'missing property')
580 self.assertIn(('m', 'method', C), attrs, 'missing plain method')
581 self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
582 self.assertIn(('datablob', 'data', A), attrs, 'missing data')
583 self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
584 self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
585
586 class D(B, C):
587 def m1(self): pass
588
589 attrs = attrs_wo_objs(D)
590 self.assertIn(('s', 'static method', A), attrs, 'missing static method')
591 if newstyle:
592 self.assertIn(('c', 'method', C), attrs, 'missing plain method')
593 else:
594 self.assertIn(('c', 'class method', A), attrs, 'missing class method')
595 self.assertIn(('p', 'property', A), attrs, 'missing property')
596 self.assertIn(('m', 'method', B), attrs, 'missing plain method')
597 self.assertIn(('m1', 'method', D), attrs, 'missing plain method')
598 self.assertIn(('datablob', 'data', A), attrs, 'missing data')
599 self.assertIn(('md', 'method', A), attrs, 'missing method descriptor')
600 self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor')
601
602
603 def test_classify_oldstyle(self):
604 """classify_class_attrs finds static methods, class methods,
605 properties, normal methods, and data attributes on an old-style
606 class.
607 """
608 self._classify_test(False)
609
610
611 def test_classify_newstyle(self):
612 """Just like test_classify_oldstyle, but for a new-style class.
613 """
614 self._classify_test(True)
615
616 def test_classify_builtin_types(self):
617 # Simple sanity check that all built-in types can have their
618 # attributes classified.
619 for name in dir(__builtin__):
620 builtin = getattr(__builtin__, name)
621 if isinstance(builtin, type):
622 inspect.classify_class_attrs(builtin)
623
624 def test_getmembers_method(self):
625 # Old-style classes
626 class B:
627 def f(self):
628 pass
629
630 self.assertIn(('f', B.f), inspect.getmembers(B))
631 # contrary to spec, ismethod() is also True for unbound methods
632 # (see #1785)
633 self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod))
634 b = B()
635 self.assertIn(('f', b.f), inspect.getmembers(b))
636 self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod))
637
638 # New-style classes
639 class B(object):
640 def f(self):
641 pass
642
643 self.assertIn(('f', B.f), inspect.getmembers(B))
644 self.assertIn(('f', B.f), inspect.getmembers(B, inspect.ismethod))
645 b = B()
646 self.assertIn(('f', b.f), inspect.getmembers(b))
647 self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod))
648
649
650class TestGetcallargsFunctions(unittest.TestCase):
651
652 # tuple parameters are named '.1', '.2', etc.
653 is_tuplename = re.compile(r'^\.\d+$').match
654
655 def assertEqualCallArgs(self, func, call_params_string, locs=None):
656 locs = dict(locs or {}, func=func)
657 r1 = eval('func(%s)' % call_params_string, None, locs)
658 r2 = eval('inspect.getcallargs(func, %s)' % call_params_string, None,
659 locs)
660 self.assertEqual(r1, r2)
661
662 def assertEqualException(self, func, call_param_string, locs=None):
663 locs = dict(locs or {}, func=func)
664 try:
665 eval('func(%s)' % call_param_string, None, locs)
666 except Exception, ex1:
667 pass
668 else:
669 self.fail('Exception not raised')
670 try:
671 eval('inspect.getcallargs(func, %s)' % call_param_string, None,
672 locs)
673 except Exception, ex2:
674 pass
675 else:
676 self.fail('Exception not raised')
677 self.assertIs(type(ex1), type(ex2))
678 self.assertEqual(str(ex1), str(ex2))
679
680 def makeCallable(self, signature):
681 """Create a function that returns its locals(), excluding the
682 autogenerated '.1', '.2', etc. tuple param names (if any)."""
683 with check_py3k_warnings(
684 ("tuple parameter unpacking has been removed", SyntaxWarning),
685 quiet=True):
686 code = ("lambda %s: dict(i for i in locals().items() "
687 "if not is_tuplename(i[0]))")
688 return eval(code % signature, {'is_tuplename' : self.is_tuplename})
689
690 def test_plain(self):
691 f = self.makeCallable('a, b=1')
692 self.assertEqualCallArgs(f, '2')
693 self.assertEqualCallArgs(f, '2, 3')
694 self.assertEqualCallArgs(f, 'a=2')
695 self.assertEqualCallArgs(f, 'b=3, a=2')
696 self.assertEqualCallArgs(f, '2, b=3')
697 # expand *iterable / **mapping
698 self.assertEqualCallArgs(f, '*(2,)')
699 self.assertEqualCallArgs(f, '*[2]')
700 self.assertEqualCallArgs(f, '*(2, 3)')
701 self.assertEqualCallArgs(f, '*[2, 3]')
702 self.assertEqualCallArgs(f, '**{"a":2}')
703 self.assertEqualCallArgs(f, 'b=3, **{"a":2}')
704 self.assertEqualCallArgs(f, '2, **{"b":3}')
705 self.assertEqualCallArgs(f, '**{"b":3, "a":2}')
706 # expand UserList / UserDict
707 self.assertEqualCallArgs(f, '*UserList([2])')
708 self.assertEqualCallArgs(f, '*UserList([2, 3])')
709 self.assertEqualCallArgs(f, '**UserDict(a=2)')
710 self.assertEqualCallArgs(f, '2, **UserDict(b=3)')
711 self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3)')
712 # unicode keyword args
713 self.assertEqualCallArgs(f, '**{u"a":2}')
714 self.assertEqualCallArgs(f, 'b=3, **{u"a":2}')
715 self.assertEqualCallArgs(f, '2, **{u"b":3}')
716 self.assertEqualCallArgs(f, '**{u"b":3, u"a":2}')
717
718 def test_varargs(self):
719 f = self.makeCallable('a, b=1, *c')
720 self.assertEqualCallArgs(f, '2')
721 self.assertEqualCallArgs(f, '2, 3')
722 self.assertEqualCallArgs(f, '2, 3, 4')
723 self.assertEqualCallArgs(f, '*(2,3,4)')
724 self.assertEqualCallArgs(f, '2, *[3,4]')
725 self.assertEqualCallArgs(f, '2, 3, *UserList([4])')
726
727 def test_varkw(self):
728 f = self.makeCallable('a, b=1, **c')
729 self.assertEqualCallArgs(f, 'a=2')
730 self.assertEqualCallArgs(f, '2, b=3, c=4')
731 self.assertEqualCallArgs(f, 'b=3, a=2, c=4')
732 self.assertEqualCallArgs(f, 'c=4, **{"a":2, "b":3}')
733 self.assertEqualCallArgs(f, '2, c=4, **{"b":3}')
734 self.assertEqualCallArgs(f, 'b=2, **{"a":3, "c":4}')
735 self.assertEqualCallArgs(f, '**UserDict(a=2, b=3, c=4)')
736 self.assertEqualCallArgs(f, '2, c=4, **UserDict(b=3)')
737 self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3, c=4)')
738 # unicode keyword args
739 self.assertEqualCallArgs(f, 'c=4, **{u"a":2, u"b":3}')
740 self.assertEqualCallArgs(f, '2, c=4, **{u"b":3}')
741 self.assertEqualCallArgs(f, 'b=2, **{u"a":3, u"c":4}')
742
743 def test_varkw_only(self):
744 # issue11256:
745 f = self.makeCallable('**c')
746 self.assertEqualCallArgs(f, '')
747 self.assertEqualCallArgs(f, 'a=1')
748 self.assertEqualCallArgs(f, 'a=1, b=2')
749 self.assertEqualCallArgs(f, 'c=3, **{"a": 1, "b": 2}')
750 self.assertEqualCallArgs(f, '**UserDict(a=1, b=2)')
751 self.assertEqualCallArgs(f, 'c=3, **UserDict(a=1, b=2)')
752
753 def test_tupleargs(self):
754 f = self.makeCallable('(b,c), (d,(e,f))=(0,[1,2])')
755 self.assertEqualCallArgs(f, '(2,3)')
756 self.assertEqualCallArgs(f, '[2,3]')
757 self.assertEqualCallArgs(f, 'UserList([2,3])')
758 self.assertEqualCallArgs(f, '(2,3), (4,(5,6))')
759 self.assertEqualCallArgs(f, '(2,3), (4,[5,6])')
760 self.assertEqualCallArgs(f, '(2,3), [4,UserList([5,6])]')
761
762 def test_multiple_features(self):
763 f = self.makeCallable('a, b=2, (c,(d,e))=(3,[4,5]), *f, **g')
764 self.assertEqualCallArgs(f, '2, 3, (4,[5,6]), 7')
765 self.assertEqualCallArgs(f, '2, 3, *[(4,[5,6]), 7], x=8')
766 self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]')
767 self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9')
768 self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9')
769 self.assertEqualCallArgs(f, 'x=8, *UserList([2, 3, (4,[5,6])]), '
770 '**{"y":9, "z":10}')
771 self.assertEqualCallArgs(f, '2, x=8, *UserList([3, (4,[5,6])]), '
772 '**UserDict(y=9, z=10)')
773
774 def test_errors(self):
775 f0 = self.makeCallable('')
776 f1 = self.makeCallable('a, b')
777 f2 = self.makeCallable('a, b=1')
778 # f0 takes no arguments
779 self.assertEqualException(f0, '1')
780 self.assertEqualException(f0, 'x=1')
781 self.assertEqualException(f0, '1,x=1')
782 # f1 takes exactly 2 arguments
783 self.assertEqualException(f1, '')
784 self.assertEqualException(f1, '1')
785 self.assertEqualException(f1, 'a=2')
786 self.assertEqualException(f1, 'b=3')
787 # f2 takes at least 1 argument
788 self.assertEqualException(f2, '')
789 self.assertEqualException(f2, 'b=3')
790 for f in f1, f2:
791 # f1/f2 takes exactly/at most 2 arguments
792 self.assertEqualException(f, '2, 3, 4')
793 self.assertEqualException(f, '1, 2, 3, a=1')
794 self.assertEqualException(f, '2, 3, 4, c=5')
795 self.assertEqualException(f, '2, 3, 4, a=1, c=5')
796 # f got an unexpected keyword argument
797 self.assertEqualException(f, 'c=2')
798 self.assertEqualException(f, '2, c=3')
799 self.assertEqualException(f, '2, 3, c=4')
800 self.assertEqualException(f, '2, c=4, b=3')
801 self.assertEqualException(f, '**{u"\u03c0\u03b9": 4}')
802 # f got multiple values for keyword argument
803 self.assertEqualException(f, '1, a=2')
804 self.assertEqualException(f, '1, **{"a":2}')
805 self.assertEqualException(f, '1, 2, b=3')
806 # XXX: Python inconsistency
807 # - for functions and bound methods: unexpected keyword 'c'
808 # - for unbound methods: multiple values for keyword 'a'
809 #self.assertEqualException(f, '1, c=3, a=2')
810 f = self.makeCallable('(a,b)=(0,1)')
811 self.assertEqualException(f, '1')
812 self.assertEqualException(f, '[1]')
813 self.assertEqualException(f, '(1,2,3)')
814 # issue11256:
815 f3 = self.makeCallable('**c')
816 self.assertEqualException(f3, '1, 2')
817 self.assertEqualException(f3, '1, 2, a=1, b=2')
818
819class TestGetcallargsMethods(TestGetcallargsFunctions):
820
821 def setUp(self):
822 class Foo(object):
823 pass
824 self.cls = Foo
825 self.inst = Foo()
826
827 def makeCallable(self, signature):
828 assert 'self' not in signature
829 mk = super(TestGetcallargsMethods, self).makeCallable
830 self.cls.method = mk('self, ' + signature)
831 return self.inst.method
832
833class TestGetcallargsUnboundMethods(TestGetcallargsMethods):
834
835 def makeCallable(self, signature):
836 super(TestGetcallargsUnboundMethods, self).makeCallable(signature)
837 return self.cls.method
838
839 def assertEqualCallArgs(self, func, call_params_string, locs=None):
840 return super(TestGetcallargsUnboundMethods, self).assertEqualCallArgs(
841 *self._getAssertEqualParams(func, call_params_string, locs))
842
843 def assertEqualException(self, func, call_params_string, locs=None):
844 return super(TestGetcallargsUnboundMethods, self).assertEqualException(
845 *self._getAssertEqualParams(func, call_params_string, locs))
846
847 def _getAssertEqualParams(self, func, call_params_string, locs=None):
848 assert 'inst' not in call_params_string
849 locs = dict(locs or {}, inst=self.inst)
850 return (func, 'inst,' + call_params_string, locs)
851
852def test_main():
853 run_unittest(
854 TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
855 TestInterpreterStack, TestClassesAndFunctions, TestPredicates,
856 TestGetcallargsFunctions, TestGetcallargsMethods,
857 TestGetcallargsUnboundMethods)
858
859if __name__ == "__main__":
860 test_main()
Note: See TracBrowser for help on using the repository browser.