blob: e20e033f219b7133e0211b361bc3125ea9109624 [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
4"""Unit tests for abc.py."""
5
Guido van Rossumcd16bf62007-06-13 18:07:49 +00006import unittest
Guido van Rossumcd16bf62007-06-13 18:07:49 +00007
8import abc
Christian Heimesbe5b30b2008-03-03 19:18:51 +00009from inspect import isabstract
Guido van Rossumcd16bf62007-06-13 18:07:49 +000010
11
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050012class TestLegacyAPI(unittest.TestCase):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000013
Guido van Rossum70d2b892007-08-01 17:52:23 +000014 def test_abstractproperty_basics(self):
15 @abc.abstractproperty
16 def foo(self): pass
Benjamin Peterson83cd3b92010-08-17 01:07:53 +000017 self.assertTrue(foo.__isabstractmethod__)
Guido van Rossum70d2b892007-08-01 17:52:23 +000018 def bar(self): pass
Benjamin Peterson83cd3b92010-08-17 01:07:53 +000019 self.assertFalse(hasattr(bar, "__isabstractmethod__"))
Guido van Rossum70d2b892007-08-01 17:52:23 +000020
Guido van Rossumcd16bf62007-06-13 18:07:49 +000021 class C(metaclass=abc.ABCMeta):
Guido van Rossum70d2b892007-08-01 17:52:23 +000022 @abc.abstractproperty
23 def foo(self): return 3
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050024 self.assertRaises(TypeError, C)
Guido van Rossumcd16bf62007-06-13 18:07:49 +000025 class D(C):
Guido van Rossum70d2b892007-08-01 17:52:23 +000026 @property
27 def foo(self): return super().foo
28 self.assertEqual(D().foo, 3)
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050029 self.assertFalse(getattr(D.foo, "__isabstractmethod__", False))
Guido van Rossum70d2b892007-08-01 17:52:23 +000030
Benjamin Peterson45c257f2010-08-17 00:52:52 +000031 def test_abstractclassmethod_basics(self):
32 @abc.abstractclassmethod
33 def foo(cls): pass
Benjamin Peterson83cd3b92010-08-17 01:07:53 +000034 self.assertTrue(foo.__isabstractmethod__)
Benjamin Peterson45c257f2010-08-17 00:52:52 +000035 @classmethod
36 def bar(cls): pass
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050037 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
Benjamin Peterson45c257f2010-08-17 00:52:52 +000038
39 class C(metaclass=abc.ABCMeta):
40 @abc.abstractclassmethod
41 def foo(cls): return cls.__name__
42 self.assertRaises(TypeError, C)
43 class D(C):
44 @classmethod
45 def foo(cls): return super().foo()
46 self.assertEqual(D.foo(), 'D')
47 self.assertEqual(D().foo(), 'D')
48
49 def test_abstractstaticmethod_basics(self):
50 @abc.abstractstaticmethod
51 def foo(): pass
Benjamin Peterson83cd3b92010-08-17 01:07:53 +000052 self.assertTrue(foo.__isabstractmethod__)
Benjamin Peterson45c257f2010-08-17 00:52:52 +000053 @staticmethod
54 def bar(): pass
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050055 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
Benjamin Peterson45c257f2010-08-17 00:52:52 +000056
57 class C(metaclass=abc.ABCMeta):
58 @abc.abstractstaticmethod
59 def foo(): return 3
60 self.assertRaises(TypeError, C)
61 class D(C):
62 @staticmethod
63 def foo(): return 4
64 self.assertEqual(D.foo(), 4)
65 self.assertEqual(D().foo(), 4)
66
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050067
68class TestABC(unittest.TestCase):
69
Andrew Svetlovb67596d2012-12-13 19:09:33 +020070 def test_ABC_helper(self):
71 # create an ABC using the helper class and perform basic checks
72 class C(abc.ABC):
73 @classmethod
74 @abc.abstractmethod
75 def foo(cls): return cls.__name__
76 self.assertEqual(type(C), abc.ABCMeta)
77 self.assertRaises(TypeError, C)
78 class D(C):
79 @classmethod
80 def foo(cls): return super().foo()
81 self.assertEqual(D.foo(), 'D')
82
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050083 def test_abstractmethod_basics(self):
84 @abc.abstractmethod
85 def foo(self): pass
86 self.assertTrue(foo.__isabstractmethod__)
87 def bar(self): pass
88 self.assertFalse(hasattr(bar, "__isabstractmethod__"))
89
90 def test_abstractproperty_basics(self):
91 @property
92 @abc.abstractmethod
93 def foo(self): pass
94 self.assertTrue(foo.__isabstractmethod__)
95 def bar(self): pass
96 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
97
98 class C(metaclass=abc.ABCMeta):
99 @property
100 @abc.abstractmethod
101 def foo(self): return 3
102 self.assertRaises(TypeError, C)
103 class D(C):
104 @C.foo.getter
105 def foo(self): return super().foo
106 self.assertEqual(D().foo, 3)
107
108 def test_abstractclassmethod_basics(self):
109 @classmethod
110 @abc.abstractmethod
111 def foo(cls): pass
112 self.assertTrue(foo.__isabstractmethod__)
113 @classmethod
114 def bar(cls): pass
115 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
116
117 class C(metaclass=abc.ABCMeta):
118 @classmethod
119 @abc.abstractmethod
120 def foo(cls): return cls.__name__
121 self.assertRaises(TypeError, C)
122 class D(C):
123 @classmethod
124 def foo(cls): return super().foo()
125 self.assertEqual(D.foo(), 'D')
126 self.assertEqual(D().foo(), 'D')
127
128 def test_abstractstaticmethod_basics(self):
129 @staticmethod
130 @abc.abstractmethod
131 def foo(): pass
132 self.assertTrue(foo.__isabstractmethod__)
133 @staticmethod
134 def bar(): pass
135 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
136
137 class C(metaclass=abc.ABCMeta):
138 @staticmethod
139 @abc.abstractmethod
140 def foo(): return 3
141 self.assertRaises(TypeError, C)
142 class D(C):
143 @staticmethod
144 def foo(): return 4
145 self.assertEqual(D.foo(), 4)
146 self.assertEqual(D().foo(), 4)
147
148 def test_abstractmethod_integration(self):
149 for abstractthing in [abc.abstractmethod, abc.abstractproperty,
150 abc.abstractclassmethod,
151 abc.abstractstaticmethod]:
152 class C(metaclass=abc.ABCMeta):
153 @abstractthing
154 def foo(self): pass # abstract
155 def bar(self): pass # concrete
156 self.assertEqual(C.__abstractmethods__, {"foo"})
157 self.assertRaises(TypeError, C) # because foo is abstract
158 self.assertTrue(isabstract(C))
159 class D(C):
160 def bar(self): pass # concrete override of concrete
161 self.assertEqual(D.__abstractmethods__, {"foo"})
162 self.assertRaises(TypeError, D) # because foo is still abstract
163 self.assertTrue(isabstract(D))
164 class E(D):
165 def foo(self): pass
166 self.assertEqual(E.__abstractmethods__, set())
167 E() # now foo is concrete, too
168 self.assertFalse(isabstract(E))
169 class F(E):
170 @abstractthing
171 def bar(self): pass # abstract override of concrete
172 self.assertEqual(F.__abstractmethods__, {"bar"})
173 self.assertRaises(TypeError, F) # because bar is abstract now
174 self.assertTrue(isabstract(F))
175
176 def test_descriptors_with_abstractmethod(self):
177 class C(metaclass=abc.ABCMeta):
178 @property
179 @abc.abstractmethod
180 def foo(self): return 3
181 @foo.setter
182 @abc.abstractmethod
183 def foo(self, val): pass
184 self.assertRaises(TypeError, C)
185 class D(C):
186 @C.foo.getter
187 def foo(self): return super().foo
188 self.assertRaises(TypeError, D)
189 class E(D):
190 @D.foo.setter
191 def foo(self, val): pass
192 self.assertEqual(E().foo, 3)
193 # check that the property's __isabstractmethod__ descriptor does the
194 # right thing when presented with a value that fails truth testing:
195 class NotBool(object):
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200196 def __bool__(self):
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -0500197 raise ValueError()
Serhiy Storchakaa60c2fe2015-03-12 21:56:08 +0200198 __len__ = __bool__
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -0500199 with self.assertRaises(ValueError):
200 class F(C):
201 def bar(self):
202 pass
203 bar.__isabstractmethod__ = NotBool()
204 foo = property(bar)
205
206
207 def test_customdescriptors_with_abstractmethod(self):
208 class Descriptor:
209 def __init__(self, fget, fset=None):
210 self._fget = fget
211 self._fset = fset
212 def getter(self, callable):
213 return Descriptor(callable, self._fget)
214 def setter(self, callable):
215 return Descriptor(self._fget, callable)
216 @property
217 def __isabstractmethod__(self):
218 return (getattr(self._fget, '__isabstractmethod__', False)
219 or getattr(self._fset, '__isabstractmethod__', False))
220 class C(metaclass=abc.ABCMeta):
221 @Descriptor
222 @abc.abstractmethod
223 def foo(self): return 3
224 @foo.setter
225 @abc.abstractmethod
226 def foo(self, val): pass
227 self.assertRaises(TypeError, C)
228 class D(C):
229 @C.foo.getter
230 def foo(self): return super().foo
231 self.assertRaises(TypeError, D)
232 class E(D):
233 @D.foo.setter
234 def foo(self, val): pass
235 self.assertFalse(E.foo.__isabstractmethod__)
236
Benjamin Peterson970d1882010-10-02 17:55:47 +0000237 def test_metaclass_abc(self):
238 # Metaclasses can be ABCs, too.
239 class A(metaclass=abc.ABCMeta):
240 @abc.abstractmethod
241 def x(self):
242 pass
243 self.assertEqual(A.__abstractmethods__, {"x"})
244 class meta(type, A):
245 def x(self):
246 return 1
247 class C(metaclass=meta):
248 pass
249
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000250 def test_registration_basics(self):
251 class A(metaclass=abc.ABCMeta):
252 pass
Christian Heimes043d6f62008-01-07 17:19:16 +0000253 class B(object):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000254 pass
255 b = B()
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000256 self.assertFalse(issubclass(B, A))
257 self.assertFalse(issubclass(B, (A,)))
Ezio Melottie9615932010-01-24 19:26:24 +0000258 self.assertNotIsInstance(b, A)
259 self.assertNotIsInstance(b, (A,))
Éric Araujo6c3787c2011-02-24 18:03:10 +0000260 B1 = A.register(B)
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000261 self.assertTrue(issubclass(B, A))
262 self.assertTrue(issubclass(B, (A,)))
Ezio Melottie9615932010-01-24 19:26:24 +0000263 self.assertIsInstance(b, A)
264 self.assertIsInstance(b, (A,))
Éric Araujo6c3787c2011-02-24 18:03:10 +0000265 self.assertIs(B1, B)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000266 class C(B):
267 pass
268 c = C()
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000269 self.assertTrue(issubclass(C, A))
270 self.assertTrue(issubclass(C, (A,)))
Ezio Melottie9615932010-01-24 19:26:24 +0000271 self.assertIsInstance(c, A)
272 self.assertIsInstance(c, (A,))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000273
Éric Araujo6c3787c2011-02-24 18:03:10 +0000274 def test_register_as_class_deco(self):
275 class A(metaclass=abc.ABCMeta):
276 pass
277 @A.register
278 class B(object):
279 pass
280 b = B()
281 self.assertTrue(issubclass(B, A))
282 self.assertTrue(issubclass(B, (A,)))
283 self.assertIsInstance(b, A)
284 self.assertIsInstance(b, (A,))
285 @A.register
286 class C(B):
287 pass
288 c = C()
289 self.assertTrue(issubclass(C, A))
290 self.assertTrue(issubclass(C, (A,)))
291 self.assertIsInstance(c, A)
292 self.assertIsInstance(c, (A,))
293 self.assertIs(C, A.register(C))
294
Christian Heimes68f5fbe2008-02-14 08:27:37 +0000295 def test_isinstance_invalidation(self):
296 class A(metaclass=abc.ABCMeta):
297 pass
298 class B:
299 pass
300 b = B()
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000301 self.assertFalse(isinstance(b, A))
302 self.assertFalse(isinstance(b, (A,)))
Łukasz Langaeadd8cf2013-05-25 18:41:50 +0200303 token_old = abc.get_cache_token()
Christian Heimes68f5fbe2008-02-14 08:27:37 +0000304 A.register(B)
Łukasz Langaeadd8cf2013-05-25 18:41:50 +0200305 token_new = abc.get_cache_token()
306 self.assertNotEqual(token_old, token_new)
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000307 self.assertTrue(isinstance(b, A))
308 self.assertTrue(isinstance(b, (A,)))
Christian Heimes68f5fbe2008-02-14 08:27:37 +0000309
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000310 def test_registration_builtins(self):
311 class A(metaclass=abc.ABCMeta):
312 pass
313 A.register(int)
Ezio Melottie9615932010-01-24 19:26:24 +0000314 self.assertIsInstance(42, A)
315 self.assertIsInstance(42, (A,))
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000316 self.assertTrue(issubclass(int, A))
317 self.assertTrue(issubclass(int, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000318 class B(A):
319 pass
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000320 B.register(str)
321 class C(str): pass
Ezio Melottie9615932010-01-24 19:26:24 +0000322 self.assertIsInstance("", A)
323 self.assertIsInstance("", (A,))
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000324 self.assertTrue(issubclass(str, A))
325 self.assertTrue(issubclass(str, (A,)))
326 self.assertTrue(issubclass(C, A))
327 self.assertTrue(issubclass(C, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000328
329 def test_registration_edge_cases(self):
330 class A(metaclass=abc.ABCMeta):
331 pass
332 A.register(A) # should pass silently
333 class A1(A):
334 pass
335 self.assertRaises(RuntimeError, A1.register, A) # cycles not allowed
Christian Heimes043d6f62008-01-07 17:19:16 +0000336 class B(object):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000337 pass
338 A1.register(B) # ok
339 A1.register(B) # should pass silently
340 class C(A):
341 pass
342 A.register(C) # should pass silently
343 self.assertRaises(RuntimeError, C.register, A) # cycles not allowed
344 C.register(B) # ok
345
Benjamin Petersond6326642010-01-27 02:25:58 +0000346 def test_register_non_class(self):
347 class A(metaclass=abc.ABCMeta):
348 pass
Ezio Melottied3a7d22010-12-01 02:32:32 +0000349 self.assertRaisesRegex(TypeError, "Can only register classes",
350 A.register, 4)
Benjamin Petersond6326642010-01-27 02:25:58 +0000351
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000352 def test_registration_transitiveness(self):
353 class A(metaclass=abc.ABCMeta):
354 pass
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000355 self.assertTrue(issubclass(A, A))
356 self.assertTrue(issubclass(A, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000357 class B(metaclass=abc.ABCMeta):
358 pass
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000359 self.assertFalse(issubclass(A, B))
360 self.assertFalse(issubclass(A, (B,)))
361 self.assertFalse(issubclass(B, A))
362 self.assertFalse(issubclass(B, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000363 class C(metaclass=abc.ABCMeta):
364 pass
365 A.register(B)
366 class B1(B):
367 pass
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000368 self.assertTrue(issubclass(B1, A))
369 self.assertTrue(issubclass(B1, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000370 class C1(C):
371 pass
372 B1.register(C1)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000373 self.assertFalse(issubclass(C, B))
374 self.assertFalse(issubclass(C, (B,)))
375 self.assertFalse(issubclass(C, B1))
376 self.assertFalse(issubclass(C, (B1,)))
377 self.assertTrue(issubclass(C1, A))
378 self.assertTrue(issubclass(C1, (A,)))
379 self.assertTrue(issubclass(C1, B))
380 self.assertTrue(issubclass(C1, (B,)))
381 self.assertTrue(issubclass(C1, B1))
382 self.assertTrue(issubclass(C1, (B1,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000383 C1.register(int)
384 class MyInt(int):
385 pass
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000386 self.assertTrue(issubclass(MyInt, A))
387 self.assertTrue(issubclass(MyInt, (A,)))
Ezio Melottie9615932010-01-24 19:26:24 +0000388 self.assertIsInstance(42, A)
389 self.assertIsInstance(42, (A,))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000390
Guido van Rossum894d35e2007-09-11 20:42:30 +0000391 def test_all_new_methods_are_called(self):
392 class A(metaclass=abc.ABCMeta):
393 pass
Christian Heimes043d6f62008-01-07 17:19:16 +0000394 class B(object):
Guido van Rossum894d35e2007-09-11 20:42:30 +0000395 counter = 0
396 def __new__(cls):
397 B.counter += 1
398 return super().__new__(cls)
399 class C(A, B):
400 pass
401 self.assertEqual(B.counter, 0)
402 C()
403 self.assertEqual(B.counter, 1)
404
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000405
Natebd583ef2017-03-15 11:39:22 -0700406class TestABCWithInitSubclass(unittest.TestCase):
407 def test_works_with_init_subclass(self):
408 saved_kwargs = {}
409 class ReceivesClassKwargs:
410 def __init_subclass__(cls, **kwargs):
411 super().__init_subclass__()
412 saved_kwargs.update(kwargs)
413 class Receiver(ReceivesClassKwargs, abc.ABC, x=1, y=2, z=3):
414 pass
415 self.assertEqual(saved_kwargs, dict(x=1, y=2, z=3))
416
417
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000418if __name__ == "__main__":
419 unittest.main()