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 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 298class 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 307class 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 349class 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. 391def attrs_wo_objs(cls): 392 return [t[:3] for t in inspect.classify_class_attrs(cls)] 393 394class 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 542class 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_varkw_only(self): 636 # issue11256: 637 f = self.makeCallable('**c') 638 self.assertEqualCallArgs(f, '') 639 self.assertEqualCallArgs(f, 'a=1') 640 self.assertEqualCallArgs(f, 'a=1, b=2') 641 self.assertEqualCallArgs(f, 'c=3, **{"a": 1, "b": 2}') 642 self.assertEqualCallArgs(f, '**UserDict(a=1, b=2)') 643 self.assertEqualCallArgs(f, 'c=3, **UserDict(a=1, b=2)') 644 645 def test_tupleargs(self): 646 f = self.makeCallable('(b,c), (d,(e,f))=(0,[1,2])') 647 self.assertEqualCallArgs(f, '(2,3)') 648 self.assertEqualCallArgs(f, '[2,3]') 649 self.assertEqualCallArgs(f, 'UserList([2,3])') 650 self.assertEqualCallArgs(f, '(2,3), (4,(5,6))') 651 self.assertEqualCallArgs(f, '(2,3), (4,[5,6])') 652 self.assertEqualCallArgs(f, '(2,3), [4,UserList([5,6])]') 653 654 def test_multiple_features(self): 655 f = self.makeCallable('a, b=2, (c,(d,e))=(3,[4,5]), *f, **g') 656 self.assertEqualCallArgs(f, '2, 3, (4,[5,6]), 7') 657 self.assertEqualCallArgs(f, '2, 3, *[(4,[5,6]), 7], x=8') 658 self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]') 659 self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9') 660 self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9') 661 self.assertEqualCallArgs(f, 'x=8, *UserList([2, 3, (4,[5,6])]), ' 662 '**{"y":9, "z":10}') 663 self.assertEqualCallArgs(f, '2, x=8, *UserList([3, (4,[5,6])]), ' 664 '**UserDict(y=9, z=10)') 665 666 def test_errors(self): 667 f0 = self.makeCallable('') 668 f1 = self.makeCallable('a, b') 669 f2 = self.makeCallable('a, b=1') 670 # f0 takes no arguments 671 self.assertEqualException(f0, '1') 672 self.assertEqualException(f0, 'x=1') 673 self.assertEqualException(f0, '1,x=1') 674 # f1 takes exactly 2 arguments 675 self.assertEqualException(f1, '') 676 self.assertEqualException(f1, '1') 677 self.assertEqualException(f1, 'a=2') 678 self.assertEqualException(f1, 'b=3') 679 # f2 takes at least 1 argument 680 self.assertEqualException(f2, '') 681 self.assertEqualException(f2, 'b=3') 682 for f in f1, f2: 683 # f1/f2 takes exactly/at most 2 arguments 684 self.assertEqualException(f, '2, 3, 4') 685 self.assertEqualException(f, '1, 2, 3, a=1') 686 self.assertEqualException(f, '2, 3, 4, c=5') 687 self.assertEqualException(f, '2, 3, 4, a=1, c=5') 688 # f got an unexpected keyword argument 689 self.assertEqualException(f, 'c=2') 690 self.assertEqualException(f, '2, c=3') 691 self.assertEqualException(f, '2, 3, c=4') 692 self.assertEqualException(f, '2, c=4, b=3') 693 self.assertEqualException(f, '**{u"\u03c0\u03b9": 4}') 694 # f got multiple values for keyword argument 695 self.assertEqualException(f, '1, a=2') 696 self.assertEqualException(f, '1, **{"a":2}') 697 self.assertEqualException(f, '1, 2, b=3') 698 # XXX: Python inconsistency 699 # - for functions and bound methods: unexpected keyword 'c' 700 # - for unbound methods: multiple values for keyword 'a' 701 #self.assertEqualException(f, '1, c=3, a=2') 702 f = self.makeCallable('(a,b)=(0,1)') 703 self.assertEqualException(f, '1') 704 self.assertEqualException(f, '[1]') 705 self.assertEqualException(f, '(1,2,3)') 706 # issue11256: 707 f3 = self.makeCallable('**c') 708 self.assertEqualException(f3, '1, 2') 709 self.assertEqualException(f3, '1, 2, a=1, b=2') 710 711class TestGetcallargsMethods(TestGetcallargsFunctions): 712 713 def setUp(self): 714 class Foo(object): 715 pass 716 self.cls = Foo 717 self.inst = Foo() 718 719 def makeCallable(self, signature): 720 assert 'self' not in signature 721 mk = super(TestGetcallargsMethods, self).makeCallable 722 self.cls.method = mk('self, ' + signature) 723 return self.inst.method 724 725class TestGetcallargsUnboundMethods(TestGetcallargsMethods): 726 727 def makeCallable(self, signature): 728 super(TestGetcallargsUnboundMethods, self).makeCallable(signature) 729 return self.cls.method 730 731 def assertEqualCallArgs(self, func, call_params_string, locs=None): 732 return super(TestGetcallargsUnboundMethods, self).assertEqualCallArgs( 733 *self._getAssertEqualParams(func, call_params_string, locs)) 734 735 def assertEqualException(self, func, call_params_string, locs=None): 736 return super(TestGetcallargsUnboundMethods, self).assertEqualException( 737 *self._getAssertEqualParams(func, call_params_string, locs)) 738 739 def _getAssertEqualParams(self, func, call_params_string, locs=None): 740 assert 'inst' not in call_params_string 741 locs = dict(locs or {}, inst=self.inst) 742 return (func, 'inst,' + call_params_string, locs) 743 744def test_main(): 745 run_unittest( 746 TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases, 747 TestInterpreterStack, TestClassesAndFunctions, TestPredicates, 748 TestGetcallargsFunctions, TestGetcallargsMethods, 749 TestGetcallargsUnboundMethods) 750 751if __name__ == "__main__": 752 test_main() 753