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