fcdfd94f167c7c2e97c758b8f25f975afdf3d962
[profile/ivi/python.git] / Lib / test / test_inspect.py
1 import re
2 import sys
3 import types
4 import unittest
5 import inspect
6 import linecache
7 import datetime
8 from UserList import UserList
9 from UserDict import UserDict
10
11 from test.test_support import run_unittest, check_py3k_warnings
12
13 with 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
20 import 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
32 modfile = mod.__file__
33 if modfile.endswith(('c', 'o')):
34     modfile = modfile[:-1]
35
36 import __builtin__
37
38 try:
39     1 // 0
40 except:
41     tb = sys.exc_traceback
42
43 git = mod.StupidGit()
44
45 class 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
61 def generator_function_example(self):
62     for i in xrange(2):
63         yield i
64
65 class 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
149 class 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
196 class 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
214 class 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         tree = inspect.getclasstree([cls[1] for cls in classes], 1)
225         self.assertEqual(tree,
226                          [(mod.ParrotDroppings, ()),
227                           (mod.StupidGit, ()),
228                           [(mod.MalodorousPervert, (mod.StupidGit,)),
229                            [(mod.FesteringGob, (mod.MalodorousPervert,
230                                                    mod.ParrotDroppings))
231                             ]
232                            ]
233                           ])
234
235     def test_getfunctions(self):
236         functions = inspect.getmembers(mod, inspect.isfunction)
237         self.assertEqual(functions, [('eggs', mod.eggs),
238                                      ('spam', mod.spam)])
239
240     @unittest.skipIf(sys.flags.optimize >= 2,
241                      "Docstrings are omitted with -O2 and above")
242     def test_getdoc(self):
243         self.assertEqual(inspect.getdoc(mod), 'A module docstring.')
244         self.assertEqual(inspect.getdoc(mod.StupidGit),
245                          'A longer,\n\nindented\n\ndocstring.')
246         self.assertEqual(inspect.getdoc(git.abuse),
247                          'Another\n\ndocstring\n\ncontaining\n\ntabs')
248
249     def test_cleandoc(self):
250         self.assertEqual(inspect.cleandoc('An\n    indented\n    docstring.'),
251                          'An\nindented\ndocstring.')
252
253     def test_getcomments(self):
254         self.assertEqual(inspect.getcomments(mod), '# line 1\n')
255         self.assertEqual(inspect.getcomments(mod.StupidGit), '# line 20\n')
256
257     def test_getmodule(self):
258         # Check actual module
259         self.assertEqual(inspect.getmodule(mod), mod)
260         # Check class (uses __module__ attribute)
261         self.assertEqual(inspect.getmodule(mod.StupidGit), mod)
262         # Check a method (no __module__ attribute, falls back to filename)
263         self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod)
264         # Do it again (check the caching isn't broken)
265         self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod)
266         # Check a builtin
267         self.assertEqual(inspect.getmodule(str), sys.modules["__builtin__"])
268         # Check filename override
269         self.assertEqual(inspect.getmodule(None, modfile), mod)
270
271     def test_getsource(self):
272         self.assertSourceEqual(git.abuse, 29, 39)
273         self.assertSourceEqual(mod.StupidGit, 21, 46)
274
275     def test_getsourcefile(self):
276         self.assertEqual(inspect.getsourcefile(mod.spam), modfile)
277         self.assertEqual(inspect.getsourcefile(git.abuse), modfile)
278         fn = "_non_existing_filename_used_for_sourcefile_test.py"
279         co = compile("None", fn, "exec")
280         self.assertEqual(inspect.getsourcefile(co), None)
281         linecache.cache[co.co_filename] = (1, None, "None", co.co_filename)
282         self.assertEqual(inspect.getsourcefile(co), fn)
283
284     def test_getfile(self):
285         self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__)
286
287     def test_getmodule_recursion(self):
288         from types import ModuleType
289         name = '__inspect_dummy'
290         m = sys.modules[name] = ModuleType(name)
291         m.__file__ = "<string>" # hopefully not a real filename...
292         m.__loader__ = "dummy"  # pretend the filename is understood by a loader
293         exec "def x(): pass" in m.__dict__
294         self.assertEqual(inspect.getsourcefile(m.x.func_code), '<string>')
295         del sys.modules[name]
296         inspect.getmodule(compile('a=10','','single'))
297
298 class TestDecorators(GetSourceBase):
299     fodderFile = mod2
300
301     def test_wrapped_decorator(self):
302         self.assertSourceEqual(mod2.wrapped, 14, 17)
303
304     def test_replacing_decorator(self):
305         self.assertSourceEqual(mod2.gone, 9, 10)
306
307 class TestOneliners(GetSourceBase):
308     fodderFile = mod2
309     def test_oneline_lambda(self):
310         # Test inspect.getsource with a one-line lambda function.
311         self.assertSourceEqual(mod2.oll, 25, 25)
312
313     def test_threeline_lambda(self):
314         # Test inspect.getsource with a three-line lambda function,
315         # where the second and third lines are _not_ indented.
316         self.assertSourceEqual(mod2.tll, 28, 30)
317
318     def test_twoline_indented_lambda(self):
319         # Test inspect.getsource with a two-line lambda function,
320         # where the second line _is_ indented.
321         self.assertSourceEqual(mod2.tlli, 33, 34)
322
323     def test_onelinefunc(self):
324         # Test inspect.getsource with a regular one-line function.
325         self.assertSourceEqual(mod2.onelinefunc, 37, 37)
326
327     def test_manyargs(self):
328         # Test inspect.getsource with a regular function where
329         # the arguments are on two lines and _not_ indented and
330         # the body on the second line with the last arguments.
331         self.assertSourceEqual(mod2.manyargs, 40, 41)
332
333     def test_twolinefunc(self):
334         # Test inspect.getsource with a regular function where
335         # the body is on two lines, following the argument list and
336         # continued on the next line by a \\.
337         self.assertSourceEqual(mod2.twolinefunc, 44, 45)
338
339     def test_lambda_in_list(self):
340         # Test inspect.getsource with a one-line lambda function
341         # defined in a list, indented.
342         self.assertSourceEqual(mod2.a[1], 49, 49)
343
344     def test_anonymous(self):
345         # Test inspect.getsource with a lambda function defined
346         # as argument to another function.
347         self.assertSourceEqual(mod2.anonymous, 55, 55)
348
349 class TestBuggyCases(GetSourceBase):
350     fodderFile = mod2
351
352     def test_with_comment(self):
353         self.assertSourceEqual(mod2.with_comment, 58, 59)
354
355     def test_multiline_sig(self):
356         self.assertSourceEqual(mod2.multiline_sig[0], 63, 64)
357
358     def test_nested_class(self):
359         self.assertSourceEqual(mod2.func69().func71, 71, 72)
360
361     def test_one_liner_followed_by_non_name(self):
362         self.assertSourceEqual(mod2.func77, 77, 77)
363
364     def test_one_liner_dedent_non_name(self):
365         self.assertSourceEqual(mod2.cls82.func83, 83, 83)
366
367     def test_with_comment_instead_of_docstring(self):
368         self.assertSourceEqual(mod2.func88, 88, 90)
369
370     def test_method_in_dynamic_class(self):
371         self.assertSourceEqual(mod2.method_in_dynamic_class, 95, 97)
372
373     @unittest.skipIf(
374         not hasattr(unicodedata, '__file__') or
375             unicodedata.__file__[-4:] in (".pyc", ".pyo"),
376         "unicodedata is not an external binary module")
377     def test_findsource_binary(self):
378         self.assertRaises(IOError, inspect.getsource, unicodedata)
379         self.assertRaises(IOError, inspect.findsource, unicodedata)
380
381     def test_findsource_code_in_linecache(self):
382         lines = ["x=1"]
383         co = compile(lines[0], "_dynamically_created_file", "exec")
384         self.assertRaises(IOError, inspect.findsource, co)
385         self.assertRaises(IOError, inspect.getsource, co)
386         linecache.cache[co.co_filename] = (1, None, lines, co.co_filename)
387         self.assertEqual(inspect.findsource(co), (lines,0))
388         self.assertEqual(inspect.getsource(co), lines[0])
389
390 # Helper for testing classify_class_attrs.
391 def attrs_wo_objs(cls):
392     return [t[:3] for t in inspect.classify_class_attrs(cls)]
393
394 class TestClassesAndFunctions(unittest.TestCase):
395     def test_classic_mro(self):
396         # Test classic-class method resolution order.
397         class A:    pass
398         class B(A): pass
399         class C(A): pass
400         class D(B, C): pass
401
402         expected = (D, B, A, C)
403         got = inspect.getmro(D)
404         self.assertEqual(expected, got)
405
406     def test_newstyle_mro(self):
407         # The same w/ new-class MRO.
408         class A(object):    pass
409         class B(A): pass
410         class C(A): pass
411         class D(B, C): pass
412
413         expected = (D, B, C, A, object)
414         got = inspect.getmro(D)
415         self.assertEqual(expected, got)
416
417     def assertArgSpecEquals(self, routine, args_e, varargs_e = None,
418                             varkw_e = None, defaults_e = None,
419                             formatted = None):
420         args, varargs, varkw, defaults = inspect.getargspec(routine)
421         self.assertEqual(args, args_e)
422         self.assertEqual(varargs, varargs_e)
423         self.assertEqual(varkw, varkw_e)
424         self.assertEqual(defaults, defaults_e)
425         if formatted is not None:
426             self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults),
427                              formatted)
428
429     def test_getargspec(self):
430         self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted = '(x, y)')
431
432         self.assertArgSpecEquals(mod.spam,
433                                  ['a', 'b', 'c', 'd', ['e', ['f']]],
434                                  'g', 'h', (3, (4, (5,))),
435                                  '(a, b, c, d=3, (e, (f,))=(4, (5,)), *g, **h)')
436
437     def test_getargspec_method(self):
438         class A(object):
439             def m(self):
440                 pass
441         self.assertArgSpecEquals(A.m, ['self'])
442
443     def test_getargspec_sublistofone(self):
444         with check_py3k_warnings(
445                 ("tuple parameter unpacking has been removed", SyntaxWarning),
446                 ("parenthesized argument names are invalid", SyntaxWarning)):
447             exec 'def sublistOfOne((foo,)): return 1'
448             self.assertArgSpecEquals(sublistOfOne, [['foo']])
449
450             exec 'def fakeSublistOfOne((foo)): return 1'
451             self.assertArgSpecEquals(fakeSublistOfOne, ['foo'])
452
453
454     def _classify_test(self, newstyle):
455         """Helper for testing that classify_class_attrs finds a bunch of
456         different kinds of attributes on a given class.
457         """
458         if newstyle:
459             base = object
460         else:
461             class base:
462                 pass
463
464         class A(base):
465             def s(): pass
466             s = staticmethod(s)
467
468             def c(cls): pass
469             c = classmethod(c)
470
471             def getp(self): pass
472             p = property(getp)
473
474             def m(self): pass
475
476             def m1(self): pass
477
478             datablob = '1'
479
480         attrs = attrs_wo_objs(A)
481         self.assertIn(('s', 'static method', A), attrs, 'missing static method')
482         self.assertIn(('c', 'class method', A), attrs, 'missing class method')
483         self.assertIn(('p', 'property', A), attrs, 'missing property')
484         self.assertIn(('m', 'method', A), attrs, 'missing plain method')
485         self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
486         self.assertIn(('datablob', 'data', A), attrs, 'missing data')
487
488         class B(A):
489             def m(self): pass
490
491         attrs = attrs_wo_objs(B)
492         self.assertIn(('s', 'static method', A), attrs, 'missing static method')
493         self.assertIn(('c', 'class method', A), attrs, 'missing class method')
494         self.assertIn(('p', 'property', A), attrs, 'missing property')
495         self.assertIn(('m', 'method', B), attrs, 'missing plain method')
496         self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
497         self.assertIn(('datablob', 'data', A), attrs, 'missing data')
498
499
500         class C(A):
501             def m(self): pass
502             def c(self): pass
503
504         attrs = attrs_wo_objs(C)
505         self.assertIn(('s', 'static method', A), attrs, 'missing static method')
506         self.assertIn(('c', 'method', C), attrs, 'missing plain method')
507         self.assertIn(('p', 'property', A), attrs, 'missing property')
508         self.assertIn(('m', 'method', C), attrs, 'missing plain method')
509         self.assertIn(('m1', 'method', A), attrs, 'missing plain method')
510         self.assertIn(('datablob', 'data', A), attrs, 'missing data')
511
512         class D(B, C):
513             def m1(self): pass
514
515         attrs = attrs_wo_objs(D)
516         self.assertIn(('s', 'static method', A), attrs, 'missing static method')
517         if newstyle:
518             self.assertIn(('c', 'method', C), attrs, 'missing plain method')
519         else:
520             self.assertIn(('c', 'class method', A), attrs, 'missing class method')
521         self.assertIn(('p', 'property', A), attrs, 'missing property')
522         self.assertIn(('m', 'method', B), attrs, 'missing plain method')
523         self.assertIn(('m1', 'method', D), attrs, 'missing plain method')
524         self.assertIn(('datablob', 'data', A), attrs, 'missing data')
525
526
527     def test_classify_oldstyle(self):
528         """classify_class_attrs finds static methods, class methods,
529         properties, normal methods, and data attributes on an old-style
530         class.
531         """
532         self._classify_test(False)
533
534
535     def test_classify_newstyle(self):
536         """Just like test_classify_oldstyle, but for a new-style class.
537         """
538         self._classify_test(True)
539
540
541
542 class TestGetcallargsFunctions(unittest.TestCase):
543
544     # tuple parameters are named '.1', '.2', etc.
545     is_tuplename = re.compile(r'^\.\d+$').match
546
547     def assertEqualCallArgs(self, func, call_params_string, locs=None):
548         locs = dict(locs or {}, func=func)
549         r1 = eval('func(%s)' % call_params_string, None, locs)
550         r2 = eval('inspect.getcallargs(func, %s)' % call_params_string, None,
551                   locs)
552         self.assertEqual(r1, r2)
553
554     def assertEqualException(self, func, call_param_string, locs=None):
555         locs = dict(locs or {}, func=func)
556         try:
557             eval('func(%s)' % call_param_string, None, locs)
558         except Exception, ex1:
559             pass
560         else:
561             self.fail('Exception not raised')
562         try:
563             eval('inspect.getcallargs(func, %s)' % call_param_string, None,
564                  locs)
565         except Exception, ex2:
566             pass
567         else:
568             self.fail('Exception not raised')
569         self.assertIs(type(ex1), type(ex2))
570         self.assertEqual(str(ex1), str(ex2))
571
572     def makeCallable(self, signature):
573         """Create a function that returns its locals(), excluding the
574         autogenerated '.1', '.2', etc. tuple param names (if any)."""
575         with check_py3k_warnings(
576             ("tuple parameter unpacking has been removed", SyntaxWarning),
577             quiet=True):
578             code = ("lambda %s: dict(i for i in locals().items() "
579                     "if not is_tuplename(i[0]))")
580             return eval(code % signature, {'is_tuplename' : self.is_tuplename})
581
582     def test_plain(self):
583         f = self.makeCallable('a, b=1')
584         self.assertEqualCallArgs(f, '2')
585         self.assertEqualCallArgs(f, '2, 3')
586         self.assertEqualCallArgs(f, 'a=2')
587         self.assertEqualCallArgs(f, 'b=3, a=2')
588         self.assertEqualCallArgs(f, '2, b=3')
589         # expand *iterable / **mapping
590         self.assertEqualCallArgs(f, '*(2,)')
591         self.assertEqualCallArgs(f, '*[2]')
592         self.assertEqualCallArgs(f, '*(2, 3)')
593         self.assertEqualCallArgs(f, '*[2, 3]')
594         self.assertEqualCallArgs(f, '**{"a":2}')
595         self.assertEqualCallArgs(f, 'b=3, **{"a":2}')
596         self.assertEqualCallArgs(f, '2, **{"b":3}')
597         self.assertEqualCallArgs(f, '**{"b":3, "a":2}')
598         # expand UserList / UserDict
599         self.assertEqualCallArgs(f, '*UserList([2])')
600         self.assertEqualCallArgs(f, '*UserList([2, 3])')
601         self.assertEqualCallArgs(f, '**UserDict(a=2)')
602         self.assertEqualCallArgs(f, '2, **UserDict(b=3)')
603         self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3)')
604         # unicode keyword args
605         self.assertEqualCallArgs(f, '**{u"a":2}')
606         self.assertEqualCallArgs(f, 'b=3, **{u"a":2}')
607         self.assertEqualCallArgs(f, '2, **{u"b":3}')
608         self.assertEqualCallArgs(f, '**{u"b":3, u"a":2}')
609
610     def test_varargs(self):
611         f = self.makeCallable('a, b=1, *c')
612         self.assertEqualCallArgs(f, '2')
613         self.assertEqualCallArgs(f, '2, 3')
614         self.assertEqualCallArgs(f, '2, 3, 4')
615         self.assertEqualCallArgs(f, '*(2,3,4)')
616         self.assertEqualCallArgs(f, '2, *[3,4]')
617         self.assertEqualCallArgs(f, '2, 3, *UserList([4])')
618
619     def test_varkw(self):
620         f = self.makeCallable('a, b=1, **c')
621         self.assertEqualCallArgs(f, 'a=2')
622         self.assertEqualCallArgs(f, '2, b=3, c=4')
623         self.assertEqualCallArgs(f, 'b=3, a=2, c=4')
624         self.assertEqualCallArgs(f, 'c=4, **{"a":2, "b":3}')
625         self.assertEqualCallArgs(f, '2, c=4, **{"b":3}')
626         self.assertEqualCallArgs(f, 'b=2, **{"a":3, "c":4}')
627         self.assertEqualCallArgs(f, '**UserDict(a=2, b=3, c=4)')
628         self.assertEqualCallArgs(f, '2, c=4, **UserDict(b=3)')
629         self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3, c=4)')
630         # unicode keyword args
631         self.assertEqualCallArgs(f, 'c=4, **{u"a":2, u"b":3}')
632         self.assertEqualCallArgs(f, '2, c=4, **{u"b":3}')
633         self.assertEqualCallArgs(f, 'b=2, **{u"a":3, u"c":4}')
634
635     def test_tupleargs(self):
636         f = self.makeCallable('(b,c), (d,(e,f))=(0,[1,2])')
637         self.assertEqualCallArgs(f, '(2,3)')
638         self.assertEqualCallArgs(f, '[2,3]')
639         self.assertEqualCallArgs(f, 'UserList([2,3])')
640         self.assertEqualCallArgs(f, '(2,3), (4,(5,6))')
641         self.assertEqualCallArgs(f, '(2,3), (4,[5,6])')
642         self.assertEqualCallArgs(f, '(2,3), [4,UserList([5,6])]')
643
644     def test_multiple_features(self):
645         f = self.makeCallable('a, b=2, (c,(d,e))=(3,[4,5]), *f, **g')
646         self.assertEqualCallArgs(f, '2, 3, (4,[5,6]), 7')
647         self.assertEqualCallArgs(f, '2, 3, *[(4,[5,6]), 7], x=8')
648         self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]')
649         self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9')
650         self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9')
651         self.assertEqualCallArgs(f, 'x=8, *UserList([2, 3, (4,[5,6])]), '
652                                  '**{"y":9, "z":10}')
653         self.assertEqualCallArgs(f, '2, x=8, *UserList([3, (4,[5,6])]), '
654                                  '**UserDict(y=9, z=10)')
655
656     def test_errors(self):
657         f0 = self.makeCallable('')
658         f1 = self.makeCallable('a, b')
659         f2 = self.makeCallable('a, b=1')
660         # f0 takes no arguments
661         self.assertEqualException(f0, '1')
662         self.assertEqualException(f0, 'x=1')
663         self.assertEqualException(f0, '1,x=1')
664         # f1 takes exactly 2 arguments
665         self.assertEqualException(f1, '')
666         self.assertEqualException(f1, '1')
667         self.assertEqualException(f1, 'a=2')
668         self.assertEqualException(f1, 'b=3')
669         # f2 takes at least 1 argument
670         self.assertEqualException(f2, '')
671         self.assertEqualException(f2, 'b=3')
672         for f in f1, f2:
673             # f1/f2 takes exactly/at most 2 arguments
674             self.assertEqualException(f, '2, 3, 4')
675             self.assertEqualException(f, '1, 2, 3, a=1')
676             self.assertEqualException(f, '2, 3, 4, c=5')
677             self.assertEqualException(f, '2, 3, 4, a=1, c=5')
678             # f got an unexpected keyword argument
679             self.assertEqualException(f, 'c=2')
680             self.assertEqualException(f, '2, c=3')
681             self.assertEqualException(f, '2, 3, c=4')
682             self.assertEqualException(f, '2, c=4, b=3')
683             self.assertEqualException(f, '**{u"\u03c0\u03b9": 4}')
684             # f got multiple values for keyword argument
685             self.assertEqualException(f, '1, a=2')
686             self.assertEqualException(f, '1, **{"a":2}')
687             self.assertEqualException(f, '1, 2, b=3')
688             # XXX: Python inconsistency
689             # - for functions and bound methods: unexpected keyword 'c'
690             # - for unbound methods: multiple values for keyword 'a'
691             #self.assertEqualException(f, '1, c=3, a=2')
692         f = self.makeCallable('(a,b)=(0,1)')
693         self.assertEqualException(f, '1')
694         self.assertEqualException(f, '[1]')
695         self.assertEqualException(f, '(1,2,3)')
696
697 class TestGetcallargsMethods(TestGetcallargsFunctions):
698
699     def setUp(self):
700         class Foo(object):
701             pass
702         self.cls = Foo
703         self.inst = Foo()
704
705     def makeCallable(self, signature):
706         assert 'self' not in signature
707         mk = super(TestGetcallargsMethods, self).makeCallable
708         self.cls.method = mk('self, ' + signature)
709         return self.inst.method
710
711 class TestGetcallargsUnboundMethods(TestGetcallargsMethods):
712
713     def makeCallable(self, signature):
714         super(TestGetcallargsUnboundMethods, self).makeCallable(signature)
715         return self.cls.method
716
717     def assertEqualCallArgs(self, func, call_params_string, locs=None):
718         return super(TestGetcallargsUnboundMethods, self).assertEqualCallArgs(
719             *self._getAssertEqualParams(func, call_params_string, locs))
720
721     def assertEqualException(self, func, call_params_string, locs=None):
722         return super(TestGetcallargsUnboundMethods, self).assertEqualException(
723             *self._getAssertEqualParams(func, call_params_string, locs))
724
725     def _getAssertEqualParams(self, func, call_params_string, locs=None):
726         assert 'inst' not in call_params_string
727         locs = dict(locs or {}, inst=self.inst)
728         return (func, 'inst,' + call_params_string, locs)
729
730 def test_main():
731     run_unittest(
732         TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases,
733         TestInterpreterStack, TestClassesAndFunctions, TestPredicates,
734         TestGetcallargsFunctions, TestGetcallargsMethods,
735         TestGetcallargsUnboundMethods)
736
737 if __name__ == "__main__":
738     test_main()