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_abstractmethod_integration(self): 153 for abstractthing in [abc.abstractmethod, abc.abstractproperty, 154 abc.abstractclassmethod, 155 abc.abstractstaticmethod]: 156 class C(metaclass=abc_ABCMeta): 157 @abstractthing 158 def foo(self): pass # abstract 159 def bar(self): pass # concrete 160 self.assertEqual(C.__abstractmethods__, {"foo"}) 161 self.assertRaises(TypeError, C) # because foo is abstract 162 self.assertTrue(isabstract(C)) 163 class D(C): 164 def bar(self): pass # concrete override of concrete 165 self.assertEqual(D.__abstractmethods__, {"foo"}) 166 self.assertRaises(TypeError, D) # because foo is still abstract 167 self.assertTrue(isabstract(D)) 168 class E(D): 169 def foo(self): pass 170 self.assertEqual(E.__abstractmethods__, set()) 171 E() # now foo is concrete, too 172 self.assertFalse(isabstract(E)) 173 class F(E): 174 @abstractthing 175 def bar(self): pass # abstract override of concrete 176 self.assertEqual(F.__abstractmethods__, {"bar"}) 177 self.assertRaises(TypeError, F) # because bar is abstract now 178 self.assertTrue(isabstract(F)) 179 180 def test_descriptors_with_abstractmethod(self): 181 class C(metaclass=abc_ABCMeta): 182 @property 183 @abc.abstractmethod 184 def foo(self): return 3 185 @foo.setter 186 @abc.abstractmethod 187 def foo(self, val): pass 188 self.assertRaises(TypeError, C) 189 class D(C): 190 @C.foo.getter 191 def foo(self): return super().foo 192 self.assertRaises(TypeError, D) 193 class E(D): 194 @D.foo.setter 195 def foo(self, val): pass 196 self.assertEqual(E().foo, 3) 197 # check that the property's __isabstractmethod__ descriptor does the 198 # right thing when presented with a value that fails truth testing: 199 class NotBool(object): 200 def __bool__(self): 201 raise ValueError() 202 __len__ = __bool__ 203 with self.assertRaises(ValueError): 204 class F(C): 205 def bar(self): 206 pass 207 bar.__isabstractmethod__ = NotBool() 208 foo = property(bar) 209 210 211 def test_customdescriptors_with_abstractmethod(self): 212 class Descriptor: 213 def __init__(self, fget, fset=None): 214 self._fget = fget 215 self._fset = fset 216 def getter(self, callable): 217 return Descriptor(callable, self._fget) 218 def setter(self, callable): 219 return Descriptor(self._fget, callable) 220 @property 221 def __isabstractmethod__(self): 222 return (getattr(self._fget, '__isabstractmethod__', False) 223 or getattr(self._fset, '__isabstractmethod__', False)) 224 class C(metaclass=abc_ABCMeta): 225 @Descriptor 226 @abc.abstractmethod 227 def foo(self): return 3 228 @foo.setter 229 @abc.abstractmethod 230 def foo(self, val): pass 231 self.assertRaises(TypeError, C) 232 class D(C): 233 @C.foo.getter 234 def foo(self): return super().foo 235 self.assertRaises(TypeError, D) 236 class E(D): 237 @D.foo.setter 238 def foo(self, val): pass 239 self.assertFalse(E.foo.__isabstractmethod__) 240 241 def test_metaclass_abc(self): 242 # Metaclasses can be ABCs, too. 243 class A(metaclass=abc_ABCMeta): 244 @abc.abstractmethod 245 def x(self): 246 pass 247 self.assertEqual(A.__abstractmethods__, {"x"}) 248 class meta(type, A): 249 def x(self): 250 return 1 251 class C(metaclass=meta): 252 pass 253 254 def test_registration_basics(self): 255 class A(metaclass=abc_ABCMeta): 256 pass 257 class B(object): 258 pass 259 b = B() 260 self.assertFalse(issubclass(B, A)) 261 self.assertFalse(issubclass(B, (A,))) 262 self.assertNotIsInstance(b, A) 263 self.assertNotIsInstance(b, (A,)) 264 B1 = A.register(B) 265 self.assertTrue(issubclass(B, A)) 266 self.assertTrue(issubclass(B, (A,))) 267 self.assertIsInstance(b, A) 268 self.assertIsInstance(b, (A,)) 269 self.assertIs(B1, B) 270 class C(B): 271 pass 272 c = C() 273 self.assertTrue(issubclass(C, A)) 274 self.assertTrue(issubclass(C, (A,))) 275 self.assertIsInstance(c, A) 276 self.assertIsInstance(c, (A,)) 277 278 def test_register_as_class_deco(self): 279 class A(metaclass=abc_ABCMeta): 280 pass 281 @A.register 282 class B(object): 283 pass 284 b = B() 285 self.assertTrue(issubclass(B, A)) 286 self.assertTrue(issubclass(B, (A,))) 287 self.assertIsInstance(b, A) 288 self.assertIsInstance(b, (A,)) 289 @A.register 290 class C(B): 291 pass 292 c = C() 293 self.assertTrue(issubclass(C, A)) 294 self.assertTrue(issubclass(C, (A,))) 295 self.assertIsInstance(c, A) 296 self.assertIsInstance(c, (A,)) 297 self.assertIs(C, A.register(C)) 298 299 def test_isinstance_invalidation(self): 300 class A(metaclass=abc_ABCMeta): 301 pass 302 class B: 303 pass 304 b = B() 305 self.assertFalse(isinstance(b, A)) 306 self.assertFalse(isinstance(b, (A,))) 307 token_old = abc_get_cache_token() 308 A.register(B) 309 token_new = abc_get_cache_token() 310 self.assertNotEqual(token_old, token_new) 311 self.assertTrue(isinstance(b, A)) 312 self.assertTrue(isinstance(b, (A,))) 313 314 def test_registration_builtins(self): 315 class A(metaclass=abc_ABCMeta): 316 pass 317 A.register(int) 318 self.assertIsInstance(42, A) 319 self.assertIsInstance(42, (A,)) 320 self.assertTrue(issubclass(int, A)) 321 self.assertTrue(issubclass(int, (A,))) 322 class B(A): 323 pass 324 B.register(str) 325 class C(str): pass 326 self.assertIsInstance("", A) 327 self.assertIsInstance("", (A,)) 328 self.assertTrue(issubclass(str, A)) 329 self.assertTrue(issubclass(str, (A,))) 330 self.assertTrue(issubclass(C, A)) 331 self.assertTrue(issubclass(C, (A,))) 332 333 def test_registration_edge_cases(self): 334 class A(metaclass=abc_ABCMeta): 335 pass 336 A.register(A) # should pass silently 337 class A1(A): 338 pass 339 self.assertRaises(RuntimeError, A1.register, A) # cycles not allowed 340 class B(object): 341 pass 342 A1.register(B) # ok 343 A1.register(B) # should pass silently 344 class C(A): 345 pass 346 A.register(C) # should pass silently 347 self.assertRaises(RuntimeError, C.register, A) # cycles not allowed 348 C.register(B) # ok 349 350 def test_register_non_class(self): 351 class A(metaclass=abc_ABCMeta): 352 pass 353 self.assertRaisesRegex(TypeError, "Can only register classes", 354 A.register, 4) 355 356 def test_registration_transitiveness(self): 357 class A(metaclass=abc_ABCMeta): 358 pass 359 self.assertTrue(issubclass(A, A)) 360 self.assertTrue(issubclass(A, (A,))) 361 class B(metaclass=abc_ABCMeta): 362 pass 363 self.assertFalse(issubclass(A, B)) 364 self.assertFalse(issubclass(A, (B,))) 365 self.assertFalse(issubclass(B, A)) 366 self.assertFalse(issubclass(B, (A,))) 367 class C(metaclass=abc_ABCMeta): 368 pass 369 A.register(B) 370 class B1(B): 371 pass 372 self.assertTrue(issubclass(B1, A)) 373 self.assertTrue(issubclass(B1, (A,))) 374 class C1(C): 375 pass 376 B1.register(C1) 377 self.assertFalse(issubclass(C, B)) 378 self.assertFalse(issubclass(C, (B,))) 379 self.assertFalse(issubclass(C, B1)) 380 self.assertFalse(issubclass(C, (B1,))) 381 self.assertTrue(issubclass(C1, A)) 382 self.assertTrue(issubclass(C1, (A,))) 383 self.assertTrue(issubclass(C1, B)) 384 self.assertTrue(issubclass(C1, (B,))) 385 self.assertTrue(issubclass(C1, B1)) 386 self.assertTrue(issubclass(C1, (B1,))) 387 C1.register(int) 388 class MyInt(int): 389 pass 390 self.assertTrue(issubclass(MyInt, A)) 391 self.assertTrue(issubclass(MyInt, (A,))) 392 self.assertIsInstance(42, A) 393 self.assertIsInstance(42, (A,)) 394 395 def test_issubclass_bad_arguments(self): 396 class A(metaclass=abc_ABCMeta): 397 pass 398 399 with self.assertRaises(TypeError): 400 issubclass({}, A) # unhashable 401 402 with self.assertRaises(TypeError): 403 issubclass(42, A) # No __mro__ 404 405 # Python version supports any iterable as __mro__. 406 # But it's implementation detail and don't emulate it in C version. 407 class C: 408 __mro__ = 42 # __mro__ is not tuple 409 410 with self.assertRaises(TypeError): 411 issubclass(C(), A) 412 413 # bpo-34441: Check that issubclass() doesn't crash on bogus 414 # classes. 415 bogus_subclasses = [ 416 None, 417 lambda x: [], 418 lambda: 42, 419 lambda: [42], 420 ] 421 422 for i, func in enumerate(bogus_subclasses): 423 class S(metaclass=abc_ABCMeta): 424 __subclasses__ = func 425 426 with self.subTest(i=i): 427 with self.assertRaises(TypeError): 428 issubclass(int, S) 429 430 # Also check that issubclass() propagates exceptions raised by 431 # __subclasses__. 432 exc_msg = "exception from __subclasses__" 433 434 def raise_exc(): 435 raise Exception(exc_msg) 436 437 class S(metaclass=abc_ABCMeta): 438 __subclasses__ = raise_exc 439 440 with self.assertRaisesRegex(Exception, exc_msg): 441 issubclass(int, S) 442 443 def test_all_new_methods_are_called(self): 444 class A(metaclass=abc_ABCMeta): 445 pass 446 class B(object): 447 counter = 0 448 def __new__(cls): 449 B.counter += 1 450 return super().__new__(cls) 451 class C(A, B): 452 pass 453 self.assertEqual(B.counter, 0) 454 C() 455 self.assertEqual(B.counter, 1) 456 457 def test_ABC_has___slots__(self): 458 self.assertTrue(hasattr(abc.ABC, '__slots__')) 459 460 def test_tricky_new_works(self): 461 def with_metaclass(meta, *bases): 462 class metaclass(type): 463 def __new__(cls, name, this_bases, d): 464 return meta(name, bases, d) 465 return type.__new__(metaclass, 'temporary_class', (), {}) 466 class A: ... 467 class B: ... 468 class C(with_metaclass(abc_ABCMeta, A, B)): 469 pass 470 self.assertEqual(C.__class__, abc_ABCMeta) 471 472 473 class TestABCWithInitSubclass(unittest.TestCase): 474 def test_works_with_init_subclass(self): 475 class abc_ABC(metaclass=abc_ABCMeta): 476 __slots__ = () 477 saved_kwargs = {} 478 class ReceivesClassKwargs: 479 def __init_subclass__(cls, **kwargs): 480 super().__init_subclass__() 481 saved_kwargs.update(kwargs) 482 class Receiver(ReceivesClassKwargs, abc_ABC, x=1, y=2, z=3): 483 pass 484 self.assertEqual(saved_kwargs, dict(x=1, y=2, z=3)) 485 return TestLegacyAPI, TestABC, TestABCWithInitSubclass 486 487TestLegacyAPI_Py, TestABC_Py, TestABCWithInitSubclass_Py = test_factory(abc.ABCMeta, 488 abc.get_cache_token) 489TestLegacyAPI_C, TestABC_C, TestABCWithInitSubclass_C = test_factory(_py_abc.ABCMeta, 490 _py_abc.get_cache_token) 491 492if __name__ == "__main__": 493 unittest.main() 494