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