blob: af26c1d6b8c5ea6f0ab9a5c93b8dbb7880f75d8b [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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +000012import _py_abc
Christian Heimesbe5b30b2008-03-03 19:18:51 +000013from inspect import isabstract
Guido van Rossumcd16bf62007-06-13 18:07:49 +000014
Ivan Levkivskyi38928992018-02-18 17:39:43 +000015def test_factory(abc_ABCMeta, abc_get_cache_token):
16 class TestLegacyAPI(unittest.TestCase):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000017
Ivan Levkivskyi38928992018-02-18 17:39:43 +000018 def test_abstractproperty_basics(self):
Guido van Rossum70d2b892007-08-01 17:52:23 +000019 @abc.abstractproperty
Ivan Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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 Levkivskyi38928992018-02-18 17:39:43 +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
Ivan Levkivskyi38928992018-02-18 17:39:43 +0000395 def test_all_new_methods_are_called(self):
396 class A(metaclass=abc_ABCMeta):
397 pass
398 class B(object):
399 counter = 0
400 def __new__(cls):
401 B.counter += 1
402 return super().__new__(cls)
403 class C(A, B):
404 pass
405 self.assertEqual(B.counter, 0)
406 C()
407 self.assertEqual(B.counter, 1)
Guido van Rossum894d35e2007-09-11 20:42:30 +0000408
Ivan Levkivskyi38928992018-02-18 17:39:43 +0000409 def test_ABC_has___slots__(self):
410 self.assertTrue(hasattr(abc.ABC, '__slots__'))
411
412 def test_tricky_new_works(self):
413 def with_metaclass(meta, *bases):
414 class metaclass(type):
415 def __new__(cls, name, this_bases, d):
416 return meta(name, bases, d)
417 return type.__new__(metaclass, 'temporary_class', (), {})
418 class A: ...
419 class B: ...
420 class C(with_metaclass(abc_ABCMeta, A, B)):
421 pass
422 self.assertEqual(C.__class__, abc_ABCMeta)
Aaron Hall, MBAff487392017-06-06 15:34:57 -0400423
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000424
Ivan Levkivskyi38928992018-02-18 17:39:43 +0000425 class TestABCWithInitSubclass(unittest.TestCase):
426 def test_works_with_init_subclass(self):
427 class abc_ABC(metaclass=abc_ABCMeta):
428 __slots__ = ()
429 saved_kwargs = {}
430 class ReceivesClassKwargs:
431 def __init_subclass__(cls, **kwargs):
432 super().__init_subclass__()
433 saved_kwargs.update(kwargs)
434 class Receiver(ReceivesClassKwargs, abc_ABC, x=1, y=2, z=3):
435 pass
436 self.assertEqual(saved_kwargs, dict(x=1, y=2, z=3))
437 return TestLegacyAPI, TestABC, TestABCWithInitSubclass
Natebd583ef2017-03-15 11:39:22 -0700438
Ivan Levkivskyi38928992018-02-18 17:39:43 +0000439TestLegacyAPI_Py, TestABC_Py, TestABCWithInitSubclass_Py = test_factory(abc.ABCMeta,
440 abc.get_cache_token)
441TestLegacyAPI_C, TestABC_C, TestABCWithInitSubclass_C = test_factory(_py_abc.ABCMeta,
442 _py_abc.get_cache_token)
Natebd583ef2017-03-15 11:39:22 -0700443
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000444if __name__ == "__main__":
445 unittest.main()