1# Copyright 2007 Google, Inc. All Rights Reserved. 2# Licensed to PSF under a Contributor Agreement. 3 4# Note: each test is run with Python and C versions of ABCMeta. Except for 5# test_ABC_helper(), which assures that abc.ABC is an instance of abc.ABCMeta. 6 7"""Unit tests for abc.py.""" 8 9import unittest 10 11import abc 12import _py_abc 13from inspect import isabstract 14 15def test_factory(abc_ABCMeta, abc_get_cache_token): 16 class TestLegacyAPI(unittest.TestCase): 17 18 def test_abstractproperty_basics(self): 19 @abc.abstractproperty 20 def foo(self): pass 21 self.assertTrue(foo.__isabstractmethod__) 22 def bar(self): pass 23 self.assertFalse(hasattr(bar, "__isabstractmethod__")) 24 25 class C(metaclass=abc_ABCMeta): 26 @abc.abstractproperty 27 def foo(self): return 3 28 self.assertRaises(TypeError, C) 29 class D(C): 30 @property 31 def foo(self): return super().foo 32 self.assertEqual(D().foo, 3) 33 self.assertFalse(getattr(D.foo, "__isabstractmethod__", False)) 34 35 def test_abstractclassmethod_basics(self): 36 @abc.abstractclassmethod 37 def foo(cls): pass 38 self.assertTrue(foo.__isabstractmethod__) 39 @classmethod 40 def bar(cls): pass 41 self.assertFalse(getattr(bar, "__isabstractmethod__", False)) 42 43 class C(metaclass=abc_ABCMeta): 44 @abc.abstractclassmethod 45 def foo(cls): return cls.__name__ 46 self.assertRaises(TypeError, C) 47 class D(C): 48 @classmethod 49 def foo(cls): return super().foo() 50 self.assertEqual(D.foo(), 'D') 51 self.assertEqual(D().foo(), 'D') 52 53 def test_abstractstaticmethod_basics(self): 54 @abc.abstractstaticmethod 55 def foo(): pass 56 self.assertTrue(foo.__isabstractmethod__) 57 @staticmethod 58 def bar(): pass 59 self.assertFalse(getattr(bar, "__isabstractmethod__", False)) 60 61 class C(metaclass=abc_ABCMeta): 62 @abc.abstractstaticmethod 63 def foo(): return 3 64 self.assertRaises(TypeError, C) 65 class D(C): 66 @staticmethod 67 def foo(): return 4 68 self.assertEqual(D.foo(), 4) 69 self.assertEqual(D().foo(), 4) 70 71 72 class TestABC(unittest.TestCase): 73 74 def test_ABC_helper(self): 75 # create an ABC using the helper class and perform basic checks 76 class C(abc.ABC): 77 @classmethod 78 @abc.abstractmethod 79 def foo(cls): return cls.__name__ 80 self.assertEqual(type(C), abc.ABCMeta) 81 self.assertRaises(TypeError, C) 82 class D(C): 83 @classmethod 84 def foo(cls): return super().foo() 85 self.assertEqual(D.foo(), 'D') 86 87 def test_abstractmethod_basics(self): 88 @abc.abstractmethod 89 def foo(self): pass 90 self.assertTrue(foo.__isabstractmethod__) 91 def bar(self): pass 92 self.assertFalse(hasattr(bar, "__isabstractmethod__")) 93 94 def test_abstractproperty_basics(self): 95 @property 96 @abc.abstractmethod 97 def foo(self): pass 98 self.assertTrue(foo.__isabstractmethod__) 99 def bar(self): pass 100 self.assertFalse(getattr(bar, "__isabstractmethod__", False)) 101 102 class C(metaclass=abc_ABCMeta): 103 @property 104 @abc.abstractmethod 105 def foo(self): return 3 106 self.assertRaises(TypeError, C) 107 class D(C): 108 @C.foo.getter 109 def foo(self): return super().foo 110 self.assertEqual(D().foo, 3) 111 112 def test_abstractclassmethod_basics(self): 113 @classmethod 114 @abc.abstractmethod 115 def foo(cls): pass 116 self.assertTrue(foo.__isabstractmethod__) 117 @classmethod 118 def bar(cls): pass 119 self.assertFalse(getattr(bar, "__isabstractmethod__", False)) 120 121 class C(metaclass=abc_ABCMeta): 122 @classmethod 123 @abc.abstractmethod 124 def foo(cls): return cls.__name__ 125 self.assertRaises(TypeError, C) 126 class D(C): 127 @classmethod 128 def foo(cls): return super().foo() 129 self.assertEqual(D.foo(), 'D') 130 self.assertEqual(D().foo(), 'D') 131 132 def test_abstractstaticmethod_basics(self): 133 @staticmethod 134 @abc.abstractmethod 135 def foo(): pass 136 self.assertTrue(foo.__isabstractmethod__) 137 @staticmethod 138 def bar(): pass 139 self.assertFalse(getattr(bar, "__isabstractmethod__", False)) 140 141 class C(metaclass=abc_ABCMeta): 142 @staticmethod 143 @abc.abstractmethod 144 def foo(): return 3 145 self.assertRaises(TypeError, C) 146 class D(C): 147 @staticmethod 148 def foo(): return 4 149 self.assertEqual(D.foo(), 4) 150 self.assertEqual(D().foo(), 4) 151 152 def test_object_new_with_one_abstractmethod(self): 153 class C(metaclass=abc_ABCMeta): 154 @abc.abstractmethod 155 def method_one(self): 156 pass 157 msg = r"class C with abstract method method_one" 158 self.assertRaisesRegex(TypeError, msg, C) 159 160 def test_object_new_with_many_abstractmethods(self): 161 class C(metaclass=abc_ABCMeta): 162 @abc.abstractmethod 163 def method_one(self): 164 pass 165 @abc.abstractmethod 166 def method_two(self): 167 pass 168 msg = r"class C with abstract methods method_one, method_two" 169 self.assertRaisesRegex(TypeError, msg, C) 170 171 def test_abstractmethod_integration(self): 172 for abstractthing in [abc.abstractmethod, abc.abstractproperty, 173 abc.abstractclassmethod, 174 abc.abstractstaticmethod]: 175 class C(metaclass=abc_ABCMeta): 176 @abstractthing 177 def foo(self): pass # abstract 178 def bar(self): pass # concrete 179 self.assertEqual(C.__abstractmethods__, {"foo"}) 180 self.assertRaises(TypeError, C) # because foo is abstract 181 self.assertTrue(isabstract(C)) 182 class D(C): 183 def bar(self): pass # concrete override of concrete 184 self.assertEqual(D.__abstractmethods__, {"foo"}) 185 self.assertRaises(TypeError, D) # because foo is still abstract 186 self.assertTrue(isabstract(D)) 187 class E(D): 188 def foo(self): pass 189 self.assertEqual(E.__abstractmethods__, set()) 190 E() # now foo is concrete, too 191 self.assertFalse(isabstract(E)) 192 class F(E): 193 @abstractthing 194 def bar(self): pass # abstract override of concrete 195 self.assertEqual(F.__abstractmethods__, {"bar"}) 196 self.assertRaises(TypeError, F) # because bar is abstract now 197 self.assertTrue(isabstract(F)) 198 199 def test_descriptors_with_abstractmethod(self): 200 class C(metaclass=abc_ABCMeta): 201 @property 202 @abc.abstractmethod 203 def foo(self): return 3 204 @foo.setter 205 @abc.abstractmethod 206 def foo(self, val): pass 207 self.assertRaises(TypeError, C) 208 class D(C): 209 @C.foo.getter 210 def foo(self): return super().foo 211 self.assertRaises(TypeError, D) 212 class E(D): 213 @D.foo.setter 214 def foo(self, val): pass 215 self.assertEqual(E().foo, 3) 216 # check that the property's __isabstractmethod__ descriptor does the 217 # right thing when presented with a value that fails truth testing: 218 class NotBool(object): 219 def __bool__(self): 220 raise ValueError() 221 __len__ = __bool__ 222 with self.assertRaises(ValueError): 223 class F(C): 224 def bar(self): 225 pass 226 bar.__isabstractmethod__ = NotBool() 227 foo = property(bar) 228 229 230 def test_customdescriptors_with_abstractmethod(self): 231 class Descriptor: 232 def __init__(self, fget, fset=None): 233 self._fget = fget 234 self._fset = fset 235 def getter(self, callable): 236 return Descriptor(callable, self._fget) 237 def setter(self, callable): 238 return Descriptor(self._fget, callable) 239 @property 240 def __isabstractmethod__(self): 241 return (getattr(self._fget, '__isabstractmethod__', False) 242 or getattr(self._fset, '__isabstractmethod__', False)) 243 class C(metaclass=abc_ABCMeta): 244 @Descriptor 245 @abc.abstractmethod 246 def foo(self): return 3 247 @foo.setter 248 @abc.abstractmethod 249 def foo(self, val): pass 250 self.assertRaises(TypeError, C) 251 class D(C): 252 @C.foo.getter 253 def foo(self): return super().foo 254 self.assertRaises(TypeError, D) 255 class E(D): 256 @D.foo.setter 257 def foo(self, val): pass 258 self.assertFalse(E.foo.__isabstractmethod__) 259 260 def test_metaclass_abc(self): 261 # Metaclasses can be ABCs, too. 262 class A(metaclass=abc_ABCMeta): 263 @abc.abstractmethod 264 def x(self): 265 pass 266 self.assertEqual(A.__abstractmethods__, {"x"}) 267 class meta(type, A): 268 def x(self): 269 return 1 270 class C(metaclass=meta): 271 pass 272 273 def test_registration_basics(self): 274 class A(metaclass=abc_ABCMeta): 275 pass 276 class B(object): 277 pass 278 b = B() 279 self.assertFalse(issubclass(B, A)) 280 self.assertFalse(issubclass(B, (A,))) 281 self.assertNotIsInstance(b, A) 282 self.assertNotIsInstance(b, (A,)) 283 B1 = A.register(B) 284 self.assertTrue(issubclass(B, A)) 285 self.assertTrue(issubclass(B, (A,))) 286 self.assertIsInstance(b, A) 287 self.assertIsInstance(b, (A,)) 288 self.assertIs(B1, B) 289 class C(B): 290 pass 291 c = C() 292 self.assertTrue(issubclass(C, A)) 293 self.assertTrue(issubclass(C, (A,))) 294 self.assertIsInstance(c, A) 295 self.assertIsInstance(c, (A,)) 296 297 def test_register_as_class_deco(self): 298 class A(metaclass=abc_ABCMeta): 299 pass 300 @A.register 301 class B(object): 302 pass 303 b = B() 304 self.assertTrue(issubclass(B, A)) 305 self.assertTrue(issubclass(B, (A,))) 306 self.assertIsInstance(b, A) 307 self.assertIsInstance(b, (A,)) 308 @A.register 309 class C(B): 310 pass 311 c = C() 312 self.assertTrue(issubclass(C, A)) 313 self.assertTrue(issubclass(C, (A,))) 314 self.assertIsInstance(c, A) 315 self.assertIsInstance(c, (A,)) 316 self.assertIs(C, A.register(C)) 317 318 def test_isinstance_invalidation(self): 319 class A(metaclass=abc_ABCMeta): 320 pass 321 class B: 322 pass 323 b = B() 324 self.assertFalse(isinstance(b, A)) 325 self.assertFalse(isinstance(b, (A,))) 326 token_old = abc_get_cache_token() 327 A.register(B) 328 token_new = abc_get_cache_token() 329 self.assertGreater(token_new, token_old) 330 self.assertTrue(isinstance(b, A)) 331 self.assertTrue(isinstance(b, (A,))) 332 333 def test_registration_builtins(self): 334 class A(metaclass=abc_ABCMeta): 335 pass 336 A.register(int) 337 self.assertIsInstance(42, A) 338 self.assertIsInstance(42, (A,)) 339 self.assertTrue(issubclass(int, A)) 340 self.assertTrue(issubclass(int, (A,))) 341 class B(A): 342 pass 343 B.register(str) 344 class C(str): pass 345 self.assertIsInstance("", A) 346 self.assertIsInstance("", (A,)) 347 self.assertTrue(issubclass(str, A)) 348 self.assertTrue(issubclass(str, (A,))) 349 self.assertTrue(issubclass(C, A)) 350 self.assertTrue(issubclass(C, (A,))) 351 352 def test_registration_edge_cases(self): 353 class A(metaclass=abc_ABCMeta): 354 pass 355 A.register(A) # should pass silently 356 class A1(A): 357 pass 358 self.assertRaises(RuntimeError, A1.register, A) # cycles not allowed 359 class B(object): 360 pass 361 A1.register(B) # ok 362 A1.register(B) # should pass silently 363 class C(A): 364 pass 365 A.register(C) # should pass silently 366 self.assertRaises(RuntimeError, C.register, A) # cycles not allowed 367 C.register(B) # ok 368 369 def test_register_non_class(self): 370 class A(metaclass=abc_ABCMeta): 371 pass 372 self.assertRaisesRegex(TypeError, "Can only register classes", 373 A.register, 4) 374 375 def test_registration_transitiveness(self): 376 class A(metaclass=abc_ABCMeta): 377 pass 378 self.assertTrue(issubclass(A, A)) 379 self.assertTrue(issubclass(A, (A,))) 380 class B(metaclass=abc_ABCMeta): 381 pass 382 self.assertFalse(issubclass(A, B)) 383 self.assertFalse(issubclass(A, (B,))) 384 self.assertFalse(issubclass(B, A)) 385 self.assertFalse(issubclass(B, (A,))) 386 class C(metaclass=abc_ABCMeta): 387 pass 388 A.register(B) 389 class B1(B): 390 pass 391 self.assertTrue(issubclass(B1, A)) 392 self.assertTrue(issubclass(B1, (A,))) 393 class C1(C): 394 pass 395 B1.register(C1) 396 self.assertFalse(issubclass(C, B)) 397 self.assertFalse(issubclass(C, (B,))) 398 self.assertFalse(issubclass(C, B1)) 399 self.assertFalse(issubclass(C, (B1,))) 400 self.assertTrue(issubclass(C1, A)) 401 self.assertTrue(issubclass(C1, (A,))) 402 self.assertTrue(issubclass(C1, B)) 403 self.assertTrue(issubclass(C1, (B,))) 404 self.assertTrue(issubclass(C1, B1)) 405 self.assertTrue(issubclass(C1, (B1,))) 406 C1.register(int) 407 class MyInt(int): 408 pass 409 self.assertTrue(issubclass(MyInt, A)) 410 self.assertTrue(issubclass(MyInt, (A,))) 411 self.assertIsInstance(42, A) 412 self.assertIsInstance(42, (A,)) 413 414 def test_issubclass_bad_arguments(self): 415 class A(metaclass=abc_ABCMeta): 416 pass 417 418 with self.assertRaises(TypeError): 419 issubclass({}, A) # unhashable 420 421 with self.assertRaises(TypeError): 422 issubclass(42, A) # No __mro__ 423 424 # Python version supports any iterable as __mro__. 425 # But it's implementation detail and don't emulate it in C version. 426 class C: 427 __mro__ = 42 # __mro__ is not tuple 428 429 with self.assertRaises(TypeError): 430 issubclass(C(), A) 431 432 # bpo-34441: Check that issubclass() doesn't crash on bogus 433 # classes. 434 bogus_subclasses = [ 435 None, 436 lambda x: [], 437 lambda: 42, 438 lambda: [42], 439 ] 440 441 for i, func in enumerate(bogus_subclasses): 442 class S(metaclass=abc_ABCMeta): 443 __subclasses__ = func 444 445 with self.subTest(i=i): 446 with self.assertRaises(TypeError): 447 issubclass(int, S) 448 449 # Also check that issubclass() propagates exceptions raised by 450 # __subclasses__. 451 exc_msg = "exception from __subclasses__" 452 453 def raise_exc(): 454 raise Exception(exc_msg) 455 456 class S(metaclass=abc_ABCMeta): 457 __subclasses__ = raise_exc 458 459 with self.assertRaisesRegex(Exception, exc_msg): 460 issubclass(int, S) 461 462 def test_subclasshook(self): 463 class A(metaclass=abc.ABCMeta): 464 @classmethod 465 def __subclasshook__(cls, C): 466 if cls is A: 467 return 'foo' in C.__dict__ 468 return NotImplemented 469 self.assertFalse(issubclass(A, A)) 470 self.assertFalse(issubclass(A, (A,))) 471 class B: 472 foo = 42 473 self.assertTrue(issubclass(B, A)) 474 self.assertTrue(issubclass(B, (A,))) 475 class C: 476 spam = 42 477 self.assertFalse(issubclass(C, A)) 478 self.assertFalse(issubclass(C, (A,))) 479 480 def test_all_new_methods_are_called(self): 481 class A(metaclass=abc_ABCMeta): 482 pass 483 class B(object): 484 counter = 0 485 def __new__(cls): 486 B.counter += 1 487 return super().__new__(cls) 488 class C(A, B): 489 pass 490 self.assertEqual(B.counter, 0) 491 C() 492 self.assertEqual(B.counter, 1) 493 494 def test_ABC_has___slots__(self): 495 self.assertTrue(hasattr(abc.ABC, '__slots__')) 496 497 def test_tricky_new_works(self): 498 def with_metaclass(meta, *bases): 499 class metaclass(type): 500 def __new__(cls, name, this_bases, d): 501 return meta(name, bases, d) 502 return type.__new__(metaclass, 'temporary_class', (), {}) 503 class A: ... 504 class B: ... 505 class C(with_metaclass(abc_ABCMeta, A, B)): 506 pass 507 self.assertEqual(C.__class__, abc_ABCMeta) 508 509 def test_update_del(self): 510 class A(metaclass=abc_ABCMeta): 511 @abc.abstractmethod 512 def foo(self): 513 pass 514 515 del A.foo 516 self.assertEqual(A.__abstractmethods__, {'foo'}) 517 self.assertFalse(hasattr(A, 'foo')) 518 519 abc.update_abstractmethods(A) 520 521 self.assertEqual(A.__abstractmethods__, set()) 522 A() 523 524 525 def test_update_new_abstractmethods(self): 526 class A(metaclass=abc_ABCMeta): 527 @abc.abstractmethod 528 def bar(self): 529 pass 530 531 @abc.abstractmethod 532 def updated_foo(self): 533 pass 534 535 A.foo = updated_foo 536 abc.update_abstractmethods(A) 537 self.assertEqual(A.__abstractmethods__, {'foo', 'bar'}) 538 msg = "class A with abstract methods bar, foo" 539 self.assertRaisesRegex(TypeError, msg, A) 540 541 def test_update_implementation(self): 542 class A(metaclass=abc_ABCMeta): 543 @abc.abstractmethod 544 def foo(self): 545 pass 546 547 class B(A): 548 pass 549 550 msg = "class B with abstract method foo" 551 self.assertRaisesRegex(TypeError, msg, B) 552 self.assertEqual(B.__abstractmethods__, {'foo'}) 553 554 B.foo = lambda self: None 555 556 abc.update_abstractmethods(B) 557 558 B() 559 self.assertEqual(B.__abstractmethods__, set()) 560 561 def test_update_as_decorator(self): 562 class A(metaclass=abc_ABCMeta): 563 @abc.abstractmethod 564 def foo(self): 565 pass 566 567 def class_decorator(cls): 568 cls.foo = lambda self: None 569 return cls 570 571 @abc.update_abstractmethods 572 @class_decorator 573 class B(A): 574 pass 575 576 B() 577 self.assertEqual(B.__abstractmethods__, set()) 578 579 def test_update_non_abc(self): 580 class A: 581 pass 582 583 @abc.abstractmethod 584 def updated_foo(self): 585 pass 586 587 A.foo = updated_foo 588 abc.update_abstractmethods(A) 589 A() 590 self.assertFalse(hasattr(A, '__abstractmethods__')) 591 592 def test_update_del_implementation(self): 593 class A(metaclass=abc_ABCMeta): 594 @abc.abstractmethod 595 def foo(self): 596 pass 597 598 class B(A): 599 def foo(self): 600 pass 601 602 B() 603 604 del B.foo 605 606 abc.update_abstractmethods(B) 607 608 msg = "class B with abstract method foo" 609 self.assertRaisesRegex(TypeError, msg, B) 610 611 def test_update_layered_implementation(self): 612 class A(metaclass=abc_ABCMeta): 613 @abc.abstractmethod 614 def foo(self): 615 pass 616 617 class B(A): 618 pass 619 620 class C(B): 621 def foo(self): 622 pass 623 624 C() 625 626 del C.foo 627 628 abc.update_abstractmethods(C) 629 630 msg = "class C with abstract method foo" 631 self.assertRaisesRegex(TypeError, msg, C) 632 633 def test_update_multi_inheritance(self): 634 class A(metaclass=abc_ABCMeta): 635 @abc.abstractmethod 636 def foo(self): 637 pass 638 639 class B(metaclass=abc_ABCMeta): 640 def foo(self): 641 pass 642 643 class C(B, A): 644 @abc.abstractmethod 645 def foo(self): 646 pass 647 648 self.assertEqual(C.__abstractmethods__, {'foo'}) 649 650 del C.foo 651 652 abc.update_abstractmethods(C) 653 654 self.assertEqual(C.__abstractmethods__, set()) 655 656 C() 657 658 659 class TestABCWithInitSubclass(unittest.TestCase): 660 def test_works_with_init_subclass(self): 661 class abc_ABC(metaclass=abc_ABCMeta): 662 __slots__ = () 663 saved_kwargs = {} 664 class ReceivesClassKwargs: 665 def __init_subclass__(cls, **kwargs): 666 super().__init_subclass__() 667 saved_kwargs.update(kwargs) 668 class Receiver(ReceivesClassKwargs, abc_ABC, x=1, y=2, z=3): 669 pass 670 self.assertEqual(saved_kwargs, dict(x=1, y=2, z=3)) 671 return TestLegacyAPI, TestABC, TestABCWithInitSubclass 672 673TestLegacyAPI_Py, TestABC_Py, TestABCWithInitSubclass_Py = test_factory(abc.ABCMeta, 674 abc.get_cache_token) 675TestLegacyAPI_C, TestABC_C, TestABCWithInitSubclass_C = test_factory(_py_abc.ABCMeta, 676 _py_abc.get_cache_token) 677 678if __name__ == "__main__": 679 unittest.main() 680