blob: 7e9c47b3cacb96978da60c935ac86eed724503c4 [file] [log] [blame]
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001# Copyright 2007 Google, Inc. All Rights Reserved.
2# Licensed to PSF under a Contributor Agreement.
3
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +00004# 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
Guido van Rossumcd16bf62007-06-13 18:07:49 +00007"""Unit tests for abc.py."""
8
Guido van Rossumcd16bf62007-06-13 18:07:49 +00009import unittest
Guido van Rossumcd16bf62007-06-13 18:07:49 +000010
11import abc
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000012import _py_abc
Christian Heimesbe5b30b2008-03-03 19:18:51 +000013from inspect import isabstract
Guido van Rossumcd16bf62007-06-13 18:07:49 +000014
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000015def test_factory(abc_ABCMeta, abc_get_cache_token):
16 class TestLegacyAPI(unittest.TestCase):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000017
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000018 def test_abstractproperty_basics(self):
Guido van Rossum70d2b892007-08-01 17:52:23 +000019 @abc.abstractproperty
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000020 def foo(self): pass
21 self.assertTrue(foo.__isabstractmethod__)
22 def bar(self): pass
23 self.assertFalse(hasattr(bar, "__isabstractmethod__"))
Guido van Rossum70d2b892007-08-01 17:52:23 +000024
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000025 class C(metaclass=abc_ABCMeta):
26 @abc.abstractproperty
27 def foo(self): return 3
28 self.assertRaises(TypeError, C)
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050029 class D(C):
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +000030 @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
Daniel Andrade4a12a172019-09-11 08:29:44 -0700152 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
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000171 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)
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -0500212 class E(D):
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000213 @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)
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -0500228
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000229
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):
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -0500265 pass
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000266 self.assertEqual(A.__abstractmethods__, {"x"})
267 class meta(type, A):
268 def x(self):
269 return 1
270 class C(metaclass=meta):
Benjamin Peterson970d1882010-10-02 17:55:47 +0000271 pass
Benjamin Peterson970d1882010-10-02 17:55:47 +0000272
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000273 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,))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000296
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000297 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))
Éric Araujo6c3787c2011-02-24 18:03:10 +0000317
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000318 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()
Dong-hee Na53e4c912020-03-30 23:35:38 +0900329 self.assertGreater(token_new, token_old)
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000330 self.assertTrue(isinstance(b, A))
331 self.assertTrue(isinstance(b, (A,)))
Christian Heimes68f5fbe2008-02-14 08:27:37 +0000332
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000333 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,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000351
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000352 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
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000368
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000369 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)
Benjamin Petersond6326642010-01-27 02:25:58 +0000374
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000375 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,))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000413
INADA Naokifc7df0e2018-03-07 16:27:01 +0900414 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
Alexey Izbyshevcdbf50c2018-08-20 23:04:19 +0300432 # 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
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000462 def test_all_new_methods_are_called(self):
463 class A(metaclass=abc_ABCMeta):
464 pass
465 class B(object):
466 counter = 0
467 def __new__(cls):
468 B.counter += 1
469 return super().__new__(cls)
470 class C(A, B):
471 pass
472 self.assertEqual(B.counter, 0)
473 C()
474 self.assertEqual(B.counter, 1)
Guido van Rossum894d35e2007-09-11 20:42:30 +0000475
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000476 def test_ABC_has___slots__(self):
477 self.assertTrue(hasattr(abc.ABC, '__slots__'))
478
479 def test_tricky_new_works(self):
480 def with_metaclass(meta, *bases):
481 class metaclass(type):
482 def __new__(cls, name, this_bases, d):
483 return meta(name, bases, d)
484 return type.__new__(metaclass, 'temporary_class', (), {})
485 class A: ...
486 class B: ...
487 class C(with_metaclass(abc_ABCMeta, A, B)):
488 pass
489 self.assertEqual(C.__class__, abc_ABCMeta)
Aaron Hall, MBAff487392017-06-06 15:34:57 -0400490
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000491
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000492 class TestABCWithInitSubclass(unittest.TestCase):
493 def test_works_with_init_subclass(self):
494 class abc_ABC(metaclass=abc_ABCMeta):
495 __slots__ = ()
496 saved_kwargs = {}
497 class ReceivesClassKwargs:
498 def __init_subclass__(cls, **kwargs):
499 super().__init_subclass__()
500 saved_kwargs.update(kwargs)
501 class Receiver(ReceivesClassKwargs, abc_ABC, x=1, y=2, z=3):
502 pass
503 self.assertEqual(saved_kwargs, dict(x=1, y=2, z=3))
504 return TestLegacyAPI, TestABC, TestABCWithInitSubclass
Natebd583ef2017-03-15 11:39:22 -0700505
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000506TestLegacyAPI_Py, TestABC_Py, TestABCWithInitSubclass_Py = test_factory(abc.ABCMeta,
507 abc.get_cache_token)
508TestLegacyAPI_C, TestABC_C, TestABCWithInitSubclass_C = test_factory(_py_abc.ABCMeta,
509 _py_abc.get_cache_token)
Natebd583ef2017-03-15 11:39:22 -0700510
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000511if __name__ == "__main__":
512 unittest.main()