1import builtins 2import collections 3import datetime 4import functools 5import importlib 6import inspect 7import io 8import linecache 9import os 10from os.path import normcase 11import _pickle 12import pickle 13import shutil 14import sys 15import types 16import textwrap 17import unicodedata 18import unittest 19import unittest.mock 20import warnings 21 22try: 23 from concurrent.futures import ThreadPoolExecutor 24except ImportError: 25 ThreadPoolExecutor = None 26 27from test.support import run_unittest, TESTFN, DirsOnSysPath, cpython_only 28from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ 29from test.support.script_helper import assert_python_ok, assert_python_failure 30from test import inspect_fodder as mod 31from test import inspect_fodder2 as mod2 32from test import support 33 34from test.test_import import _ready_to_import 35 36 37# Functions tested in this suite: 38# ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode, 39# isbuiltin, isroutine, isgenerator, isgeneratorfunction, getmembers, 40# getdoc, getfile, getmodule, getsourcefile, getcomments, getsource, 41# getclasstree, getargvalues, formatargspec, formatargvalues, 42# currentframe, stack, trace, isdatadescriptor 43 44# NOTE: There are some additional tests relating to interaction with 45# zipimport in the test_zipimport_support test module. 46 47modfile = mod.__file__ 48if modfile.endswith(('c', 'o')): 49 modfile = modfile[:-1] 50 51# Normalize file names: on Windows, the case of file names of compiled 52# modules depends on the path used to start the python executable. 53modfile = normcase(modfile) 54 55def revise(filename, *args): 56 return (normcase(filename),) + args 57 58git = mod.StupidGit() 59 60 61def signatures_with_lexicographic_keyword_only_parameters(): 62 """ 63 Yields a whole bunch of functions with only keyword-only parameters, 64 where those parameters are always in lexicographically sorted order. 65 """ 66 parameters = ['a', 'bar', 'c', 'delta', 'ephraim', 'magical', 'yoyo', 'z'] 67 for i in range(1, 2**len(parameters)): 68 p = [] 69 bit = 1 70 for j in range(len(parameters)): 71 if i & (bit << j): 72 p.append(parameters[j]) 73 fn_text = "def foo(*, " + ", ".join(p) + "): pass" 74 symbols = {} 75 exec(fn_text, symbols, symbols) 76 yield symbols['foo'] 77 78 79def unsorted_keyword_only_parameters_fn(*, throw, out, the, baby, with_, 80 the_, bathwater): 81 pass 82 83unsorted_keyword_only_parameters = 'throw out the baby with_ the_ bathwater'.split() 84 85class IsTestBase(unittest.TestCase): 86 predicates = set([inspect.isbuiltin, inspect.isclass, inspect.iscode, 87 inspect.isframe, inspect.isfunction, inspect.ismethod, 88 inspect.ismodule, inspect.istraceback, 89 inspect.isgenerator, inspect.isgeneratorfunction, 90 inspect.iscoroutine, inspect.iscoroutinefunction, 91 inspect.isasyncgen, inspect.isasyncgenfunction]) 92 93 def istest(self, predicate, exp): 94 obj = eval(exp) 95 self.assertTrue(predicate(obj), '%s(%s)' % (predicate.__name__, exp)) 96 97 for other in self.predicates - set([predicate]): 98 if (predicate == inspect.isgeneratorfunction or \ 99 predicate == inspect.isasyncgenfunction or \ 100 predicate == inspect.iscoroutinefunction) and \ 101 other == inspect.isfunction: 102 continue 103 self.assertFalse(other(obj), 'not %s(%s)' % (other.__name__, exp)) 104 105def generator_function_example(self): 106 for i in range(2): 107 yield i 108 109async def async_generator_function_example(self): 110 async for i in range(2): 111 yield i 112 113async def coroutine_function_example(self): 114 return 'spam' 115 116@types.coroutine 117def gen_coroutine_function_example(self): 118 yield 119 return 'spam' 120 121class TestPredicates(IsTestBase): 122 123 def test_excluding_predicates(self): 124 global tb 125 self.istest(inspect.isbuiltin, 'sys.exit') 126 self.istest(inspect.isbuiltin, '[].append') 127 self.istest(inspect.iscode, 'mod.spam.__code__') 128 try: 129 1/0 130 except: 131 tb = sys.exc_info()[2] 132 self.istest(inspect.isframe, 'tb.tb_frame') 133 self.istest(inspect.istraceback, 'tb') 134 if hasattr(types, 'GetSetDescriptorType'): 135 self.istest(inspect.isgetsetdescriptor, 136 'type(tb.tb_frame).f_locals') 137 else: 138 self.assertFalse(inspect.isgetsetdescriptor(type(tb.tb_frame).f_locals)) 139 finally: 140 # Clear traceback and all the frames and local variables hanging to it. 141 tb = None 142 self.istest(inspect.isfunction, 'mod.spam') 143 self.istest(inspect.isfunction, 'mod.StupidGit.abuse') 144 self.istest(inspect.ismethod, 'git.argue') 145 self.istest(inspect.ismethod, 'mod.custom_method') 146 self.istest(inspect.ismodule, 'mod') 147 self.istest(inspect.isdatadescriptor, 'collections.defaultdict.default_factory') 148 self.istest(inspect.isgenerator, '(x for x in range(2))') 149 self.istest(inspect.isgeneratorfunction, 'generator_function_example') 150 self.istest(inspect.isasyncgen, 151 'async_generator_function_example(1)') 152 self.istest(inspect.isasyncgenfunction, 153 'async_generator_function_example') 154 155 with warnings.catch_warnings(): 156 warnings.simplefilter("ignore") 157 self.istest(inspect.iscoroutine, 'coroutine_function_example(1)') 158 self.istest(inspect.iscoroutinefunction, 'coroutine_function_example') 159 160 if hasattr(types, 'MemberDescriptorType'): 161 self.istest(inspect.ismemberdescriptor, 'datetime.timedelta.days') 162 else: 163 self.assertFalse(inspect.ismemberdescriptor(datetime.timedelta.days)) 164 165 def test_iscoroutine(self): 166 async_gen_coro = async_generator_function_example(1) 167 gen_coro = gen_coroutine_function_example(1) 168 coro = coroutine_function_example(1) 169 170 self.assertFalse( 171 inspect.iscoroutinefunction(gen_coroutine_function_example)) 172 self.assertFalse( 173 inspect.iscoroutinefunction( 174 functools.partial(functools.partial( 175 gen_coroutine_function_example)))) 176 self.assertFalse(inspect.iscoroutine(gen_coro)) 177 178 self.assertTrue( 179 inspect.isgeneratorfunction(gen_coroutine_function_example)) 180 self.assertTrue( 181 inspect.isgeneratorfunction( 182 functools.partial(functools.partial( 183 gen_coroutine_function_example)))) 184 self.assertTrue(inspect.isgenerator(gen_coro)) 185 186 self.assertTrue( 187 inspect.iscoroutinefunction(coroutine_function_example)) 188 self.assertTrue( 189 inspect.iscoroutinefunction( 190 functools.partial(functools.partial( 191 coroutine_function_example)))) 192 self.assertTrue(inspect.iscoroutine(coro)) 193 194 self.assertFalse( 195 inspect.isgeneratorfunction(coroutine_function_example)) 196 self.assertFalse( 197 inspect.isgeneratorfunction( 198 functools.partial(functools.partial( 199 coroutine_function_example)))) 200 self.assertFalse(inspect.isgenerator(coro)) 201 202 self.assertTrue( 203 inspect.isasyncgenfunction(async_generator_function_example)) 204 self.assertTrue( 205 inspect.isasyncgenfunction( 206 functools.partial(functools.partial( 207 async_generator_function_example)))) 208 self.assertTrue(inspect.isasyncgen(async_gen_coro)) 209 210 coro.close(); gen_coro.close(); # silence warnings 211 212 def test_isawaitable(self): 213 def gen(): yield 214 self.assertFalse(inspect.isawaitable(gen())) 215 216 coro = coroutine_function_example(1) 217 gen_coro = gen_coroutine_function_example(1) 218 219 self.assertTrue(inspect.isawaitable(coro)) 220 self.assertTrue(inspect.isawaitable(gen_coro)) 221 222 class Future: 223 def __await__(): 224 pass 225 self.assertTrue(inspect.isawaitable(Future())) 226 self.assertFalse(inspect.isawaitable(Future)) 227 228 class NotFuture: pass 229 not_fut = NotFuture() 230 not_fut.__await__ = lambda: None 231 self.assertFalse(inspect.isawaitable(not_fut)) 232 233 coro.close(); gen_coro.close() # silence warnings 234 235 def test_isroutine(self): 236 self.assertTrue(inspect.isroutine(mod.spam)) 237 self.assertTrue(inspect.isroutine([].count)) 238 239 def test_isclass(self): 240 self.istest(inspect.isclass, 'mod.StupidGit') 241 self.assertTrue(inspect.isclass(list)) 242 243 class CustomGetattr(object): 244 def __getattr__(self, attr): 245 return None 246 self.assertFalse(inspect.isclass(CustomGetattr())) 247 248 def test_get_slot_members(self): 249 class C(object): 250 __slots__ = ("a", "b") 251 x = C() 252 x.a = 42 253 members = dict(inspect.getmembers(x)) 254 self.assertIn('a', members) 255 self.assertNotIn('b', members) 256 257 def test_isabstract(self): 258 from abc import ABCMeta, abstractmethod 259 260 class AbstractClassExample(metaclass=ABCMeta): 261 262 @abstractmethod 263 def foo(self): 264 pass 265 266 class ClassExample(AbstractClassExample): 267 def foo(self): 268 pass 269 270 a = ClassExample() 271 272 # Test general behaviour. 273 self.assertTrue(inspect.isabstract(AbstractClassExample)) 274 self.assertFalse(inspect.isabstract(ClassExample)) 275 self.assertFalse(inspect.isabstract(a)) 276 self.assertFalse(inspect.isabstract(int)) 277 self.assertFalse(inspect.isabstract(5)) 278 279 def test_isabstract_during_init_subclass(self): 280 from abc import ABCMeta, abstractmethod 281 isabstract_checks = [] 282 class AbstractChecker(metaclass=ABCMeta): 283 def __init_subclass__(cls): 284 isabstract_checks.append(inspect.isabstract(cls)) 285 class AbstractClassExample(AbstractChecker): 286 @abstractmethod 287 def foo(self): 288 pass 289 class ClassExample(AbstractClassExample): 290 def foo(self): 291 pass 292 self.assertEqual(isabstract_checks, [True, False]) 293 294 isabstract_checks.clear() 295 class AbstractChild(AbstractClassExample): 296 pass 297 class AbstractGrandchild(AbstractChild): 298 pass 299 class ConcreteGrandchild(ClassExample): 300 pass 301 self.assertEqual(isabstract_checks, [True, True, False]) 302 303 304class TestInterpreterStack(IsTestBase): 305 def __init__(self, *args, **kwargs): 306 unittest.TestCase.__init__(self, *args, **kwargs) 307 308 git.abuse(7, 8, 9) 309 310 def test_abuse_done(self): 311 self.istest(inspect.istraceback, 'git.ex[2]') 312 self.istest(inspect.isframe, 'mod.fr') 313 314 def test_stack(self): 315 self.assertTrue(len(mod.st) >= 5) 316 self.assertEqual(revise(*mod.st[0][1:]), 317 (modfile, 16, 'eggs', [' st = inspect.stack()\n'], 0)) 318 self.assertEqual(revise(*mod.st[1][1:]), 319 (modfile, 9, 'spam', [' eggs(b + d, c + f)\n'], 0)) 320 self.assertEqual(revise(*mod.st[2][1:]), 321 (modfile, 43, 'argue', [' spam(a, b, c)\n'], 0)) 322 self.assertEqual(revise(*mod.st[3][1:]), 323 (modfile, 39, 'abuse', [' self.argue(a, b, c)\n'], 0)) 324 # Test named tuple fields 325 record = mod.st[0] 326 self.assertIs(record.frame, mod.fr) 327 self.assertEqual(record.lineno, 16) 328 self.assertEqual(record.filename, mod.__file__) 329 self.assertEqual(record.function, 'eggs') 330 self.assertIn('inspect.stack()', record.code_context[0]) 331 self.assertEqual(record.index, 0) 332 333 def test_trace(self): 334 self.assertEqual(len(git.tr), 3) 335 self.assertEqual(revise(*git.tr[0][1:]), 336 (modfile, 43, 'argue', [' spam(a, b, c)\n'], 0)) 337 self.assertEqual(revise(*git.tr[1][1:]), 338 (modfile, 9, 'spam', [' eggs(b + d, c + f)\n'], 0)) 339 self.assertEqual(revise(*git.tr[2][1:]), 340 (modfile, 18, 'eggs', [' q = y / 0\n'], 0)) 341 342 def test_frame(self): 343 args, varargs, varkw, locals = inspect.getargvalues(mod.fr) 344 self.assertEqual(args, ['x', 'y']) 345 self.assertEqual(varargs, None) 346 self.assertEqual(varkw, None) 347 self.assertEqual(locals, {'x': 11, 'p': 11, 'y': 14}) 348 self.assertEqual(inspect.formatargvalues(args, varargs, varkw, locals), 349 '(x=11, y=14)') 350 351 def test_previous_frame(self): 352 args, varargs, varkw, locals = inspect.getargvalues(mod.fr.f_back) 353 self.assertEqual(args, ['a', 'b', 'c', 'd', 'e', 'f']) 354 self.assertEqual(varargs, 'g') 355 self.assertEqual(varkw, 'h') 356 self.assertEqual(inspect.formatargvalues(args, varargs, varkw, locals), 357 '(a=7, b=8, c=9, d=3, e=4, f=5, *g=(), **h={})') 358 359class GetSourceBase(unittest.TestCase): 360 # Subclasses must override. 361 fodderModule = None 362 363 def setUp(self): 364 with open(inspect.getsourcefile(self.fodderModule)) as fp: 365 self.source = fp.read() 366 367 def sourcerange(self, top, bottom): 368 lines = self.source.split("\n") 369 return "\n".join(lines[top-1:bottom]) + ("\n" if bottom else "") 370 371 def assertSourceEqual(self, obj, top, bottom): 372 self.assertEqual(inspect.getsource(obj), 373 self.sourcerange(top, bottom)) 374 375class SlotUser: 376 'Docstrings for __slots__' 377 __slots__ = {'power': 'measured in kilowatts', 378 'distance': 'measured in kilometers'} 379 380class TestRetrievingSourceCode(GetSourceBase): 381 fodderModule = mod 382 383 def test_getclasses(self): 384 classes = inspect.getmembers(mod, inspect.isclass) 385 self.assertEqual(classes, 386 [('FesteringGob', mod.FesteringGob), 387 ('MalodorousPervert', mod.MalodorousPervert), 388 ('ParrotDroppings', mod.ParrotDroppings), 389 ('StupidGit', mod.StupidGit), 390 ('Tit', mod.MalodorousPervert), 391 ('WhichComments', mod.WhichComments), 392 ]) 393 tree = inspect.getclasstree([cls[1] for cls in classes]) 394 self.assertEqual(tree, 395 [(object, ()), 396 [(mod.ParrotDroppings, (object,)), 397 [(mod.FesteringGob, (mod.MalodorousPervert, 398 mod.ParrotDroppings)) 399 ], 400 (mod.StupidGit, (object,)), 401 [(mod.MalodorousPervert, (mod.StupidGit,)), 402 [(mod.FesteringGob, (mod.MalodorousPervert, 403 mod.ParrotDroppings)) 404 ] 405 ], 406 (mod.WhichComments, (object,),) 407 ] 408 ]) 409 tree = inspect.getclasstree([cls[1] for cls in classes], True) 410 self.assertEqual(tree, 411 [(object, ()), 412 [(mod.ParrotDroppings, (object,)), 413 (mod.StupidGit, (object,)), 414 [(mod.MalodorousPervert, (mod.StupidGit,)), 415 [(mod.FesteringGob, (mod.MalodorousPervert, 416 mod.ParrotDroppings)) 417 ] 418 ], 419 (mod.WhichComments, (object,),) 420 ] 421 ]) 422 423 def test_getfunctions(self): 424 functions = inspect.getmembers(mod, inspect.isfunction) 425 self.assertEqual(functions, [('eggs', mod.eggs), 426 ('lobbest', mod.lobbest), 427 ('spam', mod.spam)]) 428 429 @unittest.skipIf(sys.flags.optimize >= 2, 430 "Docstrings are omitted with -O2 and above") 431 def test_getdoc(self): 432 self.assertEqual(inspect.getdoc(mod), 'A module docstring.') 433 self.assertEqual(inspect.getdoc(mod.StupidGit), 434 'A longer,\n\nindented\n\ndocstring.') 435 self.assertEqual(inspect.getdoc(git.abuse), 436 'Another\n\ndocstring\n\ncontaining\n\ntabs') 437 self.assertEqual(inspect.getdoc(SlotUser.power), 438 'measured in kilowatts') 439 self.assertEqual(inspect.getdoc(SlotUser.distance), 440 'measured in kilometers') 441 442 @unittest.skipIf(sys.flags.optimize >= 2, 443 "Docstrings are omitted with -O2 and above") 444 def test_getdoc_inherited(self): 445 self.assertEqual(inspect.getdoc(mod.FesteringGob), 446 'A longer,\n\nindented\n\ndocstring.') 447 self.assertEqual(inspect.getdoc(mod.FesteringGob.abuse), 448 'Another\n\ndocstring\n\ncontaining\n\ntabs') 449 self.assertEqual(inspect.getdoc(mod.FesteringGob().abuse), 450 'Another\n\ndocstring\n\ncontaining\n\ntabs') 451 self.assertEqual(inspect.getdoc(mod.FesteringGob.contradiction), 452 'The automatic gainsaying.') 453 454 @unittest.skipIf(MISSING_C_DOCSTRINGS, "test requires docstrings") 455 def test_finddoc(self): 456 finddoc = inspect._finddoc 457 self.assertEqual(finddoc(int), int.__doc__) 458 self.assertEqual(finddoc(int.to_bytes), int.to_bytes.__doc__) 459 self.assertEqual(finddoc(int().to_bytes), int.to_bytes.__doc__) 460 self.assertEqual(finddoc(int.from_bytes), int.from_bytes.__doc__) 461 self.assertEqual(finddoc(int.real), int.real.__doc__) 462 463 def test_cleandoc(self): 464 self.assertEqual(inspect.cleandoc('An\n indented\n docstring.'), 465 'An\nindented\ndocstring.') 466 467 def test_getcomments(self): 468 self.assertEqual(inspect.getcomments(mod), '# line 1\n') 469 self.assertEqual(inspect.getcomments(mod.StupidGit), '# line 20\n') 470 self.assertEqual(inspect.getcomments(mod2.cls160), '# line 159\n') 471 # If the object source file is not available, return None. 472 co = compile('x=1', '_non_existing_filename.py', 'exec') 473 self.assertIsNone(inspect.getcomments(co)) 474 # If the object has been defined in C, return None. 475 self.assertIsNone(inspect.getcomments(list)) 476 477 def test_getmodule(self): 478 # Check actual module 479 self.assertEqual(inspect.getmodule(mod), mod) 480 # Check class (uses __module__ attribute) 481 self.assertEqual(inspect.getmodule(mod.StupidGit), mod) 482 # Check a method (no __module__ attribute, falls back to filename) 483 self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod) 484 # Do it again (check the caching isn't broken) 485 self.assertEqual(inspect.getmodule(mod.StupidGit.abuse), mod) 486 # Check a builtin 487 self.assertEqual(inspect.getmodule(str), sys.modules["builtins"]) 488 # Check filename override 489 self.assertEqual(inspect.getmodule(None, modfile), mod) 490 491 def test_getframeinfo_get_first_line(self): 492 frame_info = inspect.getframeinfo(self.fodderModule.fr, 50) 493 self.assertEqual(frame_info.code_context[0], "# line 1\n") 494 self.assertEqual(frame_info.code_context[1], "'A module docstring.'\n") 495 496 def test_getsource(self): 497 self.assertSourceEqual(git.abuse, 29, 39) 498 self.assertSourceEqual(mod.StupidGit, 21, 51) 499 self.assertSourceEqual(mod.lobbest, 75, 76) 500 501 def test_getsourcefile(self): 502 self.assertEqual(normcase(inspect.getsourcefile(mod.spam)), modfile) 503 self.assertEqual(normcase(inspect.getsourcefile(git.abuse)), modfile) 504 fn = "_non_existing_filename_used_for_sourcefile_test.py" 505 co = compile("x=1", fn, "exec") 506 self.assertEqual(inspect.getsourcefile(co), None) 507 linecache.cache[co.co_filename] = (1, None, "None", co.co_filename) 508 try: 509 self.assertEqual(normcase(inspect.getsourcefile(co)), fn) 510 finally: 511 del linecache.cache[co.co_filename] 512 513 def test_getfile(self): 514 self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__) 515 516 def test_getfile_builtin_module(self): 517 with self.assertRaises(TypeError) as e: 518 inspect.getfile(sys) 519 self.assertTrue(str(e.exception).startswith('<module')) 520 521 def test_getfile_builtin_class(self): 522 with self.assertRaises(TypeError) as e: 523 inspect.getfile(int) 524 self.assertTrue(str(e.exception).startswith('<class')) 525 526 def test_getfile_builtin_function_or_method(self): 527 with self.assertRaises(TypeError) as e_abs: 528 inspect.getfile(abs) 529 self.assertIn('expected, got', str(e_abs.exception)) 530 with self.assertRaises(TypeError) as e_append: 531 inspect.getfile(list.append) 532 self.assertIn('expected, got', str(e_append.exception)) 533 534 def test_getfile_class_without_module(self): 535 class CM(type): 536 @property 537 def __module__(cls): 538 raise AttributeError 539 class C(metaclass=CM): 540 pass 541 with self.assertRaises(TypeError): 542 inspect.getfile(C) 543 544 def test_getfile_broken_repr(self): 545 class ErrorRepr: 546 def __repr__(self): 547 raise Exception('xyz') 548 er = ErrorRepr() 549 with self.assertRaises(TypeError): 550 inspect.getfile(er) 551 552 def test_getmodule_recursion(self): 553 from types import ModuleType 554 name = '__inspect_dummy' 555 m = sys.modules[name] = ModuleType(name) 556 m.__file__ = "<string>" # hopefully not a real filename... 557 m.__loader__ = "dummy" # pretend the filename is understood by a loader 558 exec("def x(): pass", m.__dict__) 559 self.assertEqual(inspect.getsourcefile(m.x.__code__), '<string>') 560 del sys.modules[name] 561 inspect.getmodule(compile('a=10','','single')) 562 563 def test_proceed_with_fake_filename(self): 564 '''doctest monkeypatches linecache to enable inspection''' 565 fn, source = '<test>', 'def x(): pass\n' 566 getlines = linecache.getlines 567 def monkey(filename, module_globals=None): 568 if filename == fn: 569 return source.splitlines(keepends=True) 570 else: 571 return getlines(filename, module_globals) 572 linecache.getlines = monkey 573 try: 574 ns = {} 575 exec(compile(source, fn, 'single'), ns) 576 inspect.getsource(ns["x"]) 577 finally: 578 linecache.getlines = getlines 579 580 def test_getsource_on_code_object(self): 581 self.assertSourceEqual(mod.eggs.__code__, 12, 18) 582 583class TestGettingSourceOfToplevelFrames(GetSourceBase): 584 fodderModule = mod 585 586 def test_range_toplevel_frame(self): 587 self.maxDiff = None 588 self.assertSourceEqual(mod.currentframe, 1, None) 589 590 def test_range_traceback_toplevel_frame(self): 591 self.assertSourceEqual(mod.tb, 1, None) 592 593class TestDecorators(GetSourceBase): 594 fodderModule = mod2 595 596 def test_wrapped_decorator(self): 597 self.assertSourceEqual(mod2.wrapped, 14, 17) 598 599 def test_replacing_decorator(self): 600 self.assertSourceEqual(mod2.gone, 9, 10) 601 602 def test_getsource_unwrap(self): 603 self.assertSourceEqual(mod2.real, 130, 132) 604 605 def test_decorator_with_lambda(self): 606 self.assertSourceEqual(mod2.func114, 113, 115) 607 608class TestOneliners(GetSourceBase): 609 fodderModule = mod2 610 def test_oneline_lambda(self): 611 # Test inspect.getsource with a one-line lambda function. 612 self.assertSourceEqual(mod2.oll, 25, 25) 613 614 def test_threeline_lambda(self): 615 # Test inspect.getsource with a three-line lambda function, 616 # where the second and third lines are _not_ indented. 617 self.assertSourceEqual(mod2.tll, 28, 30) 618 619 def test_twoline_indented_lambda(self): 620 # Test inspect.getsource with a two-line lambda function, 621 # where the second line _is_ indented. 622 self.assertSourceEqual(mod2.tlli, 33, 34) 623 624 def test_onelinefunc(self): 625 # Test inspect.getsource with a regular one-line function. 626 self.assertSourceEqual(mod2.onelinefunc, 37, 37) 627 628 def test_manyargs(self): 629 # Test inspect.getsource with a regular function where 630 # the arguments are on two lines and _not_ indented and 631 # the body on the second line with the last arguments. 632 self.assertSourceEqual(mod2.manyargs, 40, 41) 633 634 def test_twolinefunc(self): 635 # Test inspect.getsource with a regular function where 636 # the body is on two lines, following the argument list and 637 # continued on the next line by a \\. 638 self.assertSourceEqual(mod2.twolinefunc, 44, 45) 639 640 def test_lambda_in_list(self): 641 # Test inspect.getsource with a one-line lambda function 642 # defined in a list, indented. 643 self.assertSourceEqual(mod2.a[1], 49, 49) 644 645 def test_anonymous(self): 646 # Test inspect.getsource with a lambda function defined 647 # as argument to another function. 648 self.assertSourceEqual(mod2.anonymous, 55, 55) 649 650class TestBlockComments(GetSourceBase): 651 fodderModule = mod 652 653 def test_toplevel_class(self): 654 self.assertSourceEqual(mod.WhichComments, 96, 114) 655 656 def test_class_method(self): 657 self.assertSourceEqual(mod.WhichComments.f, 99, 104) 658 659 def test_class_async_method(self): 660 self.assertSourceEqual(mod.WhichComments.asyncf, 109, 112) 661 662class TestBuggyCases(GetSourceBase): 663 fodderModule = mod2 664 665 def test_with_comment(self): 666 self.assertSourceEqual(mod2.with_comment, 58, 59) 667 668 def test_multiline_sig(self): 669 self.assertSourceEqual(mod2.multiline_sig[0], 63, 64) 670 671 def test_nested_class(self): 672 self.assertSourceEqual(mod2.func69().func71, 71, 72) 673 674 def test_one_liner_followed_by_non_name(self): 675 self.assertSourceEqual(mod2.func77, 77, 77) 676 677 def test_one_liner_dedent_non_name(self): 678 self.assertSourceEqual(mod2.cls82.func83, 83, 83) 679 680 def test_with_comment_instead_of_docstring(self): 681 self.assertSourceEqual(mod2.func88, 88, 90) 682 683 def test_method_in_dynamic_class(self): 684 self.assertSourceEqual(mod2.method_in_dynamic_class, 95, 97) 685 686 # This should not skip for CPython, but might on a repackaged python where 687 # unicodedata is not an external module, or on pypy. 688 @unittest.skipIf(not hasattr(unicodedata, '__file__') or 689 unicodedata.__file__.endswith('.py'), 690 "unicodedata is not an external binary module") 691 def test_findsource_binary(self): 692 self.assertRaises(OSError, inspect.getsource, unicodedata) 693 self.assertRaises(OSError, inspect.findsource, unicodedata) 694 695 def test_findsource_code_in_linecache(self): 696 lines = ["x=1"] 697 co = compile(lines[0], "_dynamically_created_file", "exec") 698 self.assertRaises(OSError, inspect.findsource, co) 699 self.assertRaises(OSError, inspect.getsource, co) 700 linecache.cache[co.co_filename] = (1, None, lines, co.co_filename) 701 try: 702 self.assertEqual(inspect.findsource(co), (lines,0)) 703 self.assertEqual(inspect.getsource(co), lines[0]) 704 finally: 705 del linecache.cache[co.co_filename] 706 707 def test_findsource_without_filename(self): 708 for fname in ['', '<string>']: 709 co = compile('x=1', fname, "exec") 710 self.assertRaises(IOError, inspect.findsource, co) 711 self.assertRaises(IOError, inspect.getsource, co) 712 713 def test_findsource_with_out_of_bounds_lineno(self): 714 mod_len = len(inspect.getsource(mod)) 715 src = '\n' * 2* mod_len + "def f(): pass" 716 co = compile(src, mod.__file__, "exec") 717 g, l = {}, {} 718 eval(co, g, l) 719 func = l['f'] 720 self.assertEqual(func.__code__.co_firstlineno, 1+2*mod_len) 721 with self.assertRaisesRegex(IOError, "lineno is out of bounds"): 722 inspect.findsource(func) 723 724 def test_getsource_on_method(self): 725 self.assertSourceEqual(mod2.ClassWithMethod.method, 118, 119) 726 727 def test_nested_func(self): 728 self.assertSourceEqual(mod2.cls135.func136, 136, 139) 729 730 def test_class_definition_in_multiline_string_definition(self): 731 self.assertSourceEqual(mod2.cls149, 149, 152) 732 733 def test_class_definition_in_multiline_comment(self): 734 self.assertSourceEqual(mod2.cls160, 160, 163) 735 736 def test_nested_class_definition_indented_string(self): 737 self.assertSourceEqual(mod2.cls173.cls175, 175, 176) 738 739 def test_nested_class_definition(self): 740 self.assertSourceEqual(mod2.cls183, 183, 188) 741 self.assertSourceEqual(mod2.cls183.cls185, 185, 188) 742 743 def test_class_decorator(self): 744 self.assertSourceEqual(mod2.cls196, 194, 201) 745 self.assertSourceEqual(mod2.cls196.cls200, 198, 201) 746 747 def test_class_inside_conditional(self): 748 self.assertSourceEqual(mod2.cls238, 238, 240) 749 self.assertSourceEqual(mod2.cls238.cls239, 239, 240) 750 751 def test_multiple_children_classes(self): 752 self.assertSourceEqual(mod2.cls203, 203, 209) 753 self.assertSourceEqual(mod2.cls203.cls204, 204, 206) 754 self.assertSourceEqual(mod2.cls203.cls204.cls205, 205, 206) 755 self.assertSourceEqual(mod2.cls203.cls207, 207, 209) 756 self.assertSourceEqual(mod2.cls203.cls207.cls205, 208, 209) 757 758 def test_nested_class_definition_inside_function(self): 759 self.assertSourceEqual(mod2.func212(), 213, 214) 760 self.assertSourceEqual(mod2.cls213, 218, 222) 761 self.assertSourceEqual(mod2.cls213().func219(), 220, 221) 762 763 def test_nested_class_definition_inside_async_function(self): 764 import asyncio 765 self.addCleanup(asyncio.set_event_loop_policy, None) 766 self.assertSourceEqual(asyncio.run(mod2.func225()), 226, 227) 767 self.assertSourceEqual(mod2.cls226, 231, 235) 768 self.assertSourceEqual(asyncio.run(mod2.cls226().func232()), 233, 234) 769 770class TestNoEOL(GetSourceBase): 771 def setUp(self): 772 self.tempdir = TESTFN + '_dir' 773 os.mkdir(self.tempdir) 774 with open(os.path.join(self.tempdir, 775 'inspect_fodder3%spy' % os.extsep), 'w') as f: 776 f.write("class X:\n pass # No EOL") 777 with DirsOnSysPath(self.tempdir): 778 import inspect_fodder3 as mod3 779 self.fodderModule = mod3 780 super().setUp() 781 782 def tearDown(self): 783 shutil.rmtree(self.tempdir) 784 785 def test_class(self): 786 self.assertSourceEqual(self.fodderModule.X, 1, 2) 787 788 789class _BrokenDataDescriptor(object): 790 """ 791 A broken data descriptor. See bug #1785. 792 """ 793 def __get__(*args): 794 raise AttributeError("broken data descriptor") 795 796 def __set__(*args): 797 raise RuntimeError 798 799 def __getattr__(*args): 800 raise AttributeError("broken data descriptor") 801 802 803class _BrokenMethodDescriptor(object): 804 """ 805 A broken method descriptor. See bug #1785. 806 """ 807 def __get__(*args): 808 raise AttributeError("broken method descriptor") 809 810 def __getattr__(*args): 811 raise AttributeError("broken method descriptor") 812 813 814# Helper for testing classify_class_attrs. 815def attrs_wo_objs(cls): 816 return [t[:3] for t in inspect.classify_class_attrs(cls)] 817 818 819class TestClassesAndFunctions(unittest.TestCase): 820 def test_newstyle_mro(self): 821 # The same w/ new-class MRO. 822 class A(object): pass 823 class B(A): pass 824 class C(A): pass 825 class D(B, C): pass 826 827 expected = (D, B, C, A, object) 828 got = inspect.getmro(D) 829 self.assertEqual(expected, got) 830 831 def assertArgSpecEquals(self, routine, args_e, varargs_e=None, 832 varkw_e=None, defaults_e=None, formatted=None): 833 with self.assertWarns(DeprecationWarning): 834 args, varargs, varkw, defaults = inspect.getargspec(routine) 835 self.assertEqual(args, args_e) 836 self.assertEqual(varargs, varargs_e) 837 self.assertEqual(varkw, varkw_e) 838 self.assertEqual(defaults, defaults_e) 839 if formatted is not None: 840 with self.assertWarns(DeprecationWarning): 841 self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults), 842 formatted) 843 844 def assertFullArgSpecEquals(self, routine, args_e, varargs_e=None, 845 varkw_e=None, defaults_e=None, 846 posonlyargs_e=[], kwonlyargs_e=[], 847 kwonlydefaults_e=None, 848 ann_e={}, formatted=None): 849 args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \ 850 inspect.getfullargspec(routine) 851 self.assertEqual(args, args_e) 852 self.assertEqual(varargs, varargs_e) 853 self.assertEqual(varkw, varkw_e) 854 self.assertEqual(defaults, defaults_e) 855 self.assertEqual(kwonlyargs, kwonlyargs_e) 856 self.assertEqual(kwonlydefaults, kwonlydefaults_e) 857 self.assertEqual(ann, ann_e) 858 if formatted is not None: 859 with self.assertWarns(DeprecationWarning): 860 self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults, 861 kwonlyargs, kwonlydefaults, ann), 862 formatted) 863 864 def test_getargspec(self): 865 self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted='(x, y)') 866 867 self.assertArgSpecEquals(mod.spam, 868 ['a', 'b', 'c', 'd', 'e', 'f'], 869 'g', 'h', (3, 4, 5), 870 '(a, b, c, d=3, e=4, f=5, *g, **h)') 871 872 self.assertRaises(ValueError, self.assertArgSpecEquals, 873 mod2.keyworded, []) 874 875 self.assertRaises(ValueError, self.assertArgSpecEquals, 876 mod2.annotated, []) 877 self.assertRaises(ValueError, self.assertArgSpecEquals, 878 mod2.keyword_only_arg, []) 879 880 881 def test_getfullargspec(self): 882 self.assertFullArgSpecEquals(mod2.keyworded, [], varargs_e='arg1', 883 kwonlyargs_e=['arg2'], 884 kwonlydefaults_e={'arg2':1}, 885 formatted='(*arg1, arg2=1)') 886 887 self.assertFullArgSpecEquals(mod2.annotated, ['arg1'], 888 ann_e={'arg1' : list}, 889 formatted='(arg1: list)') 890 self.assertFullArgSpecEquals(mod2.keyword_only_arg, [], 891 kwonlyargs_e=['arg'], 892 formatted='(*, arg)') 893 894 self.assertFullArgSpecEquals(mod2.all_markers, ['a', 'b', 'c', 'd'], 895 kwonlyargs_e=['e', 'f'], 896 formatted='(a, b, c, d, *, e, f)') 897 898 self.assertFullArgSpecEquals(mod2.all_markers_with_args_and_kwargs, 899 ['a', 'b', 'c', 'd'], 900 varargs_e='args', 901 varkw_e='kwargs', 902 kwonlyargs_e=['e', 'f'], 903 formatted='(a, b, c, d, *args, e, f, **kwargs)') 904 905 self.assertFullArgSpecEquals(mod2.all_markers_with_defaults, ['a', 'b', 'c', 'd'], 906 defaults_e=(1,2,3), 907 kwonlyargs_e=['e', 'f'], 908 kwonlydefaults_e={'e': 4, 'f': 5}, 909 formatted='(a, b=1, c=2, d=3, *, e=4, f=5)') 910 911 def test_argspec_api_ignores_wrapped(self): 912 # Issue 20684: low level introspection API must ignore __wrapped__ 913 @functools.wraps(mod.spam) 914 def ham(x, y): 915 pass 916 # Basic check 917 self.assertArgSpecEquals(ham, ['x', 'y'], formatted='(x, y)') 918 self.assertFullArgSpecEquals(ham, ['x', 'y'], formatted='(x, y)') 919 self.assertFullArgSpecEquals(functools.partial(ham), 920 ['x', 'y'], formatted='(x, y)') 921 # Other variants 922 def check_method(f): 923 self.assertArgSpecEquals(f, ['self', 'x', 'y'], 924 formatted='(self, x, y)') 925 class C: 926 @functools.wraps(mod.spam) 927 def ham(self, x, y): 928 pass 929 pham = functools.partialmethod(ham) 930 @functools.wraps(mod.spam) 931 def __call__(self, x, y): 932 pass 933 check_method(C()) 934 check_method(C.ham) 935 check_method(C().ham) 936 check_method(C.pham) 937 check_method(C().pham) 938 939 class C_new: 940 @functools.wraps(mod.spam) 941 def __new__(self, x, y): 942 pass 943 check_method(C_new) 944 945 class C_init: 946 @functools.wraps(mod.spam) 947 def __init__(self, x, y): 948 pass 949 check_method(C_init) 950 951 def test_getfullargspec_signature_attr(self): 952 def test(): 953 pass 954 spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY) 955 test.__signature__ = inspect.Signature(parameters=(spam_param,)) 956 957 self.assertFullArgSpecEquals(test, ['spam'], formatted='(spam)') 958 959 def test_getfullargspec_signature_annos(self): 960 def test(a:'spam') -> 'ham': pass 961 spec = inspect.getfullargspec(test) 962 self.assertEqual(test.__annotations__, spec.annotations) 963 964 def test(): pass 965 spec = inspect.getfullargspec(test) 966 self.assertEqual(test.__annotations__, spec.annotations) 967 968 @unittest.skipIf(MISSING_C_DOCSTRINGS, 969 "Signature information for builtins requires docstrings") 970 def test_getfullargspec_builtin_methods(self): 971 self.assertFullArgSpecEquals(_pickle.Pickler.dump, ['self', 'obj'], 972 formatted='(self, obj)') 973 974 self.assertFullArgSpecEquals(_pickle.Pickler(io.BytesIO()).dump, ['self', 'obj'], 975 formatted='(self, obj)') 976 977 self.assertFullArgSpecEquals( 978 os.stat, 979 args_e=['path'], 980 kwonlyargs_e=['dir_fd', 'follow_symlinks'], 981 kwonlydefaults_e={'dir_fd': None, 'follow_symlinks': True}, 982 formatted='(path, *, dir_fd=None, follow_symlinks=True)') 983 984 @cpython_only 985 @unittest.skipIf(MISSING_C_DOCSTRINGS, 986 "Signature information for builtins requires docstrings") 987 def test_getfullargspec_builtin_func(self): 988 import _testcapi 989 builtin = _testcapi.docstring_with_signature_with_defaults 990 spec = inspect.getfullargspec(builtin) 991 self.assertEqual(spec.defaults[0], 'avocado') 992 993 @cpython_only 994 @unittest.skipIf(MISSING_C_DOCSTRINGS, 995 "Signature information for builtins requires docstrings") 996 def test_getfullargspec_builtin_func_no_signature(self): 997 import _testcapi 998 builtin = _testcapi.docstring_no_signature 999 with self.assertRaises(TypeError): 1000 inspect.getfullargspec(builtin) 1001 1002 def test_getfullargspec_definition_order_preserved_on_kwonly(self): 1003 for fn in signatures_with_lexicographic_keyword_only_parameters(): 1004 signature = inspect.getfullargspec(fn) 1005 l = list(signature.kwonlyargs) 1006 sorted_l = sorted(l) 1007 self.assertTrue(l) 1008 self.assertEqual(l, sorted_l) 1009 signature = inspect.getfullargspec(unsorted_keyword_only_parameters_fn) 1010 l = list(signature.kwonlyargs) 1011 self.assertEqual(l, unsorted_keyword_only_parameters) 1012 1013 def test_getargspec_method(self): 1014 class A(object): 1015 def m(self): 1016 pass 1017 self.assertArgSpecEquals(A.m, ['self']) 1018 1019 def test_classify_newstyle(self): 1020 class A(object): 1021 1022 def s(): pass 1023 s = staticmethod(s) 1024 1025 def c(cls): pass 1026 c = classmethod(c) 1027 1028 def getp(self): pass 1029 p = property(getp) 1030 1031 def m(self): pass 1032 1033 def m1(self): pass 1034 1035 datablob = '1' 1036 1037 dd = _BrokenDataDescriptor() 1038 md = _BrokenMethodDescriptor() 1039 1040 attrs = attrs_wo_objs(A) 1041 1042 self.assertIn(('__new__', 'static method', object), attrs, 1043 'missing __new__') 1044 self.assertIn(('__init__', 'method', object), attrs, 'missing __init__') 1045 1046 self.assertIn(('s', 'static method', A), attrs, 'missing static method') 1047 self.assertIn(('c', 'class method', A), attrs, 'missing class method') 1048 self.assertIn(('p', 'property', A), attrs, 'missing property') 1049 self.assertIn(('m', 'method', A), attrs, 1050 'missing plain method: %r' % attrs) 1051 self.assertIn(('m1', 'method', A), attrs, 'missing plain method') 1052 self.assertIn(('datablob', 'data', A), attrs, 'missing data') 1053 self.assertIn(('md', 'method', A), attrs, 'missing method descriptor') 1054 self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor') 1055 1056 class B(A): 1057 1058 def m(self): pass 1059 1060 attrs = attrs_wo_objs(B) 1061 self.assertIn(('s', 'static method', A), attrs, 'missing static method') 1062 self.assertIn(('c', 'class method', A), attrs, 'missing class method') 1063 self.assertIn(('p', 'property', A), attrs, 'missing property') 1064 self.assertIn(('m', 'method', B), attrs, 'missing plain method') 1065 self.assertIn(('m1', 'method', A), attrs, 'missing plain method') 1066 self.assertIn(('datablob', 'data', A), attrs, 'missing data') 1067 self.assertIn(('md', 'method', A), attrs, 'missing method descriptor') 1068 self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor') 1069 1070 1071 class C(A): 1072 1073 def m(self): pass 1074 def c(self): pass 1075 1076 attrs = attrs_wo_objs(C) 1077 self.assertIn(('s', 'static method', A), attrs, 'missing static method') 1078 self.assertIn(('c', 'method', C), attrs, 'missing plain method') 1079 self.assertIn(('p', 'property', A), attrs, 'missing property') 1080 self.assertIn(('m', 'method', C), attrs, 'missing plain method') 1081 self.assertIn(('m1', 'method', A), attrs, 'missing plain method') 1082 self.assertIn(('datablob', 'data', A), attrs, 'missing data') 1083 self.assertIn(('md', 'method', A), attrs, 'missing method descriptor') 1084 self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor') 1085 1086 class D(B, C): 1087 1088 def m1(self): pass 1089 1090 attrs = attrs_wo_objs(D) 1091 self.assertIn(('s', 'static method', A), attrs, 'missing static method') 1092 self.assertIn(('c', 'method', C), attrs, 'missing plain method') 1093 self.assertIn(('p', 'property', A), attrs, 'missing property') 1094 self.assertIn(('m', 'method', B), attrs, 'missing plain method') 1095 self.assertIn(('m1', 'method', D), attrs, 'missing plain method') 1096 self.assertIn(('datablob', 'data', A), attrs, 'missing data') 1097 self.assertIn(('md', 'method', A), attrs, 'missing method descriptor') 1098 self.assertIn(('dd', 'data', A), attrs, 'missing data descriptor') 1099 1100 def test_classify_builtin_types(self): 1101 # Simple sanity check that all built-in types can have their 1102 # attributes classified. 1103 for name in dir(__builtins__): 1104 builtin = getattr(__builtins__, name) 1105 if isinstance(builtin, type): 1106 inspect.classify_class_attrs(builtin) 1107 1108 attrs = attrs_wo_objs(bool) 1109 self.assertIn(('__new__', 'static method', bool), attrs, 1110 'missing __new__') 1111 self.assertIn(('from_bytes', 'class method', int), attrs, 1112 'missing class method') 1113 self.assertIn(('to_bytes', 'method', int), attrs, 1114 'missing plain method') 1115 self.assertIn(('__add__', 'method', int), attrs, 1116 'missing plain method') 1117 self.assertIn(('__and__', 'method', bool), attrs, 1118 'missing plain method') 1119 1120 def test_classify_DynamicClassAttribute(self): 1121 class Meta(type): 1122 def __getattr__(self, name): 1123 if name == 'ham': 1124 return 'spam' 1125 return super().__getattr__(name) 1126 class VA(metaclass=Meta): 1127 @types.DynamicClassAttribute 1128 def ham(self): 1129 return 'eggs' 1130 should_find_dca = inspect.Attribute('ham', 'data', VA, VA.__dict__['ham']) 1131 self.assertIn(should_find_dca, inspect.classify_class_attrs(VA)) 1132 should_find_ga = inspect.Attribute('ham', 'data', Meta, 'spam') 1133 self.assertIn(should_find_ga, inspect.classify_class_attrs(VA)) 1134 1135 def test_classify_overrides_bool(self): 1136 class NoBool(object): 1137 def __eq__(self, other): 1138 return NoBool() 1139 1140 def __bool__(self): 1141 raise NotImplementedError( 1142 "This object does not specify a boolean value") 1143 1144 class HasNB(object): 1145 dd = NoBool() 1146 1147 should_find_attr = inspect.Attribute('dd', 'data', HasNB, HasNB.dd) 1148 self.assertIn(should_find_attr, inspect.classify_class_attrs(HasNB)) 1149 1150 def test_classify_metaclass_class_attribute(self): 1151 class Meta(type): 1152 fish = 'slap' 1153 def __dir__(self): 1154 return ['__class__', '__module__', '__name__', 'fish'] 1155 class Class(metaclass=Meta): 1156 pass 1157 should_find = inspect.Attribute('fish', 'data', Meta, 'slap') 1158 self.assertIn(should_find, inspect.classify_class_attrs(Class)) 1159 1160 def test_classify_VirtualAttribute(self): 1161 class Meta(type): 1162 def __dir__(cls): 1163 return ['__class__', '__module__', '__name__', 'BOOM'] 1164 def __getattr__(self, name): 1165 if name =='BOOM': 1166 return 42 1167 return super().__getattr(name) 1168 class Class(metaclass=Meta): 1169 pass 1170 should_find = inspect.Attribute('BOOM', 'data', Meta, 42) 1171 self.assertIn(should_find, inspect.classify_class_attrs(Class)) 1172 1173 def test_classify_VirtualAttribute_multi_classes(self): 1174 class Meta1(type): 1175 def __dir__(cls): 1176 return ['__class__', '__module__', '__name__', 'one'] 1177 def __getattr__(self, name): 1178 if name =='one': 1179 return 1 1180 return super().__getattr__(name) 1181 class Meta2(type): 1182 def __dir__(cls): 1183 return ['__class__', '__module__', '__name__', 'two'] 1184 def __getattr__(self, name): 1185 if name =='two': 1186 return 2 1187 return super().__getattr__(name) 1188 class Meta3(Meta1, Meta2): 1189 def __dir__(cls): 1190 return list(sorted(set(['__class__', '__module__', '__name__', 'three'] + 1191 Meta1.__dir__(cls) + Meta2.__dir__(cls)))) 1192 def __getattr__(self, name): 1193 if name =='three': 1194 return 3 1195 return super().__getattr__(name) 1196 class Class1(metaclass=Meta1): 1197 pass 1198 class Class2(Class1, metaclass=Meta3): 1199 pass 1200 1201 should_find1 = inspect.Attribute('one', 'data', Meta1, 1) 1202 should_find2 = inspect.Attribute('two', 'data', Meta2, 2) 1203 should_find3 = inspect.Attribute('three', 'data', Meta3, 3) 1204 cca = inspect.classify_class_attrs(Class2) 1205 for sf in (should_find1, should_find2, should_find3): 1206 self.assertIn(sf, cca) 1207 1208 def test_classify_class_attrs_with_buggy_dir(self): 1209 class M(type): 1210 def __dir__(cls): 1211 return ['__class__', '__name__', 'missing'] 1212 class C(metaclass=M): 1213 pass 1214 attrs = [a[0] for a in inspect.classify_class_attrs(C)] 1215 self.assertNotIn('missing', attrs) 1216 1217 def test_getmembers_descriptors(self): 1218 class A(object): 1219 dd = _BrokenDataDescriptor() 1220 md = _BrokenMethodDescriptor() 1221 1222 def pred_wrapper(pred): 1223 # A quick'n'dirty way to discard standard attributes of new-style 1224 # classes. 1225 class Empty(object): 1226 pass 1227 def wrapped(x): 1228 if '__name__' in dir(x) and hasattr(Empty, x.__name__): 1229 return False 1230 return pred(x) 1231 return wrapped 1232 1233 ismethoddescriptor = pred_wrapper(inspect.ismethoddescriptor) 1234 isdatadescriptor = pred_wrapper(inspect.isdatadescriptor) 1235 1236 self.assertEqual(inspect.getmembers(A, ismethoddescriptor), 1237 [('md', A.__dict__['md'])]) 1238 self.assertEqual(inspect.getmembers(A, isdatadescriptor), 1239 [('dd', A.__dict__['dd'])]) 1240 1241 class B(A): 1242 pass 1243 1244 self.assertEqual(inspect.getmembers(B, ismethoddescriptor), 1245 [('md', A.__dict__['md'])]) 1246 self.assertEqual(inspect.getmembers(B, isdatadescriptor), 1247 [('dd', A.__dict__['dd'])]) 1248 1249 def test_getmembers_method(self): 1250 class B: 1251 def f(self): 1252 pass 1253 1254 self.assertIn(('f', B.f), inspect.getmembers(B)) 1255 self.assertNotIn(('f', B.f), inspect.getmembers(B, inspect.ismethod)) 1256 b = B() 1257 self.assertIn(('f', b.f), inspect.getmembers(b)) 1258 self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod)) 1259 1260 def test_getmembers_VirtualAttribute(self): 1261 class M(type): 1262 def __getattr__(cls, name): 1263 if name == 'eggs': 1264 return 'scrambled' 1265 return super().__getattr__(name) 1266 class A(metaclass=M): 1267 @types.DynamicClassAttribute 1268 def eggs(self): 1269 return 'spam' 1270 self.assertIn(('eggs', 'scrambled'), inspect.getmembers(A)) 1271 self.assertIn(('eggs', 'spam'), inspect.getmembers(A())) 1272 1273 def test_getmembers_with_buggy_dir(self): 1274 class M(type): 1275 def __dir__(cls): 1276 return ['__class__', '__name__', 'missing'] 1277 class C(metaclass=M): 1278 pass 1279 attrs = [a[0] for a in inspect.getmembers(C)] 1280 self.assertNotIn('missing', attrs) 1281 1282class TestIsDataDescriptor(unittest.TestCase): 1283 1284 def test_custom_descriptors(self): 1285 class NonDataDescriptor: 1286 def __get__(self, value, type=None): pass 1287 class DataDescriptor0: 1288 def __set__(self, name, value): pass 1289 class DataDescriptor1: 1290 def __delete__(self, name): pass 1291 class DataDescriptor2: 1292 __set__ = None 1293 self.assertFalse(inspect.isdatadescriptor(NonDataDescriptor()), 1294 'class with only __get__ not a data descriptor') 1295 self.assertTrue(inspect.isdatadescriptor(DataDescriptor0()), 1296 'class with __set__ is a data descriptor') 1297 self.assertTrue(inspect.isdatadescriptor(DataDescriptor1()), 1298 'class with __delete__ is a data descriptor') 1299 self.assertTrue(inspect.isdatadescriptor(DataDescriptor2()), 1300 'class with __set__ = None is a data descriptor') 1301 1302 def test_slot(self): 1303 class Slotted: 1304 __slots__ = 'foo', 1305 self.assertTrue(inspect.isdatadescriptor(Slotted.foo), 1306 'a slot is a data descriptor') 1307 1308 def test_property(self): 1309 class Propertied: 1310 @property 1311 def a_property(self): 1312 pass 1313 self.assertTrue(inspect.isdatadescriptor(Propertied.a_property), 1314 'a property is a data descriptor') 1315 1316 def test_functions(self): 1317 class Test(object): 1318 def instance_method(self): pass 1319 @classmethod 1320 def class_method(cls): pass 1321 @staticmethod 1322 def static_method(): pass 1323 def function(): 1324 pass 1325 a_lambda = lambda: None 1326 self.assertFalse(inspect.isdatadescriptor(Test().instance_method), 1327 'a instance method is not a data descriptor') 1328 self.assertFalse(inspect.isdatadescriptor(Test().class_method), 1329 'a class method is not a data descriptor') 1330 self.assertFalse(inspect.isdatadescriptor(Test().static_method), 1331 'a static method is not a data descriptor') 1332 self.assertFalse(inspect.isdatadescriptor(function), 1333 'a function is not a data descriptor') 1334 self.assertFalse(inspect.isdatadescriptor(a_lambda), 1335 'a lambda is not a data descriptor') 1336 1337 1338_global_ref = object() 1339class TestGetClosureVars(unittest.TestCase): 1340 1341 def test_name_resolution(self): 1342 # Basic test of the 4 different resolution mechanisms 1343 def f(nonlocal_ref): 1344 def g(local_ref): 1345 print(local_ref, nonlocal_ref, _global_ref, unbound_ref) 1346 return g 1347 _arg = object() 1348 nonlocal_vars = {"nonlocal_ref": _arg} 1349 global_vars = {"_global_ref": _global_ref} 1350 builtin_vars = {"print": print} 1351 unbound_names = {"unbound_ref"} 1352 expected = inspect.ClosureVars(nonlocal_vars, global_vars, 1353 builtin_vars, unbound_names) 1354 self.assertEqual(inspect.getclosurevars(f(_arg)), expected) 1355 1356 def test_generator_closure(self): 1357 def f(nonlocal_ref): 1358 def g(local_ref): 1359 print(local_ref, nonlocal_ref, _global_ref, unbound_ref) 1360 yield 1361 return g 1362 _arg = object() 1363 nonlocal_vars = {"nonlocal_ref": _arg} 1364 global_vars = {"_global_ref": _global_ref} 1365 builtin_vars = {"print": print} 1366 unbound_names = {"unbound_ref"} 1367 expected = inspect.ClosureVars(nonlocal_vars, global_vars, 1368 builtin_vars, unbound_names) 1369 self.assertEqual(inspect.getclosurevars(f(_arg)), expected) 1370 1371 def test_method_closure(self): 1372 class C: 1373 def f(self, nonlocal_ref): 1374 def g(local_ref): 1375 print(local_ref, nonlocal_ref, _global_ref, unbound_ref) 1376 return g 1377 _arg = object() 1378 nonlocal_vars = {"nonlocal_ref": _arg} 1379 global_vars = {"_global_ref": _global_ref} 1380 builtin_vars = {"print": print} 1381 unbound_names = {"unbound_ref"} 1382 expected = inspect.ClosureVars(nonlocal_vars, global_vars, 1383 builtin_vars, unbound_names) 1384 self.assertEqual(inspect.getclosurevars(C().f(_arg)), expected) 1385 1386 def test_nonlocal_vars(self): 1387 # More complex tests of nonlocal resolution 1388 def _nonlocal_vars(f): 1389 return inspect.getclosurevars(f).nonlocals 1390 1391 def make_adder(x): 1392 def add(y): 1393 return x + y 1394 return add 1395 1396 def curry(func, arg1): 1397 return lambda arg2: func(arg1, arg2) 1398 1399 def less_than(a, b): 1400 return a < b 1401 1402 # The infamous Y combinator. 1403 def Y(le): 1404 def g(f): 1405 return le(lambda x: f(f)(x)) 1406 Y.g_ref = g 1407 return g(g) 1408 1409 def check_y_combinator(func): 1410 self.assertEqual(_nonlocal_vars(func), {'f': Y.g_ref}) 1411 1412 inc = make_adder(1) 1413 add_two = make_adder(2) 1414 greater_than_five = curry(less_than, 5) 1415 1416 self.assertEqual(_nonlocal_vars(inc), {'x': 1}) 1417 self.assertEqual(_nonlocal_vars(add_two), {'x': 2}) 1418 self.assertEqual(_nonlocal_vars(greater_than_five), 1419 {'arg1': 5, 'func': less_than}) 1420 self.assertEqual(_nonlocal_vars((lambda x: lambda y: x + y)(3)), 1421 {'x': 3}) 1422 Y(check_y_combinator) 1423 1424 def test_getclosurevars_empty(self): 1425 def foo(): pass 1426 _empty = inspect.ClosureVars({}, {}, {}, set()) 1427 self.assertEqual(inspect.getclosurevars(lambda: True), _empty) 1428 self.assertEqual(inspect.getclosurevars(foo), _empty) 1429 1430 def test_getclosurevars_error(self): 1431 class T: pass 1432 self.assertRaises(TypeError, inspect.getclosurevars, 1) 1433 self.assertRaises(TypeError, inspect.getclosurevars, list) 1434 self.assertRaises(TypeError, inspect.getclosurevars, {}) 1435 1436 def _private_globals(self): 1437 code = """def f(): print(path)""" 1438 ns = {} 1439 exec(code, ns) 1440 return ns["f"], ns 1441 1442 def test_builtins_fallback(self): 1443 f, ns = self._private_globals() 1444 ns.pop("__builtins__", None) 1445 expected = inspect.ClosureVars({}, {}, {"print":print}, {"path"}) 1446 self.assertEqual(inspect.getclosurevars(f), expected) 1447 1448 def test_builtins_as_dict(self): 1449 f, ns = self._private_globals() 1450 ns["__builtins__"] = {"path":1} 1451 expected = inspect.ClosureVars({}, {}, {"path":1}, {"print"}) 1452 self.assertEqual(inspect.getclosurevars(f), expected) 1453 1454 def test_builtins_as_module(self): 1455 f, ns = self._private_globals() 1456 ns["__builtins__"] = os 1457 expected = inspect.ClosureVars({}, {}, {"path":os.path}, {"print"}) 1458 self.assertEqual(inspect.getclosurevars(f), expected) 1459 1460 1461class TestGetcallargsFunctions(unittest.TestCase): 1462 1463 def assertEqualCallArgs(self, func, call_params_string, locs=None): 1464 locs = dict(locs or {}, func=func) 1465 r1 = eval('func(%s)' % call_params_string, None, locs) 1466 r2 = eval('inspect.getcallargs(func, %s)' % call_params_string, None, 1467 locs) 1468 self.assertEqual(r1, r2) 1469 1470 def assertEqualException(self, func, call_param_string, locs=None): 1471 locs = dict(locs or {}, func=func) 1472 try: 1473 eval('func(%s)' % call_param_string, None, locs) 1474 except Exception as e: 1475 ex1 = e 1476 else: 1477 self.fail('Exception not raised') 1478 try: 1479 eval('inspect.getcallargs(func, %s)' % call_param_string, None, 1480 locs) 1481 except Exception as e: 1482 ex2 = e 1483 else: 1484 self.fail('Exception not raised') 1485 self.assertIs(type(ex1), type(ex2)) 1486 self.assertEqual(str(ex1), str(ex2)) 1487 del ex1, ex2 1488 1489 def makeCallable(self, signature): 1490 """Create a function that returns its locals()""" 1491 code = "lambda %s: locals()" 1492 return eval(code % signature) 1493 1494 def test_plain(self): 1495 f = self.makeCallable('a, b=1') 1496 self.assertEqualCallArgs(f, '2') 1497 self.assertEqualCallArgs(f, '2, 3') 1498 self.assertEqualCallArgs(f, 'a=2') 1499 self.assertEqualCallArgs(f, 'b=3, a=2') 1500 self.assertEqualCallArgs(f, '2, b=3') 1501 # expand *iterable / **mapping 1502 self.assertEqualCallArgs(f, '*(2,)') 1503 self.assertEqualCallArgs(f, '*[2]') 1504 self.assertEqualCallArgs(f, '*(2, 3)') 1505 self.assertEqualCallArgs(f, '*[2, 3]') 1506 self.assertEqualCallArgs(f, '**{"a":2}') 1507 self.assertEqualCallArgs(f, 'b=3, **{"a":2}') 1508 self.assertEqualCallArgs(f, '2, **{"b":3}') 1509 self.assertEqualCallArgs(f, '**{"b":3, "a":2}') 1510 # expand UserList / UserDict 1511 self.assertEqualCallArgs(f, '*collections.UserList([2])') 1512 self.assertEqualCallArgs(f, '*collections.UserList([2, 3])') 1513 self.assertEqualCallArgs(f, '**collections.UserDict(a=2)') 1514 self.assertEqualCallArgs(f, '2, **collections.UserDict(b=3)') 1515 self.assertEqualCallArgs(f, 'b=2, **collections.UserDict(a=3)') 1516 1517 def test_varargs(self): 1518 f = self.makeCallable('a, b=1, *c') 1519 self.assertEqualCallArgs(f, '2') 1520 self.assertEqualCallArgs(f, '2, 3') 1521 self.assertEqualCallArgs(f, '2, 3, 4') 1522 self.assertEqualCallArgs(f, '*(2,3,4)') 1523 self.assertEqualCallArgs(f, '2, *[3,4]') 1524 self.assertEqualCallArgs(f, '2, 3, *collections.UserList([4])') 1525 1526 def test_varkw(self): 1527 f = self.makeCallable('a, b=1, **c') 1528 self.assertEqualCallArgs(f, 'a=2') 1529 self.assertEqualCallArgs(f, '2, b=3, c=4') 1530 self.assertEqualCallArgs(f, 'b=3, a=2, c=4') 1531 self.assertEqualCallArgs(f, 'c=4, **{"a":2, "b":3}') 1532 self.assertEqualCallArgs(f, '2, c=4, **{"b":3}') 1533 self.assertEqualCallArgs(f, 'b=2, **{"a":3, "c":4}') 1534 self.assertEqualCallArgs(f, '**collections.UserDict(a=2, b=3, c=4)') 1535 self.assertEqualCallArgs(f, '2, c=4, **collections.UserDict(b=3)') 1536 self.assertEqualCallArgs(f, 'b=2, **collections.UserDict(a=3, c=4)') 1537 1538 def test_varkw_only(self): 1539 # issue11256: 1540 f = self.makeCallable('**c') 1541 self.assertEqualCallArgs(f, '') 1542 self.assertEqualCallArgs(f, 'a=1') 1543 self.assertEqualCallArgs(f, 'a=1, b=2') 1544 self.assertEqualCallArgs(f, 'c=3, **{"a": 1, "b": 2}') 1545 self.assertEqualCallArgs(f, '**collections.UserDict(a=1, b=2)') 1546 self.assertEqualCallArgs(f, 'c=3, **collections.UserDict(a=1, b=2)') 1547 1548 def test_keyword_only(self): 1549 f = self.makeCallable('a=3, *, c, d=2') 1550 self.assertEqualCallArgs(f, 'c=3') 1551 self.assertEqualCallArgs(f, 'c=3, a=3') 1552 self.assertEqualCallArgs(f, 'a=2, c=4') 1553 self.assertEqualCallArgs(f, '4, c=4') 1554 self.assertEqualException(f, '') 1555 self.assertEqualException(f, '3') 1556 self.assertEqualException(f, 'a=3') 1557 self.assertEqualException(f, 'd=4') 1558 1559 f = self.makeCallable('*, c, d=2') 1560 self.assertEqualCallArgs(f, 'c=3') 1561 self.assertEqualCallArgs(f, 'c=3, d=4') 1562 self.assertEqualCallArgs(f, 'd=4, c=3') 1563 1564 def test_multiple_features(self): 1565 f = self.makeCallable('a, b=2, *f, **g') 1566 self.assertEqualCallArgs(f, '2, 3, 7') 1567 self.assertEqualCallArgs(f, '2, 3, x=8') 1568 self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]') 1569 self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9') 1570 self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9') 1571 self.assertEqualCallArgs(f, 'x=8, *collections.UserList(' 1572 '[2, 3, (4,[5,6])]), **{"y":9, "z":10}') 1573 self.assertEqualCallArgs(f, '2, x=8, *collections.UserList([3, ' 1574 '(4,[5,6])]), **collections.UserDict(' 1575 'y=9, z=10)') 1576 1577 f = self.makeCallable('a, b=2, *f, x, y=99, **g') 1578 self.assertEqualCallArgs(f, '2, 3, x=8') 1579 self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]') 1580 self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9, z=10') 1581 self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9, z=10') 1582 self.assertEqualCallArgs(f, 'x=8, *collections.UserList(' 1583 '[2, 3, (4,[5,6])]), q=0, **{"y":9, "z":10}') 1584 self.assertEqualCallArgs(f, '2, x=8, *collections.UserList([3, ' 1585 '(4,[5,6])]), q=0, **collections.UserDict(' 1586 'y=9, z=10)') 1587 1588 def test_errors(self): 1589 f0 = self.makeCallable('') 1590 f1 = self.makeCallable('a, b') 1591 f2 = self.makeCallable('a, b=1') 1592 # f0 takes no arguments 1593 self.assertEqualException(f0, '1') 1594 self.assertEqualException(f0, 'x=1') 1595 self.assertEqualException(f0, '1,x=1') 1596 # f1 takes exactly 2 arguments 1597 self.assertEqualException(f1, '') 1598 self.assertEqualException(f1, '1') 1599 self.assertEqualException(f1, 'a=2') 1600 self.assertEqualException(f1, 'b=3') 1601 # f2 takes at least 1 argument 1602 self.assertEqualException(f2, '') 1603 self.assertEqualException(f2, 'b=3') 1604 for f in f1, f2: 1605 # f1/f2 takes exactly/at most 2 arguments 1606 self.assertEqualException(f, '2, 3, 4') 1607 self.assertEqualException(f, '1, 2, 3, a=1') 1608 self.assertEqualException(f, '2, 3, 4, c=5') 1609 # XXX: success of this one depends on dict order 1610 ## self.assertEqualException(f, '2, 3, 4, a=1, c=5') 1611 # f got an unexpected keyword argument 1612 self.assertEqualException(f, 'c=2') 1613 self.assertEqualException(f, '2, c=3') 1614 self.assertEqualException(f, '2, 3, c=4') 1615 self.assertEqualException(f, '2, c=4, b=3') 1616 self.assertEqualException(f, '**{u"\u03c0\u03b9": 4}') 1617 # f got multiple values for keyword argument 1618 self.assertEqualException(f, '1, a=2') 1619 self.assertEqualException(f, '1, **{"a":2}') 1620 self.assertEqualException(f, '1, 2, b=3') 1621 # XXX: Python inconsistency 1622 # - for functions and bound methods: unexpected keyword 'c' 1623 # - for unbound methods: multiple values for keyword 'a' 1624 #self.assertEqualException(f, '1, c=3, a=2') 1625 # issue11256: 1626 f3 = self.makeCallable('**c') 1627 self.assertEqualException(f3, '1, 2') 1628 self.assertEqualException(f3, '1, 2, a=1, b=2') 1629 f4 = self.makeCallable('*, a, b=0') 1630 self.assertEqualException(f3, '1, 2') 1631 self.assertEqualException(f3, '1, 2, a=1, b=2') 1632 1633 # issue #20816: getcallargs() fails to iterate over non-existent 1634 # kwonlydefaults and raises a wrong TypeError 1635 def f5(*, a): pass 1636 with self.assertRaisesRegex(TypeError, 1637 'missing 1 required keyword-only'): 1638 inspect.getcallargs(f5) 1639 1640 1641 # issue20817: 1642 def f6(a, b, c): 1643 pass 1644 with self.assertRaisesRegex(TypeError, "'a', 'b' and 'c'"): 1645 inspect.getcallargs(f6) 1646 1647 # bpo-33197 1648 with self.assertRaisesRegex(ValueError, 1649 'variadic keyword parameters cannot' 1650 ' have default values'): 1651 inspect.Parameter("foo", kind=inspect.Parameter.VAR_KEYWORD, 1652 default=42) 1653 with self.assertRaisesRegex(ValueError, 1654 "value 5 is not a valid Parameter.kind"): 1655 inspect.Parameter("bar", kind=5, default=42) 1656 1657 with self.assertRaisesRegex(TypeError, 1658 'name must be a str, not a int'): 1659 inspect.Parameter(123, kind=4) 1660 1661class TestGetcallargsMethods(TestGetcallargsFunctions): 1662 1663 def setUp(self): 1664 class Foo(object): 1665 pass 1666 self.cls = Foo 1667 self.inst = Foo() 1668 1669 def makeCallable(self, signature): 1670 assert 'self' not in signature 1671 mk = super(TestGetcallargsMethods, self).makeCallable 1672 self.cls.method = mk('self, ' + signature) 1673 return self.inst.method 1674 1675class TestGetcallargsUnboundMethods(TestGetcallargsMethods): 1676 1677 def makeCallable(self, signature): 1678 super(TestGetcallargsUnboundMethods, self).makeCallable(signature) 1679 return self.cls.method 1680 1681 def assertEqualCallArgs(self, func, call_params_string, locs=None): 1682 return super(TestGetcallargsUnboundMethods, self).assertEqualCallArgs( 1683 *self._getAssertEqualParams(func, call_params_string, locs)) 1684 1685 def assertEqualException(self, func, call_params_string, locs=None): 1686 return super(TestGetcallargsUnboundMethods, self).assertEqualException( 1687 *self._getAssertEqualParams(func, call_params_string, locs)) 1688 1689 def _getAssertEqualParams(self, func, call_params_string, locs=None): 1690 assert 'inst' not in call_params_string 1691 locs = dict(locs or {}, inst=self.inst) 1692 return (func, 'inst,' + call_params_string, locs) 1693 1694 1695class TestGetattrStatic(unittest.TestCase): 1696 1697 def test_basic(self): 1698 class Thing(object): 1699 x = object() 1700 1701 thing = Thing() 1702 self.assertEqual(inspect.getattr_static(thing, 'x'), Thing.x) 1703 self.assertEqual(inspect.getattr_static(thing, 'x', None), Thing.x) 1704 with self.assertRaises(AttributeError): 1705 inspect.getattr_static(thing, 'y') 1706 1707 self.assertEqual(inspect.getattr_static(thing, 'y', 3), 3) 1708 1709 def test_inherited(self): 1710 class Thing(object): 1711 x = object() 1712 class OtherThing(Thing): 1713 pass 1714 1715 something = OtherThing() 1716 self.assertEqual(inspect.getattr_static(something, 'x'), Thing.x) 1717 1718 def test_instance_attr(self): 1719 class Thing(object): 1720 x = 2 1721 def __init__(self, x): 1722 self.x = x 1723 thing = Thing(3) 1724 self.assertEqual(inspect.getattr_static(thing, 'x'), 3) 1725 del thing.x 1726 self.assertEqual(inspect.getattr_static(thing, 'x'), 2) 1727 1728 def test_property(self): 1729 class Thing(object): 1730 @property 1731 def x(self): 1732 raise AttributeError("I'm pretending not to exist") 1733 thing = Thing() 1734 self.assertEqual(inspect.getattr_static(thing, 'x'), Thing.x) 1735 1736 def test_descriptor_raises_AttributeError(self): 1737 class descriptor(object): 1738 def __get__(*_): 1739 raise AttributeError("I'm pretending not to exist") 1740 desc = descriptor() 1741 class Thing(object): 1742 x = desc 1743 thing = Thing() 1744 self.assertEqual(inspect.getattr_static(thing, 'x'), desc) 1745 1746 def test_classAttribute(self): 1747 class Thing(object): 1748 x = object() 1749 1750 self.assertEqual(inspect.getattr_static(Thing, 'x'), Thing.x) 1751 1752 def test_classVirtualAttribute(self): 1753 class Thing(object): 1754 @types.DynamicClassAttribute 1755 def x(self): 1756 return self._x 1757 _x = object() 1758 1759 self.assertEqual(inspect.getattr_static(Thing, 'x'), Thing.__dict__['x']) 1760 1761 def test_inherited_classattribute(self): 1762 class Thing(object): 1763 x = object() 1764 class OtherThing(Thing): 1765 pass 1766 1767 self.assertEqual(inspect.getattr_static(OtherThing, 'x'), Thing.x) 1768 1769 def test_slots(self): 1770 class Thing(object): 1771 y = 'bar' 1772 __slots__ = ['x'] 1773 def __init__(self): 1774 self.x = 'foo' 1775 thing = Thing() 1776 self.assertEqual(inspect.getattr_static(thing, 'x'), Thing.x) 1777 self.assertEqual(inspect.getattr_static(thing, 'y'), 'bar') 1778 1779 del thing.x 1780 self.assertEqual(inspect.getattr_static(thing, 'x'), Thing.x) 1781 1782 def test_metaclass(self): 1783 class meta(type): 1784 attr = 'foo' 1785 class Thing(object, metaclass=meta): 1786 pass 1787 self.assertEqual(inspect.getattr_static(Thing, 'attr'), 'foo') 1788 1789 class sub(meta): 1790 pass 1791 class OtherThing(object, metaclass=sub): 1792 x = 3 1793 self.assertEqual(inspect.getattr_static(OtherThing, 'attr'), 'foo') 1794 1795 class OtherOtherThing(OtherThing): 1796 pass 1797 # this test is odd, but it was added as it exposed a bug 1798 self.assertEqual(inspect.getattr_static(OtherOtherThing, 'x'), 3) 1799 1800 def test_no_dict_no_slots(self): 1801 self.assertEqual(inspect.getattr_static(1, 'foo', None), None) 1802 self.assertNotEqual(inspect.getattr_static('foo', 'lower'), None) 1803 1804 def test_no_dict_no_slots_instance_member(self): 1805 # returns descriptor 1806 with open(__file__) as handle: 1807 self.assertEqual(inspect.getattr_static(handle, 'name'), type(handle).name) 1808 1809 def test_inherited_slots(self): 1810 # returns descriptor 1811 class Thing(object): 1812 __slots__ = ['x'] 1813 def __init__(self): 1814 self.x = 'foo' 1815 1816 class OtherThing(Thing): 1817 pass 1818 # it would be nice if this worked... 1819 # we get the descriptor instead of the instance attribute 1820 self.assertEqual(inspect.getattr_static(OtherThing(), 'x'), Thing.x) 1821 1822 def test_descriptor(self): 1823 class descriptor(object): 1824 def __get__(self, instance, owner): 1825 return 3 1826 class Foo(object): 1827 d = descriptor() 1828 1829 foo = Foo() 1830 1831 # for a non data descriptor we return the instance attribute 1832 foo.__dict__['d'] = 1 1833 self.assertEqual(inspect.getattr_static(foo, 'd'), 1) 1834 1835 # if the descriptor is a data-descriptor we should return the 1836 # descriptor 1837 descriptor.__set__ = lambda s, i, v: None 1838 self.assertEqual(inspect.getattr_static(foo, 'd'), Foo.__dict__['d']) 1839 1840 1841 def test_metaclass_with_descriptor(self): 1842 class descriptor(object): 1843 def __get__(self, instance, owner): 1844 return 3 1845 class meta(type): 1846 d = descriptor() 1847 class Thing(object, metaclass=meta): 1848 pass 1849 self.assertEqual(inspect.getattr_static(Thing, 'd'), meta.__dict__['d']) 1850 1851 1852 def test_class_as_property(self): 1853 class Base(object): 1854 foo = 3 1855 1856 class Something(Base): 1857 executed = False 1858 @property 1859 def __class__(self): 1860 self.executed = True 1861 return object 1862 1863 instance = Something() 1864 self.assertEqual(inspect.getattr_static(instance, 'foo'), 3) 1865 self.assertFalse(instance.executed) 1866 self.assertEqual(inspect.getattr_static(Something, 'foo'), 3) 1867 1868 def test_mro_as_property(self): 1869 class Meta(type): 1870 @property 1871 def __mro__(self): 1872 return (object,) 1873 1874 class Base(object): 1875 foo = 3 1876 1877 class Something(Base, metaclass=Meta): 1878 pass 1879 1880 self.assertEqual(inspect.getattr_static(Something(), 'foo'), 3) 1881 self.assertEqual(inspect.getattr_static(Something, 'foo'), 3) 1882 1883 def test_dict_as_property(self): 1884 test = self 1885 test.called = False 1886 1887 class Foo(dict): 1888 a = 3 1889 @property 1890 def __dict__(self): 1891 test.called = True 1892 return {} 1893 1894 foo = Foo() 1895 foo.a = 4 1896 self.assertEqual(inspect.getattr_static(foo, 'a'), 3) 1897 self.assertFalse(test.called) 1898 1899 def test_custom_object_dict(self): 1900 test = self 1901 test.called = False 1902 1903 class Custom(dict): 1904 def get(self, key, default=None): 1905 test.called = True 1906 super().get(key, default) 1907 1908 class Foo(object): 1909 a = 3 1910 foo = Foo() 1911 foo.__dict__ = Custom() 1912 self.assertEqual(inspect.getattr_static(foo, 'a'), 3) 1913 self.assertFalse(test.called) 1914 1915 def test_metaclass_dict_as_property(self): 1916 class Meta(type): 1917 @property 1918 def __dict__(self): 1919 self.executed = True 1920 1921 class Thing(metaclass=Meta): 1922 executed = False 1923 1924 def __init__(self): 1925 self.spam = 42 1926 1927 instance = Thing() 1928 self.assertEqual(inspect.getattr_static(instance, "spam"), 42) 1929 self.assertFalse(Thing.executed) 1930 1931 def test_module(self): 1932 sentinel = object() 1933 self.assertIsNot(inspect.getattr_static(sys, "version", sentinel), 1934 sentinel) 1935 1936 def test_metaclass_with_metaclass_with_dict_as_property(self): 1937 class MetaMeta(type): 1938 @property 1939 def __dict__(self): 1940 self.executed = True 1941 return dict(spam=42) 1942 1943 class Meta(type, metaclass=MetaMeta): 1944 executed = False 1945 1946 class Thing(metaclass=Meta): 1947 pass 1948 1949 with self.assertRaises(AttributeError): 1950 inspect.getattr_static(Thing, "spam") 1951 self.assertFalse(Thing.executed) 1952 1953class TestGetGeneratorState(unittest.TestCase): 1954 1955 def setUp(self): 1956 def number_generator(): 1957 for number in range(5): 1958 yield number 1959 self.generator = number_generator() 1960 1961 def _generatorstate(self): 1962 return inspect.getgeneratorstate(self.generator) 1963 1964 def test_created(self): 1965 self.assertEqual(self._generatorstate(), inspect.GEN_CREATED) 1966 1967 def test_suspended(self): 1968 next(self.generator) 1969 self.assertEqual(self._generatorstate(), inspect.GEN_SUSPENDED) 1970 1971 def test_closed_after_exhaustion(self): 1972 for i in self.generator: 1973 pass 1974 self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED) 1975 1976 def test_closed_after_immediate_exception(self): 1977 with self.assertRaises(RuntimeError): 1978 self.generator.throw(RuntimeError) 1979 self.assertEqual(self._generatorstate(), inspect.GEN_CLOSED) 1980 1981 def test_running(self): 1982 # As mentioned on issue #10220, checking for the RUNNING state only 1983 # makes sense inside the generator itself. 1984 # The following generator checks for this by using the closure's 1985 # reference to self and the generator state checking helper method 1986 def running_check_generator(): 1987 for number in range(5): 1988 self.assertEqual(self._generatorstate(), inspect.GEN_RUNNING) 1989 yield number 1990 self.assertEqual(self._generatorstate(), inspect.GEN_RUNNING) 1991 self.generator = running_check_generator() 1992 # Running up to the first yield 1993 next(self.generator) 1994 # Running after the first yield 1995 next(self.generator) 1996 1997 def test_easy_debugging(self): 1998 # repr() and str() of a generator state should contain the state name 1999 names = 'GEN_CREATED GEN_RUNNING GEN_SUSPENDED GEN_CLOSED'.split() 2000 for name in names: 2001 state = getattr(inspect, name) 2002 self.assertIn(name, repr(state)) 2003 self.assertIn(name, str(state)) 2004 2005 def test_getgeneratorlocals(self): 2006 def each(lst, a=None): 2007 b=(1, 2, 3) 2008 for v in lst: 2009 if v == 3: 2010 c = 12 2011 yield v 2012 2013 numbers = each([1, 2, 3]) 2014 self.assertEqual(inspect.getgeneratorlocals(numbers), 2015 {'a': None, 'lst': [1, 2, 3]}) 2016 next(numbers) 2017 self.assertEqual(inspect.getgeneratorlocals(numbers), 2018 {'a': None, 'lst': [1, 2, 3], 'v': 1, 2019 'b': (1, 2, 3)}) 2020 next(numbers) 2021 self.assertEqual(inspect.getgeneratorlocals(numbers), 2022 {'a': None, 'lst': [1, 2, 3], 'v': 2, 2023 'b': (1, 2, 3)}) 2024 next(numbers) 2025 self.assertEqual(inspect.getgeneratorlocals(numbers), 2026 {'a': None, 'lst': [1, 2, 3], 'v': 3, 2027 'b': (1, 2, 3), 'c': 12}) 2028 try: 2029 next(numbers) 2030 except StopIteration: 2031 pass 2032 self.assertEqual(inspect.getgeneratorlocals(numbers), {}) 2033 2034 def test_getgeneratorlocals_empty(self): 2035 def yield_one(): 2036 yield 1 2037 one = yield_one() 2038 self.assertEqual(inspect.getgeneratorlocals(one), {}) 2039 try: 2040 next(one) 2041 except StopIteration: 2042 pass 2043 self.assertEqual(inspect.getgeneratorlocals(one), {}) 2044 2045 def test_getgeneratorlocals_error(self): 2046 self.assertRaises(TypeError, inspect.getgeneratorlocals, 1) 2047 self.assertRaises(TypeError, inspect.getgeneratorlocals, lambda x: True) 2048 self.assertRaises(TypeError, inspect.getgeneratorlocals, set) 2049 self.assertRaises(TypeError, inspect.getgeneratorlocals, (2,3)) 2050 2051 2052class TestGetCoroutineState(unittest.TestCase): 2053 2054 def setUp(self): 2055 @types.coroutine 2056 def number_coroutine(): 2057 for number in range(5): 2058 yield number 2059 async def coroutine(): 2060 await number_coroutine() 2061 self.coroutine = coroutine() 2062 2063 def tearDown(self): 2064 self.coroutine.close() 2065 2066 def _coroutinestate(self): 2067 return inspect.getcoroutinestate(self.coroutine) 2068 2069 def test_created(self): 2070 self.assertEqual(self._coroutinestate(), inspect.CORO_CREATED) 2071 2072 def test_suspended(self): 2073 self.coroutine.send(None) 2074 self.assertEqual(self._coroutinestate(), inspect.CORO_SUSPENDED) 2075 2076 def test_closed_after_exhaustion(self): 2077 while True: 2078 try: 2079 self.coroutine.send(None) 2080 except StopIteration: 2081 break 2082 2083 self.assertEqual(self._coroutinestate(), inspect.CORO_CLOSED) 2084 2085 def test_closed_after_immediate_exception(self): 2086 with self.assertRaises(RuntimeError): 2087 self.coroutine.throw(RuntimeError) 2088 self.assertEqual(self._coroutinestate(), inspect.CORO_CLOSED) 2089 2090 def test_easy_debugging(self): 2091 # repr() and str() of a coroutine state should contain the state name 2092 names = 'CORO_CREATED CORO_RUNNING CORO_SUSPENDED CORO_CLOSED'.split() 2093 for name in names: 2094 state = getattr(inspect, name) 2095 self.assertIn(name, repr(state)) 2096 self.assertIn(name, str(state)) 2097 2098 def test_getcoroutinelocals(self): 2099 @types.coroutine 2100 def gencoro(): 2101 yield 2102 2103 gencoro = gencoro() 2104 async def func(a=None): 2105 b = 'spam' 2106 await gencoro 2107 2108 coro = func() 2109 self.assertEqual(inspect.getcoroutinelocals(coro), 2110 {'a': None, 'gencoro': gencoro}) 2111 coro.send(None) 2112 self.assertEqual(inspect.getcoroutinelocals(coro), 2113 {'a': None, 'gencoro': gencoro, 'b': 'spam'}) 2114 2115 2116class MySignature(inspect.Signature): 2117 # Top-level to make it picklable; 2118 # used in test_signature_object_pickle 2119 pass 2120 2121class MyParameter(inspect.Parameter): 2122 # Top-level to make it picklable; 2123 # used in test_signature_object_pickle 2124 pass 2125 2126 2127 2128class TestSignatureObject(unittest.TestCase): 2129 @staticmethod 2130 def signature(func, **kw): 2131 sig = inspect.signature(func, **kw) 2132 return (tuple((param.name, 2133 (... if param.default is param.empty else param.default), 2134 (... if param.annotation is param.empty 2135 else param.annotation), 2136 str(param.kind).lower()) 2137 for param in sig.parameters.values()), 2138 (... if sig.return_annotation is sig.empty 2139 else sig.return_annotation)) 2140 2141 def test_signature_object(self): 2142 S = inspect.Signature 2143 P = inspect.Parameter 2144 2145 self.assertEqual(str(S()), '()') 2146 self.assertEqual(repr(S().parameters), 'mappingproxy(OrderedDict())') 2147 2148 def test(po, pk, pod=42, pkd=100, *args, ko, **kwargs): 2149 pass 2150 sig = inspect.signature(test) 2151 po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY) 2152 pod = sig.parameters['pod'].replace(kind=P.POSITIONAL_ONLY) 2153 pk = sig.parameters['pk'] 2154 pkd = sig.parameters['pkd'] 2155 args = sig.parameters['args'] 2156 ko = sig.parameters['ko'] 2157 kwargs = sig.parameters['kwargs'] 2158 2159 S((po, pk, args, ko, kwargs)) 2160 2161 with self.assertRaisesRegex(ValueError, 'wrong parameter order'): 2162 S((pk, po, args, ko, kwargs)) 2163 2164 with self.assertRaisesRegex(ValueError, 'wrong parameter order'): 2165 S((po, args, pk, ko, kwargs)) 2166 2167 with self.assertRaisesRegex(ValueError, 'wrong parameter order'): 2168 S((args, po, pk, ko, kwargs)) 2169 2170 with self.assertRaisesRegex(ValueError, 'wrong parameter order'): 2171 S((po, pk, args, kwargs, ko)) 2172 2173 kwargs2 = kwargs.replace(name='args') 2174 with self.assertRaisesRegex(ValueError, 'duplicate parameter name'): 2175 S((po, pk, args, kwargs2, ko)) 2176 2177 with self.assertRaisesRegex(ValueError, 'follows default argument'): 2178 S((pod, po)) 2179 2180 with self.assertRaisesRegex(ValueError, 'follows default argument'): 2181 S((po, pkd, pk)) 2182 2183 with self.assertRaisesRegex(ValueError, 'follows default argument'): 2184 S((pkd, pk)) 2185 2186 self.assertTrue(repr(sig).startswith('<Signature')) 2187 self.assertTrue('(po, pk' in repr(sig)) 2188 2189 def test_signature_object_pickle(self): 2190 def foo(a, b, *, c:1={}, **kw) -> {42:'ham'}: pass 2191 foo_partial = functools.partial(foo, a=1) 2192 2193 sig = inspect.signature(foo_partial) 2194 2195 for ver in range(pickle.HIGHEST_PROTOCOL + 1): 2196 with self.subTest(pickle_ver=ver, subclass=False): 2197 sig_pickled = pickle.loads(pickle.dumps(sig, ver)) 2198 self.assertEqual(sig, sig_pickled) 2199 2200 # Test that basic sub-classing works 2201 sig = inspect.signature(foo) 2202 myparam = MyParameter(name='z', kind=inspect.Parameter.POSITIONAL_ONLY) 2203 myparams = collections.OrderedDict(sig.parameters, a=myparam) 2204 mysig = MySignature().replace(parameters=myparams.values(), 2205 return_annotation=sig.return_annotation) 2206 self.assertTrue(isinstance(mysig, MySignature)) 2207 self.assertTrue(isinstance(mysig.parameters['z'], MyParameter)) 2208 2209 for ver in range(pickle.HIGHEST_PROTOCOL + 1): 2210 with self.subTest(pickle_ver=ver, subclass=True): 2211 sig_pickled = pickle.loads(pickle.dumps(mysig, ver)) 2212 self.assertEqual(mysig, sig_pickled) 2213 self.assertTrue(isinstance(sig_pickled, MySignature)) 2214 self.assertTrue(isinstance(sig_pickled.parameters['z'], 2215 MyParameter)) 2216 2217 def test_signature_immutability(self): 2218 def test(a): 2219 pass 2220 sig = inspect.signature(test) 2221 2222 with self.assertRaises(AttributeError): 2223 sig.foo = 'bar' 2224 2225 with self.assertRaises(TypeError): 2226 sig.parameters['a'] = None 2227 2228 def test_signature_on_noarg(self): 2229 def test(): 2230 pass 2231 self.assertEqual(self.signature(test), ((), ...)) 2232 2233 def test_signature_on_wargs(self): 2234 def test(a, b:'foo') -> 123: 2235 pass 2236 self.assertEqual(self.signature(test), 2237 ((('a', ..., ..., "positional_or_keyword"), 2238 ('b', ..., 'foo', "positional_or_keyword")), 2239 123)) 2240 2241 def test_signature_on_wkwonly(self): 2242 def test(*, a:float, b:str) -> int: 2243 pass 2244 self.assertEqual(self.signature(test), 2245 ((('a', ..., float, "keyword_only"), 2246 ('b', ..., str, "keyword_only")), 2247 int)) 2248 2249 def test_signature_on_complex_args(self): 2250 def test(a, b:'foo'=10, *args:'bar', spam:'baz', ham=123, **kwargs:int): 2251 pass 2252 self.assertEqual(self.signature(test), 2253 ((('a', ..., ..., "positional_or_keyword"), 2254 ('b', 10, 'foo', "positional_or_keyword"), 2255 ('args', ..., 'bar', "var_positional"), 2256 ('spam', ..., 'baz', "keyword_only"), 2257 ('ham', 123, ..., "keyword_only"), 2258 ('kwargs', ..., int, "var_keyword")), 2259 ...)) 2260 2261 def test_signature_without_self(self): 2262 def test_args_only(*args): # NOQA 2263 pass 2264 2265 def test_args_kwargs_only(*args, **kwargs): # NOQA 2266 pass 2267 2268 class A: 2269 @classmethod 2270 def test_classmethod(*args): # NOQA 2271 pass 2272 2273 @staticmethod 2274 def test_staticmethod(*args): # NOQA 2275 pass 2276 2277 f1 = functools.partialmethod((test_classmethod), 1) 2278 f2 = functools.partialmethod((test_args_only), 1) 2279 f3 = functools.partialmethod((test_staticmethod), 1) 2280 f4 = functools.partialmethod((test_args_kwargs_only),1) 2281 2282 self.assertEqual(self.signature(test_args_only), 2283 ((('args', ..., ..., 'var_positional'),), ...)) 2284 self.assertEqual(self.signature(test_args_kwargs_only), 2285 ((('args', ..., ..., 'var_positional'), 2286 ('kwargs', ..., ..., 'var_keyword')), ...)) 2287 self.assertEqual(self.signature(A.f1), 2288 ((('args', ..., ..., 'var_positional'),), ...)) 2289 self.assertEqual(self.signature(A.f2), 2290 ((('args', ..., ..., 'var_positional'),), ...)) 2291 self.assertEqual(self.signature(A.f3), 2292 ((('args', ..., ..., 'var_positional'),), ...)) 2293 self.assertEqual(self.signature(A.f4), 2294 ((('args', ..., ..., 'var_positional'), 2295 ('kwargs', ..., ..., 'var_keyword')), ...)) 2296 @cpython_only 2297 @unittest.skipIf(MISSING_C_DOCSTRINGS, 2298 "Signature information for builtins requires docstrings") 2299 def test_signature_on_builtins(self): 2300 import _testcapi 2301 2302 def test_unbound_method(o): 2303 """Use this to test unbound methods (things that should have a self)""" 2304 signature = inspect.signature(o) 2305 self.assertTrue(isinstance(signature, inspect.Signature)) 2306 self.assertEqual(list(signature.parameters.values())[0].name, 'self') 2307 return signature 2308 2309 def test_callable(o): 2310 """Use this to test bound methods or normal callables (things that don't expect self)""" 2311 signature = inspect.signature(o) 2312 self.assertTrue(isinstance(signature, inspect.Signature)) 2313 if signature.parameters: 2314 self.assertNotEqual(list(signature.parameters.values())[0].name, 'self') 2315 return signature 2316 2317 signature = test_callable(_testcapi.docstring_with_signature_with_defaults) 2318 def p(name): return signature.parameters[name].default 2319 self.assertEqual(p('s'), 'avocado') 2320 self.assertEqual(p('b'), b'bytes') 2321 self.assertEqual(p('d'), 3.14) 2322 self.assertEqual(p('i'), 35) 2323 self.assertEqual(p('n'), None) 2324 self.assertEqual(p('t'), True) 2325 self.assertEqual(p('f'), False) 2326 self.assertEqual(p('local'), 3) 2327 self.assertEqual(p('sys'), sys.maxsize) 2328 self.assertNotIn('exp', signature.parameters) 2329 2330 test_callable(object) 2331 2332 # normal method 2333 # (PyMethodDescr_Type, "method_descriptor") 2334 test_unbound_method(_pickle.Pickler.dump) 2335 d = _pickle.Pickler(io.StringIO()) 2336 test_callable(d.dump) 2337 2338 # static method 2339 test_callable(bytes.maketrans) 2340 test_callable(b'abc'.maketrans) 2341 2342 # class method 2343 test_callable(dict.fromkeys) 2344 test_callable({}.fromkeys) 2345 2346 # wrapper around slot (PyWrapperDescr_Type, "wrapper_descriptor") 2347 test_unbound_method(type.__call__) 2348 test_unbound_method(int.__add__) 2349 test_callable((3).__add__) 2350 2351 # _PyMethodWrapper_Type 2352 # support for 'method-wrapper' 2353 test_callable(min.__call__) 2354 2355 # This doesn't work now. 2356 # (We don't have a valid signature for "type" in 3.4) 2357 with self.assertRaisesRegex(ValueError, "no signature found"): 2358 class ThisWorksNow: 2359 __call__ = type 2360 test_callable(ThisWorksNow()) 2361 2362 # Regression test for issue #20786 2363 test_unbound_method(dict.__delitem__) 2364 test_unbound_method(property.__delete__) 2365 2366 # Regression test for issue #20586 2367 test_callable(_testcapi.docstring_with_signature_but_no_doc) 2368 2369 @cpython_only 2370 @unittest.skipIf(MISSING_C_DOCSTRINGS, 2371 "Signature information for builtins requires docstrings") 2372 def test_signature_on_decorated_builtins(self): 2373 import _testcapi 2374 func = _testcapi.docstring_with_signature_with_defaults 2375 2376 def decorator(func): 2377 @functools.wraps(func) 2378 def wrapper(*args, **kwargs) -> int: 2379 return func(*args, **kwargs) 2380 return wrapper 2381 2382 decorated_func = decorator(func) 2383 2384 self.assertEqual(inspect.signature(func), 2385 inspect.signature(decorated_func)) 2386 2387 def wrapper_like(*args, **kwargs) -> int: pass 2388 self.assertEqual(inspect.signature(decorated_func, 2389 follow_wrapped=False), 2390 inspect.signature(wrapper_like)) 2391 2392 @cpython_only 2393 def test_signature_on_builtins_no_signature(self): 2394 import _testcapi 2395 with self.assertRaisesRegex(ValueError, 2396 'no signature found for builtin'): 2397 inspect.signature(_testcapi.docstring_no_signature) 2398 2399 with self.assertRaisesRegex(ValueError, 2400 'no signature found for builtin'): 2401 inspect.signature(str) 2402 2403 def test_signature_on_non_function(self): 2404 with self.assertRaisesRegex(TypeError, 'is not a callable object'): 2405 inspect.signature(42) 2406 2407 def test_signature_from_functionlike_object(self): 2408 def func(a,b, *args, kwonly=True, kwonlyreq, **kwargs): 2409 pass 2410 2411 class funclike: 2412 # Has to be callable, and have correct 2413 # __code__, __annotations__, __defaults__, __name__, 2414 # and __kwdefaults__ attributes 2415 2416 def __init__(self, func): 2417 self.__name__ = func.__name__ 2418 self.__code__ = func.__code__ 2419 self.__annotations__ = func.__annotations__ 2420 self.__defaults__ = func.__defaults__ 2421 self.__kwdefaults__ = func.__kwdefaults__ 2422 self.func = func 2423 2424 def __call__(self, *args, **kwargs): 2425 return self.func(*args, **kwargs) 2426 2427 sig_func = inspect.Signature.from_callable(func) 2428 2429 sig_funclike = inspect.Signature.from_callable(funclike(func)) 2430 self.assertEqual(sig_funclike, sig_func) 2431 2432 sig_funclike = inspect.signature(funclike(func)) 2433 self.assertEqual(sig_funclike, sig_func) 2434 2435 # If object is not a duck type of function, then 2436 # signature will try to get a signature for its '__call__' 2437 # method 2438 fl = funclike(func) 2439 del fl.__defaults__ 2440 self.assertEqual(self.signature(fl), 2441 ((('args', ..., ..., "var_positional"), 2442 ('kwargs', ..., ..., "var_keyword")), 2443 ...)) 2444 2445 # Test with cython-like builtins: 2446 _orig_isdesc = inspect.ismethoddescriptor 2447 def _isdesc(obj): 2448 if hasattr(obj, '_builtinmock'): 2449 return True 2450 return _orig_isdesc(obj) 2451 2452 with unittest.mock.patch('inspect.ismethoddescriptor', _isdesc): 2453 builtin_func = funclike(func) 2454 # Make sure that our mock setup is working 2455 self.assertFalse(inspect.ismethoddescriptor(builtin_func)) 2456 builtin_func._builtinmock = True 2457 self.assertTrue(inspect.ismethoddescriptor(builtin_func)) 2458 self.assertEqual(inspect.signature(builtin_func), sig_func) 2459 2460 def test_signature_functionlike_class(self): 2461 # We only want to duck type function-like objects, 2462 # not classes. 2463 2464 def func(a,b, *args, kwonly=True, kwonlyreq, **kwargs): 2465 pass 2466 2467 class funclike: 2468 def __init__(self, marker): 2469 pass 2470 2471 __name__ = func.__name__ 2472 __code__ = func.__code__ 2473 __annotations__ = func.__annotations__ 2474 __defaults__ = func.__defaults__ 2475 __kwdefaults__ = func.__kwdefaults__ 2476 2477 self.assertEqual(str(inspect.signature(funclike)), '(marker)') 2478 2479 def test_signature_on_method(self): 2480 class Test: 2481 def __init__(*args): 2482 pass 2483 def m1(self, arg1, arg2=1) -> int: 2484 pass 2485 def m2(*args): 2486 pass 2487 def __call__(*, a): 2488 pass 2489 2490 self.assertEqual(self.signature(Test().m1), 2491 ((('arg1', ..., ..., "positional_or_keyword"), 2492 ('arg2', 1, ..., "positional_or_keyword")), 2493 int)) 2494 2495 self.assertEqual(self.signature(Test().m2), 2496 ((('args', ..., ..., "var_positional"),), 2497 ...)) 2498 2499 self.assertEqual(self.signature(Test), 2500 ((('args', ..., ..., "var_positional"),), 2501 ...)) 2502 2503 with self.assertRaisesRegex(ValueError, 'invalid method signature'): 2504 self.signature(Test()) 2505 2506 def test_signature_wrapped_bound_method(self): 2507 # Issue 24298 2508 class Test: 2509 def m1(self, arg1, arg2=1) -> int: 2510 pass 2511 @functools.wraps(Test().m1) 2512 def m1d(*args, **kwargs): 2513 pass 2514 self.assertEqual(self.signature(m1d), 2515 ((('arg1', ..., ..., "positional_or_keyword"), 2516 ('arg2', 1, ..., "positional_or_keyword")), 2517 int)) 2518 2519 def test_signature_on_classmethod(self): 2520 class Test: 2521 @classmethod 2522 def foo(cls, arg1, *, arg2=1): 2523 pass 2524 2525 meth = Test().foo 2526 self.assertEqual(self.signature(meth), 2527 ((('arg1', ..., ..., "positional_or_keyword"), 2528 ('arg2', 1, ..., "keyword_only")), 2529 ...)) 2530 2531 meth = Test.foo 2532 self.assertEqual(self.signature(meth), 2533 ((('arg1', ..., ..., "positional_or_keyword"), 2534 ('arg2', 1, ..., "keyword_only")), 2535 ...)) 2536 2537 def test_signature_on_staticmethod(self): 2538 class Test: 2539 @staticmethod 2540 def foo(cls, *, arg): 2541 pass 2542 2543 meth = Test().foo 2544 self.assertEqual(self.signature(meth), 2545 ((('cls', ..., ..., "positional_or_keyword"), 2546 ('arg', ..., ..., "keyword_only")), 2547 ...)) 2548 2549 meth = Test.foo 2550 self.assertEqual(self.signature(meth), 2551 ((('cls', ..., ..., "positional_or_keyword"), 2552 ('arg', ..., ..., "keyword_only")), 2553 ...)) 2554 2555 def test_signature_on_partial(self): 2556 from functools import partial 2557 2558 Parameter = inspect.Parameter 2559 2560 def test(): 2561 pass 2562 2563 self.assertEqual(self.signature(partial(test)), ((), ...)) 2564 2565 with self.assertRaisesRegex(ValueError, "has incorrect arguments"): 2566 inspect.signature(partial(test, 1)) 2567 2568 with self.assertRaisesRegex(ValueError, "has incorrect arguments"): 2569 inspect.signature(partial(test, a=1)) 2570 2571 def test(a, b, *, c, d): 2572 pass 2573 2574 self.assertEqual(self.signature(partial(test)), 2575 ((('a', ..., ..., "positional_or_keyword"), 2576 ('b', ..., ..., "positional_or_keyword"), 2577 ('c', ..., ..., "keyword_only"), 2578 ('d', ..., ..., "keyword_only")), 2579 ...)) 2580 2581 self.assertEqual(self.signature(partial(test, 1)), 2582 ((('b', ..., ..., "positional_or_keyword"), 2583 ('c', ..., ..., "keyword_only"), 2584 ('d', ..., ..., "keyword_only")), 2585 ...)) 2586 2587 self.assertEqual(self.signature(partial(test, 1, c=2)), 2588 ((('b', ..., ..., "positional_or_keyword"), 2589 ('c', 2, ..., "keyword_only"), 2590 ('d', ..., ..., "keyword_only")), 2591 ...)) 2592 2593 self.assertEqual(self.signature(partial(test, b=1, c=2)), 2594 ((('a', ..., ..., "positional_or_keyword"), 2595 ('b', 1, ..., "keyword_only"), 2596 ('c', 2, ..., "keyword_only"), 2597 ('d', ..., ..., "keyword_only")), 2598 ...)) 2599 2600 self.assertEqual(self.signature(partial(test, 0, b=1, c=2)), 2601 ((('b', 1, ..., "keyword_only"), 2602 ('c', 2, ..., "keyword_only"), 2603 ('d', ..., ..., "keyword_only")), 2604 ...)) 2605 2606 self.assertEqual(self.signature(partial(test, a=1)), 2607 ((('a', 1, ..., "keyword_only"), 2608 ('b', ..., ..., "keyword_only"), 2609 ('c', ..., ..., "keyword_only"), 2610 ('d', ..., ..., "keyword_only")), 2611 ...)) 2612 2613 def test(a, *args, b, **kwargs): 2614 pass 2615 2616 self.assertEqual(self.signature(partial(test, 1)), 2617 ((('args', ..., ..., "var_positional"), 2618 ('b', ..., ..., "keyword_only"), 2619 ('kwargs', ..., ..., "var_keyword")), 2620 ...)) 2621 2622 self.assertEqual(self.signature(partial(test, a=1)), 2623 ((('a', 1, ..., "keyword_only"), 2624 ('b', ..., ..., "keyword_only"), 2625 ('kwargs', ..., ..., "var_keyword")), 2626 ...)) 2627 2628 self.assertEqual(self.signature(partial(test, 1, 2, 3)), 2629 ((('args', ..., ..., "var_positional"), 2630 ('b', ..., ..., "keyword_only"), 2631 ('kwargs', ..., ..., "var_keyword")), 2632 ...)) 2633 2634 self.assertEqual(self.signature(partial(test, 1, 2, 3, test=True)), 2635 ((('args', ..., ..., "var_positional"), 2636 ('b', ..., ..., "keyword_only"), 2637 ('kwargs', ..., ..., "var_keyword")), 2638 ...)) 2639 2640 self.assertEqual(self.signature(partial(test, 1, 2, 3, test=1, b=0)), 2641 ((('args', ..., ..., "var_positional"), 2642 ('b', 0, ..., "keyword_only"), 2643 ('kwargs', ..., ..., "var_keyword")), 2644 ...)) 2645 2646 self.assertEqual(self.signature(partial(test, b=0)), 2647 ((('a', ..., ..., "positional_or_keyword"), 2648 ('args', ..., ..., "var_positional"), 2649 ('b', 0, ..., "keyword_only"), 2650 ('kwargs', ..., ..., "var_keyword")), 2651 ...)) 2652 2653 self.assertEqual(self.signature(partial(test, b=0, test=1)), 2654 ((('a', ..., ..., "positional_or_keyword"), 2655 ('args', ..., ..., "var_positional"), 2656 ('b', 0, ..., "keyword_only"), 2657 ('kwargs', ..., ..., "var_keyword")), 2658 ...)) 2659 2660 def test(a, b, c:int) -> 42: 2661 pass 2662 2663 sig = test.__signature__ = inspect.signature(test) 2664 2665 self.assertEqual(self.signature(partial(partial(test, 1))), 2666 ((('b', ..., ..., "positional_or_keyword"), 2667 ('c', ..., int, "positional_or_keyword")), 2668 42)) 2669 2670 self.assertEqual(self.signature(partial(partial(test, 1), 2)), 2671 ((('c', ..., int, "positional_or_keyword"),), 2672 42)) 2673 2674 psig = inspect.signature(partial(partial(test, 1), 2)) 2675 2676 def foo(a): 2677 return a 2678 _foo = partial(partial(foo, a=10), a=20) 2679 self.assertEqual(self.signature(_foo), 2680 ((('a', 20, ..., "keyword_only"),), 2681 ...)) 2682 # check that we don't have any side-effects in signature(), 2683 # and the partial object is still functioning 2684 self.assertEqual(_foo(), 20) 2685 2686 def foo(a, b, c): 2687 return a, b, c 2688 _foo = partial(partial(foo, 1, b=20), b=30) 2689 2690 self.assertEqual(self.signature(_foo), 2691 ((('b', 30, ..., "keyword_only"), 2692 ('c', ..., ..., "keyword_only")), 2693 ...)) 2694 self.assertEqual(_foo(c=10), (1, 30, 10)) 2695 2696 def foo(a, b, c, *, d): 2697 return a, b, c, d 2698 _foo = partial(partial(foo, d=20, c=20), b=10, d=30) 2699 self.assertEqual(self.signature(_foo), 2700 ((('a', ..., ..., "positional_or_keyword"), 2701 ('b', 10, ..., "keyword_only"), 2702 ('c', 20, ..., "keyword_only"), 2703 ('d', 30, ..., "keyword_only"), 2704 ), 2705 ...)) 2706 ba = inspect.signature(_foo).bind(a=200, b=11) 2707 self.assertEqual(_foo(*ba.args, **ba.kwargs), (200, 11, 20, 30)) 2708 2709 def foo(a=1, b=2, c=3): 2710 return a, b, c 2711 _foo = partial(foo, c=13) # (a=1, b=2, *, c=13) 2712 2713 ba = inspect.signature(_foo).bind(a=11) 2714 self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 2, 13)) 2715 2716 ba = inspect.signature(_foo).bind(11, 12) 2717 self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 12, 13)) 2718 2719 ba = inspect.signature(_foo).bind(11, b=12) 2720 self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 12, 13)) 2721 2722 ba = inspect.signature(_foo).bind(b=12) 2723 self.assertEqual(_foo(*ba.args, **ba.kwargs), (1, 12, 13)) 2724 2725 _foo = partial(_foo, b=10, c=20) 2726 ba = inspect.signature(_foo).bind(12) 2727 self.assertEqual(_foo(*ba.args, **ba.kwargs), (12, 10, 20)) 2728 2729 2730 def foo(a, b, c, d, **kwargs): 2731 pass 2732 sig = inspect.signature(foo) 2733 params = sig.parameters.copy() 2734 params['a'] = params['a'].replace(kind=Parameter.POSITIONAL_ONLY) 2735 params['b'] = params['b'].replace(kind=Parameter.POSITIONAL_ONLY) 2736 foo.__signature__ = inspect.Signature(params.values()) 2737 sig = inspect.signature(foo) 2738 self.assertEqual(str(sig), '(a, b, /, c, d, **kwargs)') 2739 2740 self.assertEqual(self.signature(partial(foo, 1)), 2741 ((('b', ..., ..., 'positional_only'), 2742 ('c', ..., ..., 'positional_or_keyword'), 2743 ('d', ..., ..., 'positional_or_keyword'), 2744 ('kwargs', ..., ..., 'var_keyword')), 2745 ...)) 2746 2747 self.assertEqual(self.signature(partial(foo, 1, 2)), 2748 ((('c', ..., ..., 'positional_or_keyword'), 2749 ('d', ..., ..., 'positional_or_keyword'), 2750 ('kwargs', ..., ..., 'var_keyword')), 2751 ...)) 2752 2753 self.assertEqual(self.signature(partial(foo, 1, 2, 3)), 2754 ((('d', ..., ..., 'positional_or_keyword'), 2755 ('kwargs', ..., ..., 'var_keyword')), 2756 ...)) 2757 2758 self.assertEqual(self.signature(partial(foo, 1, 2, c=3)), 2759 ((('c', 3, ..., 'keyword_only'), 2760 ('d', ..., ..., 'keyword_only'), 2761 ('kwargs', ..., ..., 'var_keyword')), 2762 ...)) 2763 2764 self.assertEqual(self.signature(partial(foo, 1, c=3)), 2765 ((('b', ..., ..., 'positional_only'), 2766 ('c', 3, ..., 'keyword_only'), 2767 ('d', ..., ..., 'keyword_only'), 2768 ('kwargs', ..., ..., 'var_keyword')), 2769 ...)) 2770 2771 def test_signature_on_partialmethod(self): 2772 from functools import partialmethod 2773 2774 class Spam: 2775 def test(): 2776 pass 2777 ham = partialmethod(test) 2778 2779 with self.assertRaisesRegex(ValueError, "has incorrect arguments"): 2780 inspect.signature(Spam.ham) 2781 2782 class Spam: 2783 def test(it, a, *, c) -> 'spam': 2784 pass 2785 ham = partialmethod(test, c=1) 2786 2787 self.assertEqual(self.signature(Spam.ham), 2788 ((('it', ..., ..., 'positional_or_keyword'), 2789 ('a', ..., ..., 'positional_or_keyword'), 2790 ('c', 1, ..., 'keyword_only')), 2791 'spam')) 2792 2793 self.assertEqual(self.signature(Spam().ham), 2794 ((('a', ..., ..., 'positional_or_keyword'), 2795 ('c', 1, ..., 'keyword_only')), 2796 'spam')) 2797 2798 class Spam: 2799 def test(self: 'anno', x): 2800 pass 2801 2802 g = partialmethod(test, 1) 2803 2804 self.assertEqual(self.signature(Spam.g), 2805 ((('self', ..., 'anno', 'positional_or_keyword'),), 2806 ...)) 2807 2808 def test_signature_on_fake_partialmethod(self): 2809 def foo(a): pass 2810 foo._partialmethod = 'spam' 2811 self.assertEqual(str(inspect.signature(foo)), '(a)') 2812 2813 def test_signature_on_decorated(self): 2814 import functools 2815 2816 def decorator(func): 2817 @functools.wraps(func) 2818 def wrapper(*args, **kwargs) -> int: 2819 return func(*args, **kwargs) 2820 return wrapper 2821 2822 class Foo: 2823 @decorator 2824 def bar(self, a, b): 2825 pass 2826 2827 self.assertEqual(self.signature(Foo.bar), 2828 ((('self', ..., ..., "positional_or_keyword"), 2829 ('a', ..., ..., "positional_or_keyword"), 2830 ('b', ..., ..., "positional_or_keyword")), 2831 ...)) 2832 2833 self.assertEqual(self.signature(Foo().bar), 2834 ((('a', ..., ..., "positional_or_keyword"), 2835 ('b', ..., ..., "positional_or_keyword")), 2836 ...)) 2837 2838 self.assertEqual(self.signature(Foo.bar, follow_wrapped=False), 2839 ((('args', ..., ..., "var_positional"), 2840 ('kwargs', ..., ..., "var_keyword")), 2841 ...)) # functools.wraps will copy __annotations__ 2842 # from "func" to "wrapper", hence no 2843 # return_annotation 2844 2845 # Test that we handle method wrappers correctly 2846 def decorator(func): 2847 @functools.wraps(func) 2848 def wrapper(*args, **kwargs) -> int: 2849 return func(42, *args, **kwargs) 2850 sig = inspect.signature(func) 2851 new_params = tuple(sig.parameters.values())[1:] 2852 wrapper.__signature__ = sig.replace(parameters=new_params) 2853 return wrapper 2854 2855 class Foo: 2856 @decorator 2857 def __call__(self, a, b): 2858 pass 2859 2860 self.assertEqual(self.signature(Foo.__call__), 2861 ((('a', ..., ..., "positional_or_keyword"), 2862 ('b', ..., ..., "positional_or_keyword")), 2863 ...)) 2864 2865 self.assertEqual(self.signature(Foo().__call__), 2866 ((('b', ..., ..., "positional_or_keyword"),), 2867 ...)) 2868 2869 # Test we handle __signature__ partway down the wrapper stack 2870 def wrapped_foo_call(): 2871 pass 2872 wrapped_foo_call.__wrapped__ = Foo.__call__ 2873 2874 self.assertEqual(self.signature(wrapped_foo_call), 2875 ((('a', ..., ..., "positional_or_keyword"), 2876 ('b', ..., ..., "positional_or_keyword")), 2877 ...)) 2878 2879 2880 def test_signature_on_class(self): 2881 class C: 2882 def __init__(self, a): 2883 pass 2884 2885 self.assertEqual(self.signature(C), 2886 ((('a', ..., ..., "positional_or_keyword"),), 2887 ...)) 2888 2889 class CM(type): 2890 def __call__(cls, a): 2891 pass 2892 class C(metaclass=CM): 2893 def __init__(self, b): 2894 pass 2895 2896 self.assertEqual(self.signature(C), 2897 ((('a', ..., ..., "positional_or_keyword"),), 2898 ...)) 2899 2900 class CM(type): 2901 def __new__(mcls, name, bases, dct, *, foo=1): 2902 return super().__new__(mcls, name, bases, dct) 2903 class C(metaclass=CM): 2904 def __init__(self, b): 2905 pass 2906 2907 self.assertEqual(self.signature(C), 2908 ((('b', ..., ..., "positional_or_keyword"),), 2909 ...)) 2910 2911 self.assertEqual(self.signature(CM), 2912 ((('name', ..., ..., "positional_or_keyword"), 2913 ('bases', ..., ..., "positional_or_keyword"), 2914 ('dct', ..., ..., "positional_or_keyword"), 2915 ('foo', 1, ..., "keyword_only")), 2916 ...)) 2917 2918 class CMM(type): 2919 def __new__(mcls, name, bases, dct, *, foo=1): 2920 return super().__new__(mcls, name, bases, dct) 2921 def __call__(cls, nm, bs, dt): 2922 return type(nm, bs, dt) 2923 class CM(type, metaclass=CMM): 2924 def __new__(mcls, name, bases, dct, *, bar=2): 2925 return super().__new__(mcls, name, bases, dct) 2926 class C(metaclass=CM): 2927 def __init__(self, b): 2928 pass 2929 2930 self.assertEqual(self.signature(CMM), 2931 ((('name', ..., ..., "positional_or_keyword"), 2932 ('bases', ..., ..., "positional_or_keyword"), 2933 ('dct', ..., ..., "positional_or_keyword"), 2934 ('foo', 1, ..., "keyword_only")), 2935 ...)) 2936 2937 self.assertEqual(self.signature(CM), 2938 ((('nm', ..., ..., "positional_or_keyword"), 2939 ('bs', ..., ..., "positional_or_keyword"), 2940 ('dt', ..., ..., "positional_or_keyword")), 2941 ...)) 2942 2943 self.assertEqual(self.signature(C), 2944 ((('b', ..., ..., "positional_or_keyword"),), 2945 ...)) 2946 2947 class CM(type): 2948 def __init__(cls, name, bases, dct, *, bar=2): 2949 return super().__init__(name, bases, dct) 2950 class C(metaclass=CM): 2951 def __init__(self, b): 2952 pass 2953 2954 self.assertEqual(self.signature(CM), 2955 ((('name', ..., ..., "positional_or_keyword"), 2956 ('bases', ..., ..., "positional_or_keyword"), 2957 ('dct', ..., ..., "positional_or_keyword"), 2958 ('bar', 2, ..., "keyword_only")), 2959 ...)) 2960 2961 @unittest.skipIf(MISSING_C_DOCSTRINGS, 2962 "Signature information for builtins requires docstrings") 2963 def test_signature_on_class_without_init(self): 2964 # Test classes without user-defined __init__ or __new__ 2965 class C: pass 2966 self.assertEqual(str(inspect.signature(C)), '()') 2967 class D(C): pass 2968 self.assertEqual(str(inspect.signature(D)), '()') 2969 2970 # Test meta-classes without user-defined __init__ or __new__ 2971 class C(type): pass 2972 class D(C): pass 2973 with self.assertRaisesRegex(ValueError, "callable.*is not supported"): 2974 self.assertEqual(inspect.signature(C), None) 2975 with self.assertRaisesRegex(ValueError, "callable.*is not supported"): 2976 self.assertEqual(inspect.signature(D), None) 2977 2978 @unittest.skipIf(MISSING_C_DOCSTRINGS, 2979 "Signature information for builtins requires docstrings") 2980 def test_signature_on_builtin_class(self): 2981 expected = ('(file, protocol=None, fix_imports=True, ' 2982 'buffer_callback=None)') 2983 self.assertEqual(str(inspect.signature(_pickle.Pickler)), expected) 2984 2985 class P(_pickle.Pickler): pass 2986 class EmptyTrait: pass 2987 class P2(EmptyTrait, P): pass 2988 self.assertEqual(str(inspect.signature(P)), expected) 2989 self.assertEqual(str(inspect.signature(P2)), expected) 2990 2991 class P3(P2): 2992 def __init__(self, spam): 2993 pass 2994 self.assertEqual(str(inspect.signature(P3)), '(spam)') 2995 2996 class MetaP(type): 2997 def __call__(cls, foo, bar): 2998 pass 2999 class P4(P2, metaclass=MetaP): 3000 pass 3001 self.assertEqual(str(inspect.signature(P4)), '(foo, bar)') 3002 3003 def test_signature_on_callable_objects(self): 3004 class Foo: 3005 def __call__(self, a): 3006 pass 3007 3008 self.assertEqual(self.signature(Foo()), 3009 ((('a', ..., ..., "positional_or_keyword"),), 3010 ...)) 3011 3012 class Spam: 3013 pass 3014 with self.assertRaisesRegex(TypeError, "is not a callable object"): 3015 inspect.signature(Spam()) 3016 3017 class Bar(Spam, Foo): 3018 pass 3019 3020 self.assertEqual(self.signature(Bar()), 3021 ((('a', ..., ..., "positional_or_keyword"),), 3022 ...)) 3023 3024 class Wrapped: 3025 pass 3026 Wrapped.__wrapped__ = lambda a: None 3027 self.assertEqual(self.signature(Wrapped), 3028 ((('a', ..., ..., "positional_or_keyword"),), 3029 ...)) 3030 # wrapper loop: 3031 Wrapped.__wrapped__ = Wrapped 3032 with self.assertRaisesRegex(ValueError, 'wrapper loop'): 3033 self.signature(Wrapped) 3034 3035 def test_signature_on_lambdas(self): 3036 self.assertEqual(self.signature((lambda a=10: a)), 3037 ((('a', 10, ..., "positional_or_keyword"),), 3038 ...)) 3039 3040 def test_signature_equality(self): 3041 def foo(a, *, b:int) -> float: pass 3042 self.assertFalse(inspect.signature(foo) == 42) 3043 self.assertTrue(inspect.signature(foo) != 42) 3044 self.assertTrue(inspect.signature(foo) == ALWAYS_EQ) 3045 self.assertFalse(inspect.signature(foo) != ALWAYS_EQ) 3046 3047 def bar(a, *, b:int) -> float: pass 3048 self.assertTrue(inspect.signature(foo) == inspect.signature(bar)) 3049 self.assertFalse(inspect.signature(foo) != inspect.signature(bar)) 3050 self.assertEqual( 3051 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3052 3053 def bar(a, *, b:int) -> int: pass 3054 self.assertFalse(inspect.signature(foo) == inspect.signature(bar)) 3055 self.assertTrue(inspect.signature(foo) != inspect.signature(bar)) 3056 self.assertNotEqual( 3057 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3058 3059 def bar(a, *, b:int): pass 3060 self.assertFalse(inspect.signature(foo) == inspect.signature(bar)) 3061 self.assertTrue(inspect.signature(foo) != inspect.signature(bar)) 3062 self.assertNotEqual( 3063 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3064 3065 def bar(a, *, b:int=42) -> float: pass 3066 self.assertFalse(inspect.signature(foo) == inspect.signature(bar)) 3067 self.assertTrue(inspect.signature(foo) != inspect.signature(bar)) 3068 self.assertNotEqual( 3069 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3070 3071 def bar(a, *, c) -> float: pass 3072 self.assertFalse(inspect.signature(foo) == inspect.signature(bar)) 3073 self.assertTrue(inspect.signature(foo) != inspect.signature(bar)) 3074 self.assertNotEqual( 3075 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3076 3077 def bar(a, b:int) -> float: pass 3078 self.assertFalse(inspect.signature(foo) == inspect.signature(bar)) 3079 self.assertTrue(inspect.signature(foo) != inspect.signature(bar)) 3080 self.assertNotEqual( 3081 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3082 def spam(b:int, a) -> float: pass 3083 self.assertFalse(inspect.signature(spam) == inspect.signature(bar)) 3084 self.assertTrue(inspect.signature(spam) != inspect.signature(bar)) 3085 self.assertNotEqual( 3086 hash(inspect.signature(spam)), hash(inspect.signature(bar))) 3087 3088 def foo(*, a, b, c): pass 3089 def bar(*, c, b, a): pass 3090 self.assertTrue(inspect.signature(foo) == inspect.signature(bar)) 3091 self.assertFalse(inspect.signature(foo) != inspect.signature(bar)) 3092 self.assertEqual( 3093 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3094 3095 def foo(*, a=1, b, c): pass 3096 def bar(*, c, b, a=1): pass 3097 self.assertTrue(inspect.signature(foo) == inspect.signature(bar)) 3098 self.assertFalse(inspect.signature(foo) != inspect.signature(bar)) 3099 self.assertEqual( 3100 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3101 3102 def foo(pos, *, a=1, b, c): pass 3103 def bar(pos, *, c, b, a=1): pass 3104 self.assertTrue(inspect.signature(foo) == inspect.signature(bar)) 3105 self.assertFalse(inspect.signature(foo) != inspect.signature(bar)) 3106 self.assertEqual( 3107 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3108 3109 def foo(pos, *, a, b, c): pass 3110 def bar(pos, *, c, b, a=1): pass 3111 self.assertFalse(inspect.signature(foo) == inspect.signature(bar)) 3112 self.assertTrue(inspect.signature(foo) != inspect.signature(bar)) 3113 self.assertNotEqual( 3114 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3115 3116 def foo(pos, *args, a=42, b, c, **kwargs:int): pass 3117 def bar(pos, *args, c, b, a=42, **kwargs:int): pass 3118 self.assertTrue(inspect.signature(foo) == inspect.signature(bar)) 3119 self.assertFalse(inspect.signature(foo) != inspect.signature(bar)) 3120 self.assertEqual( 3121 hash(inspect.signature(foo)), hash(inspect.signature(bar))) 3122 3123 def test_signature_hashable(self): 3124 S = inspect.Signature 3125 P = inspect.Parameter 3126 3127 def foo(a): pass 3128 foo_sig = inspect.signature(foo) 3129 3130 manual_sig = S(parameters=[P('a', P.POSITIONAL_OR_KEYWORD)]) 3131 3132 self.assertEqual(hash(foo_sig), hash(manual_sig)) 3133 self.assertNotEqual(hash(foo_sig), 3134 hash(manual_sig.replace(return_annotation='spam'))) 3135 3136 def bar(a) -> 1: pass 3137 self.assertNotEqual(hash(foo_sig), hash(inspect.signature(bar))) 3138 3139 def foo(a={}): pass 3140 with self.assertRaisesRegex(TypeError, 'unhashable type'): 3141 hash(inspect.signature(foo)) 3142 3143 def foo(a) -> {}: pass 3144 with self.assertRaisesRegex(TypeError, 'unhashable type'): 3145 hash(inspect.signature(foo)) 3146 3147 def test_signature_str(self): 3148 def foo(a:int=1, *, b, c=None, **kwargs) -> 42: 3149 pass 3150 self.assertEqual(str(inspect.signature(foo)), 3151 '(a: int = 1, *, b, c=None, **kwargs) -> 42') 3152 3153 def foo(a:int=1, *args, b, c=None, **kwargs) -> 42: 3154 pass 3155 self.assertEqual(str(inspect.signature(foo)), 3156 '(a: int = 1, *args, b, c=None, **kwargs) -> 42') 3157 3158 def foo(): 3159 pass 3160 self.assertEqual(str(inspect.signature(foo)), '()') 3161 3162 def test_signature_str_positional_only(self): 3163 P = inspect.Parameter 3164 S = inspect.Signature 3165 3166 def test(a_po, *, b, **kwargs): 3167 return a_po, kwargs 3168 3169 sig = inspect.signature(test) 3170 new_params = list(sig.parameters.values()) 3171 new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY) 3172 test.__signature__ = sig.replace(parameters=new_params) 3173 3174 self.assertEqual(str(inspect.signature(test)), 3175 '(a_po, /, *, b, **kwargs)') 3176 3177 self.assertEqual(str(S(parameters=[P('foo', P.POSITIONAL_ONLY)])), 3178 '(foo, /)') 3179 3180 self.assertEqual(str(S(parameters=[ 3181 P('foo', P.POSITIONAL_ONLY), 3182 P('bar', P.VAR_KEYWORD)])), 3183 '(foo, /, **bar)') 3184 3185 self.assertEqual(str(S(parameters=[ 3186 P('foo', P.POSITIONAL_ONLY), 3187 P('bar', P.VAR_POSITIONAL)])), 3188 '(foo, /, *bar)') 3189 3190 def test_signature_replace_anno(self): 3191 def test() -> 42: 3192 pass 3193 3194 sig = inspect.signature(test) 3195 sig = sig.replace(return_annotation=None) 3196 self.assertIs(sig.return_annotation, None) 3197 sig = sig.replace(return_annotation=sig.empty) 3198 self.assertIs(sig.return_annotation, sig.empty) 3199 sig = sig.replace(return_annotation=42) 3200 self.assertEqual(sig.return_annotation, 42) 3201 self.assertEqual(sig, inspect.signature(test)) 3202 3203 def test_signature_on_mangled_parameters(self): 3204 class Spam: 3205 def foo(self, __p1:1=2, *, __p2:2=3): 3206 pass 3207 class Ham(Spam): 3208 pass 3209 3210 self.assertEqual(self.signature(Spam.foo), 3211 ((('self', ..., ..., "positional_or_keyword"), 3212 ('_Spam__p1', 2, 1, "positional_or_keyword"), 3213 ('_Spam__p2', 3, 2, "keyword_only")), 3214 ...)) 3215 3216 self.assertEqual(self.signature(Spam.foo), 3217 self.signature(Ham.foo)) 3218 3219 def test_signature_from_callable_python_obj(self): 3220 class MySignature(inspect.Signature): pass 3221 def foo(a, *, b:1): pass 3222 foo_sig = MySignature.from_callable(foo) 3223 self.assertIsInstance(foo_sig, MySignature) 3224 3225 def test_signature_from_callable_class(self): 3226 # A regression test for a class inheriting its signature from `object`. 3227 class MySignature(inspect.Signature): pass 3228 class foo: pass 3229 foo_sig = MySignature.from_callable(foo) 3230 self.assertIsInstance(foo_sig, MySignature) 3231 3232 @unittest.skipIf(MISSING_C_DOCSTRINGS, 3233 "Signature information for builtins requires docstrings") 3234 def test_signature_from_callable_builtin_obj(self): 3235 class MySignature(inspect.Signature): pass 3236 sig = MySignature.from_callable(_pickle.Pickler) 3237 self.assertIsInstance(sig, MySignature) 3238 3239 def test_signature_definition_order_preserved_on_kwonly(self): 3240 for fn in signatures_with_lexicographic_keyword_only_parameters(): 3241 signature = inspect.signature(fn) 3242 l = list(signature.parameters) 3243 sorted_l = sorted(l) 3244 self.assertTrue(l) 3245 self.assertEqual(l, sorted_l) 3246 signature = inspect.signature(unsorted_keyword_only_parameters_fn) 3247 l = list(signature.parameters) 3248 self.assertEqual(l, unsorted_keyword_only_parameters) 3249 3250 def test_signater_parameters_is_ordered(self): 3251 p1 = inspect.signature(lambda x, y: None).parameters 3252 p2 = inspect.signature(lambda y, x: None).parameters 3253 self.assertNotEqual(p1, p2) 3254 3255 3256class TestParameterObject(unittest.TestCase): 3257 def test_signature_parameter_kinds(self): 3258 P = inspect.Parameter 3259 self.assertTrue(P.POSITIONAL_ONLY < P.POSITIONAL_OR_KEYWORD < \ 3260 P.VAR_POSITIONAL < P.KEYWORD_ONLY < P.VAR_KEYWORD) 3261 3262 self.assertEqual(str(P.POSITIONAL_ONLY), 'POSITIONAL_ONLY') 3263 self.assertTrue('POSITIONAL_ONLY' in repr(P.POSITIONAL_ONLY)) 3264 3265 def test_signature_parameter_object(self): 3266 p = inspect.Parameter('foo', default=10, 3267 kind=inspect.Parameter.POSITIONAL_ONLY) 3268 self.assertEqual(p.name, 'foo') 3269 self.assertEqual(p.default, 10) 3270 self.assertIs(p.annotation, p.empty) 3271 self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) 3272 3273 with self.assertRaisesRegex(ValueError, "value '123' is " 3274 "not a valid Parameter.kind"): 3275 inspect.Parameter('foo', default=10, kind='123') 3276 3277 with self.assertRaisesRegex(ValueError, 'not a valid parameter name'): 3278 inspect.Parameter('1', kind=inspect.Parameter.VAR_KEYWORD) 3279 3280 with self.assertRaisesRegex(TypeError, 'name must be a str'): 3281 inspect.Parameter(None, kind=inspect.Parameter.VAR_KEYWORD) 3282 3283 with self.assertRaisesRegex(ValueError, 3284 'is not a valid parameter name'): 3285 inspect.Parameter('$', kind=inspect.Parameter.VAR_KEYWORD) 3286 3287 with self.assertRaisesRegex(ValueError, 3288 'is not a valid parameter name'): 3289 inspect.Parameter('.a', kind=inspect.Parameter.VAR_KEYWORD) 3290 3291 with self.assertRaisesRegex(ValueError, 'cannot have default values'): 3292 inspect.Parameter('a', default=42, 3293 kind=inspect.Parameter.VAR_KEYWORD) 3294 3295 with self.assertRaisesRegex(ValueError, 'cannot have default values'): 3296 inspect.Parameter('a', default=42, 3297 kind=inspect.Parameter.VAR_POSITIONAL) 3298 3299 p = inspect.Parameter('a', default=42, 3300 kind=inspect.Parameter.POSITIONAL_OR_KEYWORD) 3301 with self.assertRaisesRegex(ValueError, 'cannot have default values'): 3302 p.replace(kind=inspect.Parameter.VAR_POSITIONAL) 3303 3304 self.assertTrue(repr(p).startswith('<Parameter')) 3305 self.assertTrue('"a=42"' in repr(p)) 3306 3307 def test_signature_parameter_hashable(self): 3308 P = inspect.Parameter 3309 foo = P('foo', kind=P.POSITIONAL_ONLY) 3310 self.assertEqual(hash(foo), hash(P('foo', kind=P.POSITIONAL_ONLY))) 3311 self.assertNotEqual(hash(foo), hash(P('foo', kind=P.POSITIONAL_ONLY, 3312 default=42))) 3313 self.assertNotEqual(hash(foo), 3314 hash(foo.replace(kind=P.VAR_POSITIONAL))) 3315 3316 def test_signature_parameter_equality(self): 3317 P = inspect.Parameter 3318 p = P('foo', default=42, kind=inspect.Parameter.KEYWORD_ONLY) 3319 3320 self.assertTrue(p == p) 3321 self.assertFalse(p != p) 3322 self.assertFalse(p == 42) 3323 self.assertTrue(p != 42) 3324 self.assertTrue(p == ALWAYS_EQ) 3325 self.assertFalse(p != ALWAYS_EQ) 3326 3327 self.assertTrue(p == P('foo', default=42, 3328 kind=inspect.Parameter.KEYWORD_ONLY)) 3329 self.assertFalse(p != P('foo', default=42, 3330 kind=inspect.Parameter.KEYWORD_ONLY)) 3331 3332 def test_signature_parameter_replace(self): 3333 p = inspect.Parameter('foo', default=42, 3334 kind=inspect.Parameter.KEYWORD_ONLY) 3335 3336 self.assertIsNot(p, p.replace()) 3337 self.assertEqual(p, p.replace()) 3338 3339 p2 = p.replace(annotation=1) 3340 self.assertEqual(p2.annotation, 1) 3341 p2 = p2.replace(annotation=p2.empty) 3342 self.assertEqual(p, p2) 3343 3344 p2 = p2.replace(name='bar') 3345 self.assertEqual(p2.name, 'bar') 3346 self.assertNotEqual(p2, p) 3347 3348 with self.assertRaisesRegex(ValueError, 3349 'name is a required attribute'): 3350 p2 = p2.replace(name=p2.empty) 3351 3352 p2 = p2.replace(name='foo', default=None) 3353 self.assertIs(p2.default, None) 3354 self.assertNotEqual(p2, p) 3355 3356 p2 = p2.replace(name='foo', default=p2.empty) 3357 self.assertIs(p2.default, p2.empty) 3358 3359 3360 p2 = p2.replace(default=42, kind=p2.POSITIONAL_OR_KEYWORD) 3361 self.assertEqual(p2.kind, p2.POSITIONAL_OR_KEYWORD) 3362 self.assertNotEqual(p2, p) 3363 3364 with self.assertRaisesRegex(ValueError, 3365 "value <class 'inspect._empty'> " 3366 "is not a valid Parameter.kind"): 3367 p2 = p2.replace(kind=p2.empty) 3368 3369 p2 = p2.replace(kind=p2.KEYWORD_ONLY) 3370 self.assertEqual(p2, p) 3371 3372 def test_signature_parameter_positional_only(self): 3373 with self.assertRaisesRegex(TypeError, 'name must be a str'): 3374 inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY) 3375 3376 @cpython_only 3377 def test_signature_parameter_implicit(self): 3378 with self.assertRaisesRegex(ValueError, 3379 'implicit arguments must be passed as ' 3380 'positional or keyword arguments, ' 3381 'not positional-only'): 3382 inspect.Parameter('.0', kind=inspect.Parameter.POSITIONAL_ONLY) 3383 3384 param = inspect.Parameter( 3385 '.0', kind=inspect.Parameter.POSITIONAL_OR_KEYWORD) 3386 self.assertEqual(param.kind, inspect.Parameter.POSITIONAL_ONLY) 3387 self.assertEqual(param.name, 'implicit0') 3388 3389 def test_signature_parameter_immutability(self): 3390 p = inspect.Parameter('spam', kind=inspect.Parameter.KEYWORD_ONLY) 3391 3392 with self.assertRaises(AttributeError): 3393 p.foo = 'bar' 3394 3395 with self.assertRaises(AttributeError): 3396 p.kind = 123 3397 3398 3399class TestSignatureBind(unittest.TestCase): 3400 @staticmethod 3401 def call(func, *args, **kwargs): 3402 sig = inspect.signature(func) 3403 ba = sig.bind(*args, **kwargs) 3404 return func(*ba.args, **ba.kwargs) 3405 3406 def test_signature_bind_empty(self): 3407 def test(): 3408 return 42 3409 3410 self.assertEqual(self.call(test), 42) 3411 with self.assertRaisesRegex(TypeError, 'too many positional arguments'): 3412 self.call(test, 1) 3413 with self.assertRaisesRegex(TypeError, 'too many positional arguments'): 3414 self.call(test, 1, spam=10) 3415 with self.assertRaisesRegex( 3416 TypeError, "got an unexpected keyword argument 'spam'"): 3417 3418 self.call(test, spam=1) 3419 3420 def test_signature_bind_var(self): 3421 def test(*args, **kwargs): 3422 return args, kwargs 3423 3424 self.assertEqual(self.call(test), ((), {})) 3425 self.assertEqual(self.call(test, 1), ((1,), {})) 3426 self.assertEqual(self.call(test, 1, 2), ((1, 2), {})) 3427 self.assertEqual(self.call(test, foo='bar'), ((), {'foo': 'bar'})) 3428 self.assertEqual(self.call(test, 1, foo='bar'), ((1,), {'foo': 'bar'})) 3429 self.assertEqual(self.call(test, args=10), ((), {'args': 10})) 3430 self.assertEqual(self.call(test, 1, 2, foo='bar'), 3431 ((1, 2), {'foo': 'bar'})) 3432 3433 def test_signature_bind_just_args(self): 3434 def test(a, b, c): 3435 return a, b, c 3436 3437 self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) 3438 3439 with self.assertRaisesRegex(TypeError, 'too many positional arguments'): 3440 self.call(test, 1, 2, 3, 4) 3441 3442 with self.assertRaisesRegex(TypeError, 3443 "missing a required argument: 'b'"): 3444 self.call(test, 1) 3445 3446 with self.assertRaisesRegex(TypeError, 3447 "missing a required argument: 'a'"): 3448 self.call(test) 3449 3450 def test(a, b, c=10): 3451 return a, b, c 3452 self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) 3453 self.assertEqual(self.call(test, 1, 2), (1, 2, 10)) 3454 3455 def test(a=1, b=2, c=3): 3456 return a, b, c 3457 self.assertEqual(self.call(test, a=10, c=13), (10, 2, 13)) 3458 self.assertEqual(self.call(test, a=10), (10, 2, 3)) 3459 self.assertEqual(self.call(test, b=10), (1, 10, 3)) 3460 3461 def test_signature_bind_varargs_order(self): 3462 def test(*args): 3463 return args 3464 3465 self.assertEqual(self.call(test), ()) 3466 self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) 3467 3468 def test_signature_bind_args_and_varargs(self): 3469 def test(a, b, c=3, *args): 3470 return a, b, c, args 3471 3472 self.assertEqual(self.call(test, 1, 2, 3, 4, 5), (1, 2, 3, (4, 5))) 3473 self.assertEqual(self.call(test, 1, 2), (1, 2, 3, ())) 3474 self.assertEqual(self.call(test, b=1, a=2), (2, 1, 3, ())) 3475 self.assertEqual(self.call(test, 1, b=2), (1, 2, 3, ())) 3476 3477 with self.assertRaisesRegex(TypeError, 3478 "multiple values for argument 'c'"): 3479 self.call(test, 1, 2, 3, c=4) 3480 3481 def test_signature_bind_just_kwargs(self): 3482 def test(**kwargs): 3483 return kwargs 3484 3485 self.assertEqual(self.call(test), {}) 3486 self.assertEqual(self.call(test, foo='bar', spam='ham'), 3487 {'foo': 'bar', 'spam': 'ham'}) 3488 3489 def test_signature_bind_args_and_kwargs(self): 3490 def test(a, b, c=3, **kwargs): 3491 return a, b, c, kwargs 3492 3493 self.assertEqual(self.call(test, 1, 2), (1, 2, 3, {})) 3494 self.assertEqual(self.call(test, 1, 2, foo='bar', spam='ham'), 3495 (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) 3496 self.assertEqual(self.call(test, b=2, a=1, foo='bar', spam='ham'), 3497 (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) 3498 self.assertEqual(self.call(test, a=1, b=2, foo='bar', spam='ham'), 3499 (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) 3500 self.assertEqual(self.call(test, 1, b=2, foo='bar', spam='ham'), 3501 (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) 3502 self.assertEqual(self.call(test, 1, b=2, c=4, foo='bar', spam='ham'), 3503 (1, 2, 4, {'foo': 'bar', 'spam': 'ham'})) 3504 self.assertEqual(self.call(test, 1, 2, 4, foo='bar'), 3505 (1, 2, 4, {'foo': 'bar'})) 3506 self.assertEqual(self.call(test, c=5, a=4, b=3), 3507 (4, 3, 5, {})) 3508 3509 def test_signature_bind_kwonly(self): 3510 def test(*, foo): 3511 return foo 3512 with self.assertRaisesRegex(TypeError, 3513 'too many positional arguments'): 3514 self.call(test, 1) 3515 self.assertEqual(self.call(test, foo=1), 1) 3516 3517 def test(a, *, foo=1, bar): 3518 return foo 3519 with self.assertRaisesRegex(TypeError, 3520 "missing a required argument: 'bar'"): 3521 self.call(test, 1) 3522 3523 def test(foo, *, bar): 3524 return foo, bar 3525 self.assertEqual(self.call(test, 1, bar=2), (1, 2)) 3526 self.assertEqual(self.call(test, bar=2, foo=1), (1, 2)) 3527 3528 with self.assertRaisesRegex( 3529 TypeError, "got an unexpected keyword argument 'spam'"): 3530 3531 self.call(test, bar=2, foo=1, spam=10) 3532 3533 with self.assertRaisesRegex(TypeError, 3534 'too many positional arguments'): 3535 self.call(test, 1, 2) 3536 3537 with self.assertRaisesRegex(TypeError, 3538 'too many positional arguments'): 3539 self.call(test, 1, 2, bar=2) 3540 3541 with self.assertRaisesRegex( 3542 TypeError, "got an unexpected keyword argument 'spam'"): 3543 3544 self.call(test, 1, bar=2, spam='ham') 3545 3546 with self.assertRaisesRegex(TypeError, 3547 "missing a required argument: 'bar'"): 3548 self.call(test, 1) 3549 3550 def test(foo, *, bar, **bin): 3551 return foo, bar, bin 3552 self.assertEqual(self.call(test, 1, bar=2), (1, 2, {})) 3553 self.assertEqual(self.call(test, foo=1, bar=2), (1, 2, {})) 3554 self.assertEqual(self.call(test, 1, bar=2, spam='ham'), 3555 (1, 2, {'spam': 'ham'})) 3556 self.assertEqual(self.call(test, spam='ham', foo=1, bar=2), 3557 (1, 2, {'spam': 'ham'})) 3558 with self.assertRaisesRegex(TypeError, 3559 "missing a required argument: 'foo'"): 3560 self.call(test, spam='ham', bar=2) 3561 self.assertEqual(self.call(test, 1, bar=2, bin=1, spam=10), 3562 (1, 2, {'bin': 1, 'spam': 10})) 3563 3564 def test_signature_bind_arguments(self): 3565 def test(a, *args, b, z=100, **kwargs): 3566 pass 3567 sig = inspect.signature(test) 3568 ba = sig.bind(10, 20, b=30, c=40, args=50, kwargs=60) 3569 # we won't have 'z' argument in the bound arguments object, as we didn't 3570 # pass it to the 'bind' 3571 self.assertEqual(tuple(ba.arguments.items()), 3572 (('a', 10), ('args', (20,)), ('b', 30), 3573 ('kwargs', {'c': 40, 'args': 50, 'kwargs': 60}))) 3574 self.assertEqual(ba.kwargs, 3575 {'b': 30, 'c': 40, 'args': 50, 'kwargs': 60}) 3576 self.assertEqual(ba.args, (10, 20)) 3577 3578 def test_signature_bind_positional_only(self): 3579 P = inspect.Parameter 3580 3581 def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs): 3582 return a_po, b_po, c_po, foo, bar, kwargs 3583 3584 sig = inspect.signature(test) 3585 new_params = collections.OrderedDict(tuple(sig.parameters.items())) 3586 for name in ('a_po', 'b_po', 'c_po'): 3587 new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY) 3588 new_sig = sig.replace(parameters=new_params.values()) 3589 test.__signature__ = new_sig 3590 3591 self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6), 3592 (1, 2, 4, 5, 6, {})) 3593 3594 self.assertEqual(self.call(test, 1, 2), 3595 (1, 2, 3, 42, 50, {})) 3596 3597 self.assertEqual(self.call(test, 1, 2, foo=4, bar=5), 3598 (1, 2, 3, 4, 5, {})) 3599 3600 with self.assertRaisesRegex(TypeError, "but was passed as a keyword"): 3601 self.call(test, 1, 2, foo=4, bar=5, c_po=10) 3602 3603 with self.assertRaisesRegex(TypeError, "parameter is positional only"): 3604 self.call(test, 1, 2, c_po=4) 3605 3606 with self.assertRaisesRegex(TypeError, "parameter is positional only"): 3607 self.call(test, a_po=1, b_po=2) 3608 3609 def test_signature_bind_with_self_arg(self): 3610 # Issue #17071: one of the parameters is named "self 3611 def test(a, self, b): 3612 pass 3613 sig = inspect.signature(test) 3614 ba = sig.bind(1, 2, 3) 3615 self.assertEqual(ba.args, (1, 2, 3)) 3616 ba = sig.bind(1, self=2, b=3) 3617 self.assertEqual(ba.args, (1, 2, 3)) 3618 3619 def test_signature_bind_vararg_name(self): 3620 def test(a, *args): 3621 return a, args 3622 sig = inspect.signature(test) 3623 3624 with self.assertRaisesRegex( 3625 TypeError, "got an unexpected keyword argument 'args'"): 3626 3627 sig.bind(a=0, args=1) 3628 3629 def test(*args, **kwargs): 3630 return args, kwargs 3631 self.assertEqual(self.call(test, args=1), ((), {'args': 1})) 3632 3633 sig = inspect.signature(test) 3634 ba = sig.bind(args=1) 3635 self.assertEqual(ba.arguments, {'kwargs': {'args': 1}}) 3636 3637 @cpython_only 3638 def test_signature_bind_implicit_arg(self): 3639 # Issue #19611: getcallargs should work with set comprehensions 3640 def make_set(): 3641 return {z * z for z in range(5)} 3642 setcomp_code = make_set.__code__.co_consts[1] 3643 setcomp_func = types.FunctionType(setcomp_code, {}) 3644 3645 iterator = iter(range(5)) 3646 self.assertEqual(self.call(setcomp_func, iterator), {0, 1, 4, 9, 16}) 3647 3648 def test_signature_bind_posonly_kwargs(self): 3649 def foo(bar, /, **kwargs): 3650 return bar, kwargs.get(bar) 3651 3652 sig = inspect.signature(foo) 3653 result = sig.bind("pos-only", bar="keyword") 3654 3655 self.assertEqual(result.kwargs, {"bar": "keyword"}) 3656 self.assertIn(("bar", "pos-only"), result.arguments.items()) 3657 3658 3659class TestBoundArguments(unittest.TestCase): 3660 def test_signature_bound_arguments_unhashable(self): 3661 def foo(a): pass 3662 ba = inspect.signature(foo).bind(1) 3663 3664 with self.assertRaisesRegex(TypeError, 'unhashable type'): 3665 hash(ba) 3666 3667 def test_signature_bound_arguments_equality(self): 3668 def foo(a): pass 3669 ba = inspect.signature(foo).bind(1) 3670 self.assertTrue(ba == ba) 3671 self.assertFalse(ba != ba) 3672 self.assertTrue(ba == ALWAYS_EQ) 3673 self.assertFalse(ba != ALWAYS_EQ) 3674 3675 ba2 = inspect.signature(foo).bind(1) 3676 self.assertTrue(ba == ba2) 3677 self.assertFalse(ba != ba2) 3678 3679 ba3 = inspect.signature(foo).bind(2) 3680 self.assertFalse(ba == ba3) 3681 self.assertTrue(ba != ba3) 3682 ba3.arguments['a'] = 1 3683 self.assertTrue(ba == ba3) 3684 self.assertFalse(ba != ba3) 3685 3686 def bar(b): pass 3687 ba4 = inspect.signature(bar).bind(1) 3688 self.assertFalse(ba == ba4) 3689 self.assertTrue(ba != ba4) 3690 3691 def foo(*, a, b): pass 3692 sig = inspect.signature(foo) 3693 ba1 = sig.bind(a=1, b=2) 3694 ba2 = sig.bind(b=2, a=1) 3695 self.assertTrue(ba1 == ba2) 3696 self.assertFalse(ba1 != ba2) 3697 3698 def test_signature_bound_arguments_pickle(self): 3699 def foo(a, b, *, c:1={}, **kw) -> {42:'ham'}: pass 3700 sig = inspect.signature(foo) 3701 ba = sig.bind(20, 30, z={}) 3702 3703 for ver in range(pickle.HIGHEST_PROTOCOL + 1): 3704 with self.subTest(pickle_ver=ver): 3705 ba_pickled = pickle.loads(pickle.dumps(ba, ver)) 3706 self.assertEqual(ba, ba_pickled) 3707 3708 def test_signature_bound_arguments_repr(self): 3709 def foo(a, b, *, c:1={}, **kw) -> {42:'ham'}: pass 3710 sig = inspect.signature(foo) 3711 ba = sig.bind(20, 30, z={}) 3712 self.assertRegex(repr(ba), r'<BoundArguments \(a=20,.*\}\}\)>') 3713 3714 def test_signature_bound_arguments_apply_defaults(self): 3715 def foo(a, b=1, *args, c:1={}, **kw): pass 3716 sig = inspect.signature(foo) 3717 3718 ba = sig.bind(20) 3719 ba.apply_defaults() 3720 self.assertEqual( 3721 list(ba.arguments.items()), 3722 [('a', 20), ('b', 1), ('args', ()), ('c', {}), ('kw', {})]) 3723 3724 # Make sure that we preserve the order: 3725 # i.e. 'c' should be *before* 'kw'. 3726 ba = sig.bind(10, 20, 30, d=1) 3727 ba.apply_defaults() 3728 self.assertEqual( 3729 list(ba.arguments.items()), 3730 [('a', 10), ('b', 20), ('args', (30,)), ('c', {}), ('kw', {'d':1})]) 3731 3732 # Make sure that BoundArguments produced by bind_partial() 3733 # are supported. 3734 def foo(a, b): pass 3735 sig = inspect.signature(foo) 3736 ba = sig.bind_partial(20) 3737 ba.apply_defaults() 3738 self.assertEqual( 3739 list(ba.arguments.items()), 3740 [('a', 20)]) 3741 3742 # Test no args 3743 def foo(): pass 3744 sig = inspect.signature(foo) 3745 ba = sig.bind() 3746 ba.apply_defaults() 3747 self.assertEqual(list(ba.arguments.items()), []) 3748 3749 # Make sure a no-args binding still acquires proper defaults. 3750 def foo(a='spam'): pass 3751 sig = inspect.signature(foo) 3752 ba = sig.bind() 3753 ba.apply_defaults() 3754 self.assertEqual(list(ba.arguments.items()), [('a', 'spam')]) 3755 3756 def test_signature_bound_arguments_arguments_type(self): 3757 def foo(a): pass 3758 ba = inspect.signature(foo).bind(1) 3759 self.assertIs(type(ba.arguments), dict) 3760 3761class TestSignaturePrivateHelpers(unittest.TestCase): 3762 def test_signature_get_bound_param(self): 3763 getter = inspect._signature_get_bound_param 3764 3765 self.assertEqual(getter('($self)'), 'self') 3766 self.assertEqual(getter('($self, obj)'), 'self') 3767 self.assertEqual(getter('($cls, /, obj)'), 'cls') 3768 3769 def _strip_non_python_syntax(self, input, 3770 clean_signature, self_parameter, last_positional_only): 3771 computed_clean_signature, \ 3772 computed_self_parameter, \ 3773 computed_last_positional_only = \ 3774 inspect._signature_strip_non_python_syntax(input) 3775 self.assertEqual(computed_clean_signature, clean_signature) 3776 self.assertEqual(computed_self_parameter, self_parameter) 3777 self.assertEqual(computed_last_positional_only, last_positional_only) 3778 3779 def test_signature_strip_non_python_syntax(self): 3780 self._strip_non_python_syntax( 3781 "($module, /, path, mode, *, dir_fd=None, " + 3782 "effective_ids=False,\n follow_symlinks=True)", 3783 "(module, path, mode, *, dir_fd=None, " + 3784 "effective_ids=False, follow_symlinks=True)", 3785 0, 3786 0) 3787 3788 self._strip_non_python_syntax( 3789 "($module, word, salt, /)", 3790 "(module, word, salt)", 3791 0, 3792 2) 3793 3794 self._strip_non_python_syntax( 3795 "(x, y=None, z=None, /)", 3796 "(x, y=None, z=None)", 3797 None, 3798 2) 3799 3800 self._strip_non_python_syntax( 3801 "(x, y=None, z=None)", 3802 "(x, y=None, z=None)", 3803 None, 3804 None) 3805 3806 self._strip_non_python_syntax( 3807 "(x,\n y=None,\n z = None )", 3808 "(x, y=None, z=None)", 3809 None, 3810 None) 3811 3812 self._strip_non_python_syntax( 3813 "", 3814 "", 3815 None, 3816 None) 3817 3818 self._strip_non_python_syntax( 3819 None, 3820 None, 3821 None, 3822 None) 3823 3824class TestSignatureDefinitions(unittest.TestCase): 3825 # This test case provides a home for checking that particular APIs 3826 # have signatures available for introspection 3827 3828 @cpython_only 3829 @unittest.skipIf(MISSING_C_DOCSTRINGS, 3830 "Signature information for builtins requires docstrings") 3831 def test_builtins_have_signatures(self): 3832 # This checks all builtin callables in CPython have signatures 3833 # A few have signatures Signature can't yet handle, so we skip those 3834 # since they will have to wait until PEP 457 adds the required 3835 # introspection support to the inspect module 3836 # Some others also haven't been converted yet for various other 3837 # reasons, so we also skip those for the time being, but design 3838 # the test to fail in order to indicate when it needs to be 3839 # updated. 3840 no_signature = set() 3841 # These need PEP 457 groups 3842 needs_groups = {"range", "slice", "dir", "getattr", 3843 "next", "iter", "vars"} 3844 no_signature |= needs_groups 3845 # These need PEP 457 groups or a signature change to accept None 3846 needs_semantic_update = {"round"} 3847 no_signature |= needs_semantic_update 3848 # These need *args support in Argument Clinic 3849 needs_varargs = {"breakpoint", "min", "max", "print", 3850 "__build_class__"} 3851 no_signature |= needs_varargs 3852 # These simply weren't covered in the initial AC conversion 3853 # for builtin callables 3854 not_converted_yet = {"open", "__import__"} 3855 no_signature |= not_converted_yet 3856 # These builtin types are expected to provide introspection info 3857 types_with_signatures = set() 3858 # Check the signatures we expect to be there 3859 ns = vars(builtins) 3860 for name, obj in sorted(ns.items()): 3861 if not callable(obj): 3862 continue 3863 # The builtin types haven't been converted to AC yet 3864 if isinstance(obj, type) and (name not in types_with_signatures): 3865 # Note that this also skips all the exception types 3866 no_signature.add(name) 3867 if (name in no_signature): 3868 # Not yet converted 3869 continue 3870 with self.subTest(builtin=name): 3871 self.assertIsNotNone(inspect.signature(obj)) 3872 # Check callables that haven't been converted don't claim a signature 3873 # This ensures this test will start failing as more signatures are 3874 # added, so the affected items can be moved into the scope of the 3875 # regression test above 3876 for name in no_signature: 3877 with self.subTest(builtin=name): 3878 self.assertIsNone(obj.__text_signature__) 3879 3880 def test_python_function_override_signature(self): 3881 def func(*args, **kwargs): 3882 pass 3883 func.__text_signature__ = '($self, a, b=1, *args, c, d=2, **kwargs)' 3884 sig = inspect.signature(func) 3885 self.assertIsNotNone(sig) 3886 self.assertEqual(str(sig), '(self, /, a, b=1, *args, c, d=2, **kwargs)') 3887 func.__text_signature__ = '($self, a, b=1, /, *args, c, d=2, **kwargs)' 3888 sig = inspect.signature(func) 3889 self.assertEqual(str(sig), '(self, a, b=1, /, *args, c, d=2, **kwargs)') 3890 3891 3892class NTimesUnwrappable: 3893 def __init__(self, n): 3894 self.n = n 3895 self._next = None 3896 3897 @property 3898 def __wrapped__(self): 3899 if self.n <= 0: 3900 raise Exception("Unwrapped too many times") 3901 if self._next is None: 3902 self._next = NTimesUnwrappable(self.n - 1) 3903 return self._next 3904 3905class TestUnwrap(unittest.TestCase): 3906 3907 def test_unwrap_one(self): 3908 def func(a, b): 3909 return a + b 3910 wrapper = functools.lru_cache(maxsize=20)(func) 3911 self.assertIs(inspect.unwrap(wrapper), func) 3912 3913 def test_unwrap_several(self): 3914 def func(a, b): 3915 return a + b 3916 wrapper = func 3917 for __ in range(10): 3918 @functools.wraps(wrapper) 3919 def wrapper(): 3920 pass 3921 self.assertIsNot(wrapper.__wrapped__, func) 3922 self.assertIs(inspect.unwrap(wrapper), func) 3923 3924 def test_stop(self): 3925 def func1(a, b): 3926 return a + b 3927 @functools.wraps(func1) 3928 def func2(): 3929 pass 3930 @functools.wraps(func2) 3931 def wrapper(): 3932 pass 3933 func2.stop_here = 1 3934 unwrapped = inspect.unwrap(wrapper, 3935 stop=(lambda f: hasattr(f, "stop_here"))) 3936 self.assertIs(unwrapped, func2) 3937 3938 def test_cycle(self): 3939 def func1(): pass 3940 func1.__wrapped__ = func1 3941 with self.assertRaisesRegex(ValueError, 'wrapper loop'): 3942 inspect.unwrap(func1) 3943 3944 def func2(): pass 3945 func2.__wrapped__ = func1 3946 func1.__wrapped__ = func2 3947 with self.assertRaisesRegex(ValueError, 'wrapper loop'): 3948 inspect.unwrap(func1) 3949 with self.assertRaisesRegex(ValueError, 'wrapper loop'): 3950 inspect.unwrap(func2) 3951 3952 def test_unhashable(self): 3953 def func(): pass 3954 func.__wrapped__ = None 3955 class C: 3956 __hash__ = None 3957 __wrapped__ = func 3958 self.assertIsNone(inspect.unwrap(C())) 3959 3960 def test_recursion_limit(self): 3961 obj = NTimesUnwrappable(sys.getrecursionlimit() + 1) 3962 with self.assertRaisesRegex(ValueError, 'wrapper loop'): 3963 inspect.unwrap(obj) 3964 3965class TestMain(unittest.TestCase): 3966 def test_only_source(self): 3967 module = importlib.import_module('unittest') 3968 rc, out, err = assert_python_ok('-m', 'inspect', 3969 'unittest') 3970 lines = out.decode().splitlines() 3971 # ignore the final newline 3972 self.assertEqual(lines[:-1], inspect.getsource(module).splitlines()) 3973 self.assertEqual(err, b'') 3974 3975 def test_custom_getattr(self): 3976 def foo(): 3977 pass 3978 foo.__signature__ = 42 3979 with self.assertRaises(TypeError): 3980 inspect.signature(foo) 3981 3982 @unittest.skipIf(ThreadPoolExecutor is None, 3983 'threads required to test __qualname__ for source files') 3984 def test_qualname_source(self): 3985 rc, out, err = assert_python_ok('-m', 'inspect', 3986 'concurrent.futures:ThreadPoolExecutor') 3987 lines = out.decode().splitlines() 3988 # ignore the final newline 3989 self.assertEqual(lines[:-1], 3990 inspect.getsource(ThreadPoolExecutor).splitlines()) 3991 self.assertEqual(err, b'') 3992 3993 def test_builtins(self): 3994 module = importlib.import_module('unittest') 3995 _, out, err = assert_python_failure('-m', 'inspect', 3996 'sys') 3997 lines = err.decode().splitlines() 3998 self.assertEqual(lines, ["Can't get info for builtin modules."]) 3999 4000 def test_details(self): 4001 module = importlib.import_module('unittest') 4002 args = support.optim_args_from_interpreter_flags() 4003 rc, out, err = assert_python_ok(*args, '-m', 'inspect', 4004 'unittest', '--details') 4005 output = out.decode() 4006 # Just a quick sanity check on the output 4007 self.assertIn(module.__name__, output) 4008 self.assertIn(module.__file__, output) 4009 self.assertIn(module.__cached__, output) 4010 self.assertEqual(err, b'') 4011 4012 4013class TestReload(unittest.TestCase): 4014 4015 src_before = textwrap.dedent("""\ 4016def foo(): 4017 print("Bla") 4018 """) 4019 4020 src_after = textwrap.dedent("""\ 4021def foo(): 4022 print("Oh no!") 4023 """) 4024 4025 def assertInspectEqual(self, path, source): 4026 inspected_src = inspect.getsource(source) 4027 with open(path) as src: 4028 self.assertEqual( 4029 src.read().splitlines(True), 4030 inspected_src.splitlines(True) 4031 ) 4032 4033 def test_getsource_reload(self): 4034 # see issue 1218234 4035 with _ready_to_import('reload_bug', self.src_before) as (name, path): 4036 module = importlib.import_module(name) 4037 self.assertInspectEqual(path, module) 4038 with open(path, 'w') as src: 4039 src.write(self.src_after) 4040 self.assertInspectEqual(path, module) 4041 4042 4043def test_main(): 4044 run_unittest( 4045 TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBlockComments, 4046 TestBuggyCases, TestInterpreterStack, TestClassesAndFunctions, TestPredicates, 4047 TestGetcallargsFunctions, TestGetcallargsMethods, 4048 TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState, 4049 TestNoEOL, TestSignatureObject, TestSignatureBind, TestParameterObject, 4050 TestBoundArguments, TestSignaturePrivateHelpers, 4051 TestSignatureDefinitions, TestIsDataDescriptor, 4052 TestGetClosureVars, TestUnwrap, TestMain, TestReload, 4053 TestGetCoroutineState, TestGettingSourceOfToplevelFrames 4054 ) 4055 4056if __name__ == "__main__": 4057 test_main() 4058