blob: 9f5afb241aea3a16d6bf3acb4f75b929ce0acf3b [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
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)
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -0500193 class E(D):
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000194 @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)
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -0500209
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000210
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):
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -0500246 pass
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000247 self.assertEqual(A.__abstractmethods__, {"x"})
248 class meta(type, A):
249 def x(self):
250 return 1
251 class C(metaclass=meta):
Benjamin Peterson970d1882010-10-02 17:55:47 +0000252 pass
Benjamin Peterson970d1882010-10-02 17:55:47 +0000253
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000254 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,))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000277
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000278 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))
Éric Araujo6c3787c2011-02-24 18:03:10 +0000298
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000299 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,)))
Christian Heimes68f5fbe2008-02-14 08:27:37 +0000313
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000314 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,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000332
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000333 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
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000349
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000350 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)
Benjamin Petersond6326642010-01-27 02:25:58 +0000355
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000356 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,))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000394
INADA Naokifc7df0e2018-03-07 16:27:01 +0900395 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
Alexey Izbyshevcdbf50c2018-08-20 23:04:19 +0300413 # 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
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000443 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)
Guido van Rossum894d35e2007-09-11 20:42:30 +0000456
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000457 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)
Aaron Hall, MBAff487392017-06-06 15:34:57 -0400471
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000472
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000473 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
Natebd583ef2017-03-15 11:39:22 -0700486
Ivan Levkivskyi03e3c342018-02-18 12:41:58 +0000487TestLegacyAPI_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)
Natebd583ef2017-03-15 11:39:22 -0700491
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000492if __name__ == "__main__":
493 unittest.main()