1# Copyright 2001-2013 Python Software Foundation; All Rights Reserved 2from __future__ import absolute_import, division, print_function 3import collections 4import sys 5 6try: 7 import unittest2 as unittest 8except ImportError: 9 import unittest 10 11import funcsigs as inspect 12 13 14class TestSignatureObject(unittest.TestCase): 15 @staticmethod 16 def signature(func): 17 sig = inspect.signature(func) 18 return (tuple((param.name, 19 (Ellipsis if param.default is param.empty else param.default), 20 (Ellipsis if param.annotation is param.empty 21 else param.annotation), 22 str(param.kind).lower()) 23 for param in sig.parameters.values()), 24 (Ellipsis if sig.return_annotation is sig.empty 25 else sig.return_annotation)) 26 27 def __init__(self, *args, **kwargs): 28 unittest.TestCase.__init__(self, *args, **kwargs) 29 if not hasattr(self, 'assertRaisesRegex'): 30 self.assertRaisesRegex = self.assertRaisesRegexp 31 32 if sys.version_info[0] > 2: 33 exec(""" 34def test_signature_object(self): 35 S = inspect.Signature 36 P = inspect.Parameter 37 38 self.assertEqual(str(S()), '()') 39 40 def test(po, pk, *args, ko, **kwargs): 41 pass 42 sig = inspect.signature(test) 43 po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY) 44 pk = sig.parameters['pk'] 45 args = sig.parameters['args'] 46 ko = sig.parameters['ko'] 47 kwargs = sig.parameters['kwargs'] 48 49 S((po, pk, args, ko, kwargs)) 50 51 with self.assertRaisesRegex(ValueError, 'wrong parameter order'): 52 S((pk, po, args, ko, kwargs)) 53 54 with self.assertRaisesRegex(ValueError, 'wrong parameter order'): 55 S((po, args, pk, ko, kwargs)) 56 57 with self.assertRaisesRegex(ValueError, 'wrong parameter order'): 58 S((args, po, pk, ko, kwargs)) 59 60 with self.assertRaisesRegex(ValueError, 'wrong parameter order'): 61 S((po, pk, args, kwargs, ko)) 62 63 kwargs2 = kwargs.replace(name='args') 64 with self.assertRaisesRegex(ValueError, 'duplicate parameter name'): 65 S((po, pk, args, kwargs2, ko)) 66""") 67 68 def test_signature_immutability(self): 69 def test(a): 70 pass 71 sig = inspect.signature(test) 72 73 with self.assertRaises(AttributeError): 74 sig.foo = 'bar' 75 76 # Python2 does not have MappingProxyType class 77 if sys.version_info[:2] < (3, 3): 78 return 79 80 with self.assertRaises(TypeError): 81 sig.parameters['a'] = None 82 83 def test_signature_on_noarg(self): 84 def test(): 85 pass 86 self.assertEqual(self.signature(test), ((), Ellipsis)) 87 88 if sys.version_info[0] > 2: 89 exec(""" 90def test_signature_on_wargs(self): 91 def test(a, b:'foo') -> 123: 92 pass 93 self.assertEqual(self.signature(test), 94 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), 95 ('b', Ellipsis, 'foo', "positional_or_keyword")), 96 123)) 97""") 98 99 if sys.version_info[0] > 2: 100 exec(""" 101def test_signature_on_wkwonly(self): 102 def test(*, a:float, b:str) -> int: 103 pass 104 self.assertEqual(self.signature(test), 105 ((('a', Ellipsis, float, "keyword_only"), 106 ('b', Ellipsis, str, "keyword_only")), 107 int)) 108""") 109 110 if sys.version_info[0] > 2: 111 exec(""" 112def test_signature_on_complex_args(self): 113 def test(a, b:'foo'=10, *args:'bar', spam:'baz', ham=123, **kwargs:int): 114 pass 115 self.assertEqual(self.signature(test), 116 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), 117 ('b', 10, 'foo', "positional_or_keyword"), 118 ('args', Ellipsis, 'bar', "var_positional"), 119 ('spam', Ellipsis, 'baz', "keyword_only"), 120 ('ham', 123, Ellipsis, "keyword_only"), 121 ('kwargs', Ellipsis, int, "var_keyword")), 122 Ellipsis)) 123""") 124 125 def test_signature_on_builtin_function(self): 126 with self.assertRaisesRegex(ValueError, 'not supported by signature'): 127 inspect.signature(type) 128 with self.assertRaisesRegex(ValueError, 'not supported by signature'): 129 # support for 'wrapper_descriptor' 130 inspect.signature(type.__call__) 131 if hasattr(sys, 'pypy_version_info'): 132 raise ValueError('not supported by signature') 133 with self.assertRaisesRegex(ValueError, 'not supported by signature'): 134 # support for 'method-wrapper' 135 inspect.signature(min.__call__) 136 if hasattr(sys, 'pypy_version_info'): 137 raise ValueError('not supported by signature') 138 with self.assertRaisesRegex(ValueError, 139 'no signature found for builtin function'): 140 # support for 'method-wrapper' 141 inspect.signature(min) 142 143 def test_signature_on_non_function(self): 144 with self.assertRaisesRegex(TypeError, 'is not a callable object'): 145 inspect.signature(42) 146 147 with self.assertRaisesRegex(TypeError, 'is not a Python function'): 148 inspect.Signature.from_function(42) 149 150 if sys.version_info[0] > 2: 151 exec(""" 152def test_signature_on_method(self): 153 class Test: 154 def foo(self, arg1, arg2=1) -> int: 155 pass 156 157 meth = Test().foo 158 159 self.assertEqual(self.signature(meth), 160 ((('arg1', Ellipsis, Ellipsis, "positional_or_keyword"), 161 ('arg2', 1, Ellipsis, "positional_or_keyword")), 162 int)) 163""") 164 165 if sys.version_info[0] > 2: 166 exec(""" 167def test_signature_on_classmethod(self): 168 class Test: 169 @classmethod 170 def foo(cls, arg1, *, arg2=1): 171 pass 172 173 meth = Test().foo 174 self.assertEqual(self.signature(meth), 175 ((('arg1', Ellipsis, Ellipsis, "positional_or_keyword"), 176 ('arg2', 1, Ellipsis, "keyword_only")), 177 Ellipsis)) 178 179 meth = Test.foo 180 self.assertEqual(self.signature(meth), 181 ((('arg1', Ellipsis, Ellipsis, "positional_or_keyword"), 182 ('arg2', 1, Ellipsis, "keyword_only")), 183 Ellipsis)) 184""") 185 186 if sys.version_info[0] > 2: 187 exec(""" 188def test_signature_on_staticmethod(self): 189 class Test: 190 @staticmethod 191 def foo(cls, *, arg): 192 pass 193 194 meth = Test().foo 195 self.assertEqual(self.signature(meth), 196 ((('cls', Ellipsis, Ellipsis, "positional_or_keyword"), 197 ('arg', Ellipsis, Ellipsis, "keyword_only")), 198 Ellipsis)) 199 200 meth = Test.foo 201 self.assertEqual(self.signature(meth), 202 ((('cls', Ellipsis, Ellipsis, "positional_or_keyword"), 203 ('arg', Ellipsis, Ellipsis, "keyword_only")), 204 Ellipsis)) 205""") 206 207 if sys.version_info[0] > 2: 208 exec(""" 209def test_signature_on_partial(self): 210 from functools import partial 211 212 def test(): 213 pass 214 215 self.assertEqual(self.signature(partial(test)), ((), Ellipsis)) 216 217 with self.assertRaisesRegex(ValueError, "has incorrect arguments"): 218 inspect.signature(partial(test, 1)) 219 220 with self.assertRaisesRegex(ValueError, "has incorrect arguments"): 221 inspect.signature(partial(test, a=1)) 222 223 def test(a, b, *, c, d): 224 pass 225 226 self.assertEqual(self.signature(partial(test)), 227 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), 228 ('b', Ellipsis, Ellipsis, "positional_or_keyword"), 229 ('c', Ellipsis, Ellipsis, "keyword_only"), 230 ('d', Ellipsis, Ellipsis, "keyword_only")), 231 Ellipsis)) 232 233 self.assertEqual(self.signature(partial(test, 1)), 234 ((('b', Ellipsis, Ellipsis, "positional_or_keyword"), 235 ('c', Ellipsis, Ellipsis, "keyword_only"), 236 ('d', Ellipsis, Ellipsis, "keyword_only")), 237 Ellipsis)) 238 239 self.assertEqual(self.signature(partial(test, 1, c=2)), 240 ((('b', Ellipsis, Ellipsis, "positional_or_keyword"), 241 ('c', 2, Ellipsis, "keyword_only"), 242 ('d', Ellipsis, Ellipsis, "keyword_only")), 243 Ellipsis)) 244 245 self.assertEqual(self.signature(partial(test, b=1, c=2)), 246 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), 247 ('b', 1, Ellipsis, "positional_or_keyword"), 248 ('c', 2, Ellipsis, "keyword_only"), 249 ('d', Ellipsis, Ellipsis, "keyword_only")), 250 Ellipsis)) 251 252 self.assertEqual(self.signature(partial(test, 0, b=1, c=2)), 253 ((('b', 1, Ellipsis, "positional_or_keyword"), 254 ('c', 2, Ellipsis, "keyword_only"), 255 ('d', Ellipsis, Ellipsis, "keyword_only"),), 256 Ellipsis)) 257 258 def test(a, *args, b, **kwargs): 259 pass 260 261 self.assertEqual(self.signature(partial(test, 1)), 262 ((('args', Ellipsis, Ellipsis, "var_positional"), 263 ('b', Ellipsis, Ellipsis, "keyword_only"), 264 ('kwargs', Ellipsis, Ellipsis, "var_keyword")), 265 Ellipsis)) 266 267 self.assertEqual(self.signature(partial(test, 1, 2, 3)), 268 ((('args', Ellipsis, Ellipsis, "var_positional"), 269 ('b', Ellipsis, Ellipsis, "keyword_only"), 270 ('kwargs', Ellipsis, Ellipsis, "var_keyword")), 271 Ellipsis)) 272 273 274 self.assertEqual(self.signature(partial(test, 1, 2, 3, test=True)), 275 ((('args', Ellipsis, Ellipsis, "var_positional"), 276 ('b', Ellipsis, Ellipsis, "keyword_only"), 277 ('kwargs', Ellipsis, Ellipsis, "var_keyword")), 278 Ellipsis)) 279 280 self.assertEqual(self.signature(partial(test, 1, 2, 3, test=1, b=0)), 281 ((('args', Ellipsis, Ellipsis, "var_positional"), 282 ('b', 0, Ellipsis, "keyword_only"), 283 ('kwargs', Ellipsis, Ellipsis, "var_keyword")), 284 Ellipsis)) 285 286 self.assertEqual(self.signature(partial(test, b=0)), 287 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), 288 ('args', Ellipsis, Ellipsis, "var_positional"), 289 ('b', 0, Ellipsis, "keyword_only"), 290 ('kwargs', Ellipsis, Ellipsis, "var_keyword")), 291 Ellipsis)) 292 293 self.assertEqual(self.signature(partial(test, b=0, test=1)), 294 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), 295 ('args', Ellipsis, Ellipsis, "var_positional"), 296 ('b', 0, Ellipsis, "keyword_only"), 297 ('kwargs', Ellipsis, Ellipsis, "var_keyword")), 298 Ellipsis)) 299 300 def test(a, b, c:int) -> 42: 301 pass 302 303 sig = test.__signature__ = inspect.signature(test) 304 305 self.assertEqual(self.signature(partial(partial(test, 1))), 306 ((('b', Ellipsis, Ellipsis, "positional_or_keyword"), 307 ('c', Ellipsis, int, "positional_or_keyword")), 308 42)) 309 310 self.assertEqual(self.signature(partial(partial(test, 1), 2)), 311 ((('c', Ellipsis, int, "positional_or_keyword"),), 312 42)) 313 314 psig = inspect.signature(partial(partial(test, 1), 2)) 315 316 def foo(a): 317 return a 318 _foo = partial(partial(foo, a=10), a=20) 319 self.assertEqual(self.signature(_foo), 320 ((('a', 20, Ellipsis, "positional_or_keyword"),), 321 Ellipsis)) 322 # check that we don't have any side-effects in signature(), 323 # and the partial object is still functioning 324 self.assertEqual(_foo(), 20) 325 326 def foo(a, b, c): 327 return a, b, c 328 _foo = partial(partial(foo, 1, b=20), b=30) 329 self.assertEqual(self.signature(_foo), 330 ((('b', 30, Ellipsis, "positional_or_keyword"), 331 ('c', Ellipsis, Ellipsis, "positional_or_keyword")), 332 Ellipsis)) 333 self.assertEqual(_foo(c=10), (1, 30, 10)) 334 _foo = partial(_foo, 2) # now 'b' has two values - 335 # positional and keyword 336 with self.assertRaisesRegex(ValueError, "has incorrect arguments"): 337 inspect.signature(_foo) 338 339 def foo(a, b, c, *, d): 340 return a, b, c, d 341 _foo = partial(partial(foo, d=20, c=20), b=10, d=30) 342 self.assertEqual(self.signature(_foo), 343 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), 344 ('b', 10, Ellipsis, "positional_or_keyword"), 345 ('c', 20, Ellipsis, "positional_or_keyword"), 346 ('d', 30, Ellipsis, "keyword_only")), 347 Ellipsis)) 348 ba = inspect.signature(_foo).bind(a=200, b=11) 349 self.assertEqual(_foo(*ba.args, **ba.kwargs), (200, 11, 20, 30)) 350 351 def foo(a=1, b=2, c=3): 352 return a, b, c 353 _foo = partial(foo, a=10, c=13) 354 ba = inspect.signature(_foo).bind(11) 355 self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 2, 13)) 356 ba = inspect.signature(_foo).bind(11, 12) 357 self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 12, 13)) 358 ba = inspect.signature(_foo).bind(11, b=12) 359 self.assertEqual(_foo(*ba.args, **ba.kwargs), (11, 12, 13)) 360 ba = inspect.signature(_foo).bind(b=12) 361 self.assertEqual(_foo(*ba.args, **ba.kwargs), (10, 12, 13)) 362 _foo = partial(_foo, b=10) 363 ba = inspect.signature(_foo).bind(12, 14) 364 self.assertEqual(_foo(*ba.args, **ba.kwargs), (12, 14, 13)) 365""") 366 367 if sys.version_info[0] > 2: 368 exec(""" 369def test_signature_on_decorated(self): 370 import functools 371 372 def decorator(func): 373 @functools.wraps(func) 374 def wrapper(*args, **kwargs) -> int: 375 return func(*args, **kwargs) 376 return wrapper 377 378 class Foo: 379 @decorator 380 def bar(self, a, b): 381 pass 382 383 self.assertEqual(self.signature(Foo.bar), 384 ((('self', Ellipsis, Ellipsis, "positional_or_keyword"), 385 ('a', Ellipsis, Ellipsis, "positional_or_keyword"), 386 ('b', Ellipsis, Ellipsis, "positional_or_keyword")), 387 Ellipsis)) 388 389 self.assertEqual(self.signature(Foo().bar), 390 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), 391 ('b', Ellipsis, Ellipsis, "positional_or_keyword")), 392 Ellipsis)) 393 394 # Test that we handle method wrappers correctly 395 def decorator(func): 396 @functools.wraps(func) 397 def wrapper(*args, **kwargs) -> int: 398 return func(42, *args, **kwargs) 399 sig = inspect.signature(func) 400 new_params = tuple(sig.parameters.values())[1:] 401 wrapper.__signature__ = sig.replace(parameters=new_params) 402 return wrapper 403 404 class Foo: 405 @decorator 406 def __call__(self, a, b): 407 pass 408 409 self.assertEqual(self.signature(Foo.__call__), 410 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"), 411 ('b', Ellipsis, Ellipsis, "positional_or_keyword")), 412 Ellipsis)) 413 414 self.assertEqual(self.signature(Foo().__call__), 415 ((('b', Ellipsis, Ellipsis, "positional_or_keyword"),), 416 Ellipsis)) 417""") 418 419 if sys.version_info[0] > 2: 420 exec(""" 421def test_signature_on_class(self): 422 class C: 423 def __init__(self, a): 424 pass 425 426 self.assertEqual(self.signature(C), 427 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), 428 Ellipsis)) 429 430 class CM(type): 431 def __call__(cls, a): 432 pass 433 class C(metaclass=CM): 434 def __init__(self, b): 435 pass 436 437 self.assertEqual(self.signature(C), 438 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), 439 Ellipsis)) 440 441 class CM(type): 442 def __new__(mcls, name, bases, dct, *, foo=1): 443 return super().__new__(mcls, name, bases, dct) 444 class C(metaclass=CM): 445 def __init__(self, b): 446 pass 447 448 self.assertEqual(self.signature(C), 449 ((('b', Ellipsis, Ellipsis, "positional_or_keyword"),), 450 Ellipsis)) 451 452 self.assertEqual(self.signature(CM), 453 ((('name', Ellipsis, Ellipsis, "positional_or_keyword"), 454 ('bases', Ellipsis, Ellipsis, "positional_or_keyword"), 455 ('dct', Ellipsis, Ellipsis, "positional_or_keyword"), 456 ('foo', 1, Ellipsis, "keyword_only")), 457 Ellipsis)) 458 459 class CMM(type): 460 def __new__(mcls, name, bases, dct, *, foo=1): 461 return super().__new__(mcls, name, bases, dct) 462 def __call__(cls, nm, bs, dt): 463 return type(nm, bs, dt) 464 class CM(type, metaclass=CMM): 465 def __new__(mcls, name, bases, dct, *, bar=2): 466 return super().__new__(mcls, name, bases, dct) 467 class C(metaclass=CM): 468 def __init__(self, b): 469 pass 470 471 self.assertEqual(self.signature(CMM), 472 ((('name', Ellipsis, Ellipsis, "positional_or_keyword"), 473 ('bases', Ellipsis, Ellipsis, "positional_or_keyword"), 474 ('dct', Ellipsis, Ellipsis, "positional_or_keyword"), 475 ('foo', 1, Ellipsis, "keyword_only")), 476 Ellipsis)) 477 478 self.assertEqual(self.signature(CM), 479 ((('nm', Ellipsis, Ellipsis, "positional_or_keyword"), 480 ('bs', Ellipsis, Ellipsis, "positional_or_keyword"), 481 ('dt', Ellipsis, Ellipsis, "positional_or_keyword")), 482 Ellipsis)) 483 484 self.assertEqual(self.signature(C), 485 ((('b', Ellipsis, Ellipsis, "positional_or_keyword"),), 486 Ellipsis)) 487 488 class CM(type): 489 def __init__(cls, name, bases, dct, *, bar=2): 490 return super().__init__(name, bases, dct) 491 class C(metaclass=CM): 492 def __init__(self, b): 493 pass 494 495 self.assertEqual(self.signature(CM), 496 ((('name', Ellipsis, Ellipsis, "positional_or_keyword"), 497 ('bases', Ellipsis, Ellipsis, "positional_or_keyword"), 498 ('dct', Ellipsis, Ellipsis, "positional_or_keyword"), 499 ('bar', 2, Ellipsis, "keyword_only")), 500 Ellipsis)) 501""") 502 503 def test_signature_on_callable_objects(self): 504 class Foo(object): 505 def __call__(self, a): 506 pass 507 508 self.assertEqual(self.signature(Foo()), 509 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), 510 Ellipsis)) 511 512 class Spam(object): 513 pass 514 with self.assertRaisesRegex(TypeError, "is not a callable object"): 515 inspect.signature(Spam()) 516 517 class Bar(Spam, Foo): 518 pass 519 520 self.assertEqual(self.signature(Bar()), 521 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), 522 Ellipsis)) 523 524 class ToFail(object): 525 __call__ = type 526 with self.assertRaisesRegex(ValueError, "not supported by signature"): 527 inspect.signature(ToFail()) 528 529 if sys.version_info[0] < 3: 530 return 531 532 class Wrapped(object): 533 pass 534 Wrapped.__wrapped__ = lambda a: None 535 self.assertEqual(self.signature(Wrapped), 536 ((('a', Ellipsis, Ellipsis, "positional_or_keyword"),), 537 Ellipsis)) 538 539 def test_signature_on_lambdas(self): 540 self.assertEqual(self.signature((lambda a=10: a)), 541 ((('a', 10, Ellipsis, "positional_or_keyword"),), 542 Ellipsis)) 543 544 if sys.version_info[0] > 2: 545 exec(""" 546def test_signature_equality(self): 547 def foo(a, *, b:int) -> float: pass 548 self.assertNotEqual(inspect.signature(foo), 42) 549 550 def bar(a, *, b:int) -> float: pass 551 self.assertEqual(inspect.signature(foo), inspect.signature(bar)) 552 553 def bar(a, *, b:int) -> int: pass 554 self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) 555 556 def bar(a, *, b:int): pass 557 self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) 558 559 def bar(a, *, b:int=42) -> float: pass 560 self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) 561 562 def bar(a, *, c) -> float: pass 563 self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) 564 565 def bar(a, b:int) -> float: pass 566 self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) 567 def spam(b:int, a) -> float: pass 568 self.assertNotEqual(inspect.signature(spam), inspect.signature(bar)) 569 570 def foo(*, a, b, c): pass 571 def bar(*, c, b, a): pass 572 self.assertEqual(inspect.signature(foo), inspect.signature(bar)) 573 574 def foo(*, a=1, b, c): pass 575 def bar(*, c, b, a=1): pass 576 self.assertEqual(inspect.signature(foo), inspect.signature(bar)) 577 578 def foo(pos, *, a=1, b, c): pass 579 def bar(pos, *, c, b, a=1): pass 580 self.assertEqual(inspect.signature(foo), inspect.signature(bar)) 581 582 def foo(pos, *, a, b, c): pass 583 def bar(pos, *, c, b, a=1): pass 584 self.assertNotEqual(inspect.signature(foo), inspect.signature(bar)) 585 586 def foo(pos, *args, a=42, b, c, **kwargs:int): pass 587 def bar(pos, *args, c, b, a=42, **kwargs:int): pass 588 self.assertEqual(inspect.signature(foo), inspect.signature(bar)) 589""") 590 591 def test_signature_unhashable(self): 592 def foo(a): pass 593 sig = inspect.signature(foo) 594 with self.assertRaisesRegex(TypeError, 'unhashable type'): 595 hash(sig) 596 597 598 if sys.version_info[0] > 2: 599 exec(""" 600def test_signature_str(self): 601 def foo(a:int=1, *, b, c=None, **kwargs) -> 42: 602 pass 603 self.assertEqual(str(inspect.signature(foo)), 604 '(a:int=1, *, b, c=None, **kwargs) -> 42') 605 606 def foo(a:int=1, *args, b, c=None, **kwargs) -> 42: 607 pass 608 self.assertEqual(str(inspect.signature(foo)), 609 '(a:int=1, *args, b, c=None, **kwargs) -> 42') 610 611 def foo(): 612 pass 613 self.assertEqual(str(inspect.signature(foo)), '()') 614""") 615 616 if sys.version_info[0] > 2: 617 exec(""" 618def test_signature_str_positional_only(self): 619 P = inspect.Parameter 620 621 def test(a_po, *, b, **kwargs): 622 return a_po, kwargs 623 624 sig = inspect.signature(test) 625 new_params = list(sig.parameters.values()) 626 new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY) 627 test.__signature__ = sig.replace(parameters=new_params) 628 629 self.assertEqual(str(inspect.signature(test)), 630 '(<a_po>, *, b, **kwargs)') 631 632 sig = inspect.signature(test) 633 new_params = list(sig.parameters.values()) 634 new_params[0] = new_params[0].replace(name=None) 635 test.__signature__ = sig.replace(parameters=new_params) 636 self.assertEqual(str(inspect.signature(test)), 637 '(<0>, *, b, **kwargs)') 638""") 639 640 if sys.version_info[0] > 2: 641 exec(""" 642def test_signature_replace_anno(self): 643 def test() -> 42: 644 pass 645 646 sig = inspect.signature(test) 647 sig = sig.replace(return_annotation=None) 648 self.assertIs(sig.return_annotation, None) 649 sig = sig.replace(return_annotation=sig.empty) 650 self.assertIs(sig.return_annotation, sig.empty) 651 sig = sig.replace(return_annotation=42) 652 self.assertEqual(sig.return_annotation, 42) 653 self.assertEqual(sig, inspect.signature(test)) 654""") 655 656 657class TestParameterObject(unittest.TestCase): 658 659 def __init__(self, *args, **kwargs): 660 unittest.TestCase.__init__(self, *args, **kwargs) 661 if not hasattr(self, 'assertRaisesRegex'): 662 self.assertRaisesRegex = self.assertRaisesRegexp 663 664 def test_signature_parameter_kinds(self): 665 P = inspect.Parameter 666 self.assertTrue(P.POSITIONAL_ONLY < P.POSITIONAL_OR_KEYWORD < \ 667 P.VAR_POSITIONAL < P.KEYWORD_ONLY < P.VAR_KEYWORD) 668 669 self.assertEqual(str(P.POSITIONAL_ONLY), 'POSITIONAL_ONLY') 670 self.assertTrue('POSITIONAL_ONLY' in repr(P.POSITIONAL_ONLY)) 671 672 def test_signature_parameter_object(self): 673 p = inspect.Parameter('foo', default=10, 674 kind=inspect.Parameter.POSITIONAL_ONLY) 675 self.assertEqual(p.name, 'foo') 676 self.assertEqual(p.default, 10) 677 self.assertIs(p.annotation, p.empty) 678 self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) 679 680 with self.assertRaisesRegex(ValueError, 'invalid value'): 681 inspect.Parameter('foo', default=10, kind='123') 682 683 with self.assertRaisesRegex(ValueError, 'not a valid parameter name'): 684 inspect.Parameter('1', kind=inspect.Parameter.VAR_KEYWORD) 685 686 with self.assertRaisesRegex(ValueError, 687 'non-positional-only parameter'): 688 inspect.Parameter(None, kind=inspect.Parameter.VAR_KEYWORD) 689 690 with self.assertRaisesRegex(ValueError, 'cannot have default values'): 691 inspect.Parameter('a', default=42, 692 kind=inspect.Parameter.VAR_KEYWORD) 693 694 with self.assertRaisesRegex(ValueError, 'cannot have default values'): 695 inspect.Parameter('a', default=42, 696 kind=inspect.Parameter.VAR_POSITIONAL) 697 698 p = inspect.Parameter('a', default=42, 699 kind=inspect.Parameter.POSITIONAL_OR_KEYWORD) 700 with self.assertRaisesRegex(ValueError, 'cannot have default values'): 701 p.replace(kind=inspect.Parameter.VAR_POSITIONAL) 702 703 self.assertTrue(repr(p).startswith('<Parameter')) 704 705 def test_signature_parameter_equality(self): 706 P = inspect.Parameter 707 p = P('foo', default=42, kind=inspect.Parameter.KEYWORD_ONLY) 708 709 self.assertEqual(p, p) 710 self.assertNotEqual(p, 42) 711 712 self.assertEqual(p, P('foo', default=42, 713 kind=inspect.Parameter.KEYWORD_ONLY)) 714 715 def test_signature_parameter_unhashable(self): 716 p = inspect.Parameter('foo', default=42, 717 kind=inspect.Parameter.KEYWORD_ONLY) 718 719 with self.assertRaisesRegex(TypeError, 'unhashable type'): 720 hash(p) 721 722 def test_signature_parameter_replace(self): 723 p = inspect.Parameter('foo', default=42, 724 kind=inspect.Parameter.KEYWORD_ONLY) 725 726 self.assertIsNot(p, p.replace()) 727 self.assertEqual(p, p.replace()) 728 729 p2 = p.replace(annotation=1) 730 self.assertEqual(p2.annotation, 1) 731 p2 = p2.replace(annotation=p2.empty) 732 self.assertEqual(p, p2) 733 734 p2 = p2.replace(name='bar') 735 self.assertEqual(p2.name, 'bar') 736 self.assertNotEqual(p2, p) 737 738 with self.assertRaisesRegex(ValueError, 'not a valid parameter name'): 739 p2 = p2.replace(name=p2.empty) 740 741 p2 = p2.replace(name='foo', default=None) 742 self.assertIs(p2.default, None) 743 self.assertNotEqual(p2, p) 744 745 p2 = p2.replace(name='foo', default=p2.empty) 746 self.assertIs(p2.default, p2.empty) 747 748 749 p2 = p2.replace(default=42, kind=p2.POSITIONAL_OR_KEYWORD) 750 self.assertEqual(p2.kind, p2.POSITIONAL_OR_KEYWORD) 751 self.assertNotEqual(p2, p) 752 753 with self.assertRaisesRegex(ValueError, 'invalid value for'): 754 p2 = p2.replace(kind=p2.empty) 755 756 p2 = p2.replace(kind=p2.KEYWORD_ONLY) 757 self.assertEqual(p2, p) 758 759 def test_signature_parameter_positional_only(self): 760 p = inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY) 761 self.assertEqual(str(p), '<>') 762 763 p = p.replace(name='1') 764 self.assertEqual(str(p), '<1>') 765 766 def test_signature_parameter_immutability(self): 767 p = inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY) 768 769 with self.assertRaises(AttributeError): 770 p.foo = 'bar' 771 772 with self.assertRaises(AttributeError): 773 p.kind = 123 774 775 776class TestSignatureBind(unittest.TestCase): 777 @staticmethod 778 def call(func, *args, **kwargs): 779 sig = inspect.signature(func) 780 ba = sig.bind(*args, **kwargs) 781 return func(*ba.args, **ba.kwargs) 782 783 def __init__(self, *args, **kwargs): 784 unittest.TestCase.__init__(self, *args, **kwargs) 785 if not hasattr(self, 'assertRaisesRegex'): 786 self.assertRaisesRegex = self.assertRaisesRegexp 787 788 def test_signature_bind_empty(self): 789 def test(): 790 return 42 791 792 self.assertEqual(self.call(test), 42) 793 with self.assertRaisesRegex(TypeError, 'too many positional arguments'): 794 self.call(test, 1) 795 with self.assertRaisesRegex(TypeError, 'too many positional arguments'): 796 self.call(test, 1, spam=10) 797 with self.assertRaisesRegex(TypeError, 'too many keyword arguments'): 798 self.call(test, spam=1) 799 800 def test_signature_bind_var(self): 801 def test(*args, **kwargs): 802 return args, kwargs 803 804 self.assertEqual(self.call(test), ((), {})) 805 self.assertEqual(self.call(test, 1), ((1,), {})) 806 self.assertEqual(self.call(test, 1, 2), ((1, 2), {})) 807 self.assertEqual(self.call(test, foo='bar'), ((), {'foo': 'bar'})) 808 self.assertEqual(self.call(test, 1, foo='bar'), ((1,), {'foo': 'bar'})) 809 self.assertEqual(self.call(test, args=10), ((), {'args': 10})) 810 self.assertEqual(self.call(test, 1, 2, foo='bar'), 811 ((1, 2), {'foo': 'bar'})) 812 813 def test_signature_bind_just_args(self): 814 def test(a, b, c): 815 return a, b, c 816 817 self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) 818 819 with self.assertRaisesRegex(TypeError, 'too many positional arguments'): 820 self.call(test, 1, 2, 3, 4) 821 822 with self.assertRaisesRegex(TypeError, "'b' parameter lacking default"): 823 self.call(test, 1) 824 825 with self.assertRaisesRegex(TypeError, "'a' parameter lacking default"): 826 self.call(test) 827 828 def test(a, b, c=10): 829 return a, b, c 830 self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) 831 self.assertEqual(self.call(test, 1, 2), (1, 2, 10)) 832 833 def test(a=1, b=2, c=3): 834 return a, b, c 835 self.assertEqual(self.call(test, a=10, c=13), (10, 2, 13)) 836 self.assertEqual(self.call(test, a=10), (10, 2, 3)) 837 self.assertEqual(self.call(test, b=10), (1, 10, 3)) 838 839 def test_signature_bind_varargs_order(self): 840 def test(*args): 841 return args 842 843 self.assertEqual(self.call(test), ()) 844 self.assertEqual(self.call(test, 1, 2, 3), (1, 2, 3)) 845 846 def test_signature_bind_args_and_varargs(self): 847 def test(a, b, c=3, *args): 848 return a, b, c, args 849 850 self.assertEqual(self.call(test, 1, 2, 3, 4, 5), (1, 2, 3, (4, 5))) 851 self.assertEqual(self.call(test, 1, 2), (1, 2, 3, ())) 852 self.assertEqual(self.call(test, b=1, a=2), (2, 1, 3, ())) 853 self.assertEqual(self.call(test, 1, b=2), (1, 2, 3, ())) 854 855 with self.assertRaisesRegex(TypeError, 856 "multiple values for argument 'c'"): 857 self.call(test, 1, 2, 3, c=4) 858 859 def test_signature_bind_just_kwargs(self): 860 def test(**kwargs): 861 return kwargs 862 863 self.assertEqual(self.call(test), {}) 864 self.assertEqual(self.call(test, foo='bar', spam='ham'), 865 {'foo': 'bar', 'spam': 'ham'}) 866 867 def test_signature_bind_args_and_kwargs(self): 868 def test(a, b, c=3, **kwargs): 869 return a, b, c, kwargs 870 871 self.assertEqual(self.call(test, 1, 2), (1, 2, 3, {})) 872 self.assertEqual(self.call(test, 1, 2, foo='bar', spam='ham'), 873 (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) 874 self.assertEqual(self.call(test, b=2, a=1, foo='bar', spam='ham'), 875 (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) 876 self.assertEqual(self.call(test, a=1, b=2, foo='bar', spam='ham'), 877 (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) 878 self.assertEqual(self.call(test, 1, b=2, foo='bar', spam='ham'), 879 (1, 2, 3, {'foo': 'bar', 'spam': 'ham'})) 880 self.assertEqual(self.call(test, 1, b=2, c=4, foo='bar', spam='ham'), 881 (1, 2, 4, {'foo': 'bar', 'spam': 'ham'})) 882 self.assertEqual(self.call(test, 1, 2, 4, foo='bar'), 883 (1, 2, 4, {'foo': 'bar'})) 884 self.assertEqual(self.call(test, c=5, a=4, b=3), 885 (4, 3, 5, {})) 886 887 if sys.version_info[0] > 2: 888 exec(""" 889def test_signature_bind_kwonly(self): 890 def test(*, foo): 891 return foo 892 with self.assertRaisesRegex(TypeError, 893 'too many positional arguments'): 894 self.call(test, 1) 895 self.assertEqual(self.call(test, foo=1), 1) 896 897 def test(a, *, foo=1, bar): 898 return foo 899 with self.assertRaisesRegex(TypeError, 900 "'bar' parameter lacking default value"): 901 self.call(test, 1) 902 903 def test(foo, *, bar): 904 return foo, bar 905 self.assertEqual(self.call(test, 1, bar=2), (1, 2)) 906 self.assertEqual(self.call(test, bar=2, foo=1), (1, 2)) 907 908 with self.assertRaisesRegex(TypeError, 909 'too many keyword arguments'): 910 self.call(test, bar=2, foo=1, spam=10) 911 912 with self.assertRaisesRegex(TypeError, 913 'too many positional arguments'): 914 self.call(test, 1, 2) 915 916 with self.assertRaisesRegex(TypeError, 917 'too many positional arguments'): 918 self.call(test, 1, 2, bar=2) 919 920 with self.assertRaisesRegex(TypeError, 921 'too many keyword arguments'): 922 self.call(test, 1, bar=2, spam='ham') 923 924 with self.assertRaisesRegex(TypeError, 925 "'bar' parameter lacking default value"): 926 self.call(test, 1) 927 928 def test(foo, *, bar, **bin): 929 return foo, bar, bin 930 self.assertEqual(self.call(test, 1, bar=2), (1, 2, {})) 931 self.assertEqual(self.call(test, foo=1, bar=2), (1, 2, {})) 932 self.assertEqual(self.call(test, 1, bar=2, spam='ham'), 933 (1, 2, {'spam': 'ham'})) 934 self.assertEqual(self.call(test, spam='ham', foo=1, bar=2), 935 (1, 2, {'spam': 'ham'})) 936 with self.assertRaisesRegex(TypeError, 937 "'foo' parameter lacking default value"): 938 self.call(test, spam='ham', bar=2) 939 self.assertEqual(self.call(test, 1, bar=2, bin=1, spam=10), 940 (1, 2, {'bin': 1, 'spam': 10})) 941""") 942# 943 if sys.version_info[0] > 2: 944 exec(""" 945def test_signature_bind_arguments(self): 946 def test(a, *args, b, z=100, **kwargs): 947 pass 948 sig = inspect.signature(test) 949 ba = sig.bind(10, 20, b=30, c=40, args=50, kwargs=60) 950 # we won't have 'z' argument in the bound arguments object, as we didn't 951 # pass it to the 'bind' 952 self.assertEqual(tuple(ba.arguments.items()), 953 (('a', 10), ('args', (20,)), ('b', 30), 954 ('kwargs', {'c': 40, 'args': 50, 'kwargs': 60}))) 955 self.assertEqual(ba.kwargs, 956 {'b': 30, 'c': 40, 'args': 50, 'kwargs': 60}) 957 self.assertEqual(ba.args, (10, 20)) 958""") 959# 960 if sys.version_info[0] > 2: 961 exec(""" 962def test_signature_bind_positional_only(self): 963 P = inspect.Parameter 964 965 def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs): 966 return a_po, b_po, c_po, foo, bar, kwargs 967 968 sig = inspect.signature(test) 969 new_params = collections.OrderedDict(tuple(sig.parameters.items())) 970 for name in ('a_po', 'b_po', 'c_po'): 971 new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY) 972 new_sig = sig.replace(parameters=new_params.values()) 973 test.__signature__ = new_sig 974 975 self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6), 976 (1, 2, 4, 5, 6, {})) 977 978 with self.assertRaisesRegex(TypeError, "parameter is positional only"): 979 self.call(test, 1, 2, c_po=4) 980 981 with self.assertRaisesRegex(TypeError, "parameter is positional only"): 982 self.call(test, a_po=1, b_po=2) 983""") 984 985 986class TestBoundArguments(unittest.TestCase): 987 988 def __init__(self, *args, **kwargs): 989 unittest.TestCase.__init__(self, *args, **kwargs) 990 if not hasattr(self, 'assertRaisesRegex'): 991 self.assertRaisesRegex = self.assertRaisesRegexp 992 993 def test_signature_bound_arguments_unhashable(self): 994 def foo(a): pass 995 ba = inspect.signature(foo).bind(1) 996 997 with self.assertRaisesRegex(TypeError, 'unhashable type'): 998 hash(ba) 999 1000 def test_signature_bound_arguments_equality(self): 1001 def foo(a): pass 1002 ba = inspect.signature(foo).bind(1) 1003 self.assertEqual(ba, ba) 1004 1005 ba2 = inspect.signature(foo).bind(1) 1006 self.assertEqual(ba, ba2) 1007 1008 ba3 = inspect.signature(foo).bind(2) 1009 self.assertNotEqual(ba, ba3) 1010 ba3.arguments['a'] = 1 1011 self.assertEqual(ba, ba3) 1012 1013 def bar(b): pass 1014 ba4 = inspect.signature(bar).bind(1) 1015 self.assertNotEqual(ba, ba4) 1016 1017 1018if __name__ == "__main__": 1019 unittest.begin() 1020