blob: 4b151575ba48e521596b3c00f3f96ba2268d108b [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
Benjamin Petersonee8712c2008-05-20 21:35:26 +00007from test import support
Guido van Rossumcd16bf62007-06-13 18:07:49 +00008
9import abc
Christian Heimesbe5b30b2008-03-03 19:18:51 +000010from inspect import isabstract
Guido van Rossumcd16bf62007-06-13 18:07:49 +000011
12
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050013class TestLegacyAPI(unittest.TestCase):
Guido van Rossumcd16bf62007-06-13 18:07:49 +000014
Guido van Rossum70d2b892007-08-01 17:52:23 +000015 def test_abstractproperty_basics(self):
16 @abc.abstractproperty
17 def foo(self): pass
Benjamin Peterson83cd3b92010-08-17 01:07:53 +000018 self.assertTrue(foo.__isabstractmethod__)
Guido van Rossum70d2b892007-08-01 17:52:23 +000019 def bar(self): pass
Benjamin Peterson83cd3b92010-08-17 01:07:53 +000020 self.assertFalse(hasattr(bar, "__isabstractmethod__"))
Guido van Rossum70d2b892007-08-01 17:52:23 +000021
Guido van Rossumcd16bf62007-06-13 18:07:49 +000022 class C(metaclass=abc.ABCMeta):
Guido van Rossum70d2b892007-08-01 17:52:23 +000023 @abc.abstractproperty
24 def foo(self): return 3
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050025 self.assertRaises(TypeError, C)
Guido van Rossumcd16bf62007-06-13 18:07:49 +000026 class D(C):
Guido van Rossum70d2b892007-08-01 17:52:23 +000027 @property
28 def foo(self): return super().foo
29 self.assertEqual(D().foo, 3)
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050030 self.assertFalse(getattr(D.foo, "__isabstractmethod__", False))
Guido van Rossum70d2b892007-08-01 17:52:23 +000031
Benjamin Peterson45c257f2010-08-17 00:52:52 +000032 def test_abstractclassmethod_basics(self):
33 @abc.abstractclassmethod
34 def foo(cls): pass
Benjamin Peterson83cd3b92010-08-17 01:07:53 +000035 self.assertTrue(foo.__isabstractmethod__)
Benjamin Peterson45c257f2010-08-17 00:52:52 +000036 @classmethod
37 def bar(cls): pass
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050038 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
Benjamin Peterson45c257f2010-08-17 00:52:52 +000039
40 class C(metaclass=abc.ABCMeta):
41 @abc.abstractclassmethod
42 def foo(cls): return cls.__name__
43 self.assertRaises(TypeError, C)
44 class D(C):
45 @classmethod
46 def foo(cls): return super().foo()
47 self.assertEqual(D.foo(), 'D')
48 self.assertEqual(D().foo(), 'D')
49
50 def test_abstractstaticmethod_basics(self):
51 @abc.abstractstaticmethod
52 def foo(): pass
Benjamin Peterson83cd3b92010-08-17 01:07:53 +000053 self.assertTrue(foo.__isabstractmethod__)
Benjamin Peterson45c257f2010-08-17 00:52:52 +000054 @staticmethod
55 def bar(): pass
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050056 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
Benjamin Peterson45c257f2010-08-17 00:52:52 +000057
58 class C(metaclass=abc.ABCMeta):
59 @abc.abstractstaticmethod
60 def foo(): return 3
61 self.assertRaises(TypeError, C)
62 class D(C):
63 @staticmethod
64 def foo(): return 4
65 self.assertEqual(D.foo(), 4)
66 self.assertEqual(D().foo(), 4)
67
Guido van Rossum70d2b892007-08-01 17:52:23 +000068 def test_abstractmethod_integration(self):
Benjamin Peterson45c257f2010-08-17 00:52:52 +000069 for abstractthing in [abc.abstractmethod, abc.abstractproperty,
70 abc.abstractclassmethod,
71 abc.abstractstaticmethod]:
Guido van Rossum70d2b892007-08-01 17:52:23 +000072 class C(metaclass=abc.ABCMeta):
73 @abstractthing
74 def foo(self): pass # abstract
75 def bar(self): pass # concrete
76 self.assertEqual(C.__abstractmethods__, {"foo"})
77 self.assertRaises(TypeError, C) # because foo is abstract
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000078 self.assertTrue(isabstract(C))
Guido van Rossum70d2b892007-08-01 17:52:23 +000079 class D(C):
80 def bar(self): pass # concrete override of concrete
81 self.assertEqual(D.__abstractmethods__, {"foo"})
82 self.assertRaises(TypeError, D) # because foo is still abstract
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000083 self.assertTrue(isabstract(D))
Guido van Rossum70d2b892007-08-01 17:52:23 +000084 class E(D):
85 def foo(self): pass
86 self.assertEqual(E.__abstractmethods__, set())
87 E() # now foo is concrete, too
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000088 self.assertFalse(isabstract(E))
Guido van Rossum70d2b892007-08-01 17:52:23 +000089 class F(E):
90 @abstractthing
91 def bar(self): pass # abstract override of concrete
92 self.assertEqual(F.__abstractmethods__, {"bar"})
93 self.assertRaises(TypeError, F) # because bar is abstract now
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000094 self.assertTrue(isabstract(F))
Guido van Rossumcd16bf62007-06-13 18:07:49 +000095
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -050096
97class TestABC(unittest.TestCase):
98
Andrew Svetlovb67596d2012-12-13 19:09:33 +020099 def test_ABC_helper(self):
100 # create an ABC using the helper class and perform basic checks
101 class C(abc.ABC):
102 @classmethod
103 @abc.abstractmethod
104 def foo(cls): return cls.__name__
105 self.assertEqual(type(C), abc.ABCMeta)
106 self.assertRaises(TypeError, C)
107 class D(C):
108 @classmethod
109 def foo(cls): return super().foo()
110 self.assertEqual(D.foo(), 'D')
111
Benjamin Petersonbfebb7b2011-12-15 15:34:02 -0500112 def test_abstractmethod_basics(self):
113 @abc.abstractmethod
114 def foo(self): pass
115 self.assertTrue(foo.__isabstractmethod__)
116 def bar(self): pass
117 self.assertFalse(hasattr(bar, "__isabstractmethod__"))
118
119 def test_abstractproperty_basics(self):
120 @property
121 @abc.abstractmethod
122 def foo(self): pass
123 self.assertTrue(foo.__isabstractmethod__)
124 def bar(self): pass
125 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
126
127 class C(metaclass=abc.ABCMeta):
128 @property
129 @abc.abstractmethod
130 def foo(self): return 3
131 self.assertRaises(TypeError, C)
132 class D(C):
133 @C.foo.getter
134 def foo(self): return super().foo
135 self.assertEqual(D().foo, 3)
136
137 def test_abstractclassmethod_basics(self):
138 @classmethod
139 @abc.abstractmethod
140 def foo(cls): pass
141 self.assertTrue(foo.__isabstractmethod__)
142 @classmethod
143 def bar(cls): pass
144 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
145
146 class C(metaclass=abc.ABCMeta):
147 @classmethod
148 @abc.abstractmethod
149 def foo(cls): return cls.__name__
150 self.assertRaises(TypeError, C)
151 class D(C):
152 @classmethod
153 def foo(cls): return super().foo()
154 self.assertEqual(D.foo(), 'D')
155 self.assertEqual(D().foo(), 'D')
156
157 def test_abstractstaticmethod_basics(self):
158 @staticmethod
159 @abc.abstractmethod
160 def foo(): pass
161 self.assertTrue(foo.__isabstractmethod__)
162 @staticmethod
163 def bar(): pass
164 self.assertFalse(getattr(bar, "__isabstractmethod__", False))
165
166 class C(metaclass=abc.ABCMeta):
167 @staticmethod
168 @abc.abstractmethod
169 def foo(): return 3
170 self.assertRaises(TypeError, C)
171 class D(C):
172 @staticmethod
173 def foo(): return 4
174 self.assertEqual(D.foo(), 4)
175 self.assertEqual(D().foo(), 4)
176
177 def test_abstractmethod_integration(self):
178 for abstractthing in [abc.abstractmethod, abc.abstractproperty,
179 abc.abstractclassmethod,
180 abc.abstractstaticmethod]:
181 class C(metaclass=abc.ABCMeta):
182 @abstractthing
183 def foo(self): pass # abstract
184 def bar(self): pass # concrete
185 self.assertEqual(C.__abstractmethods__, {"foo"})
186 self.assertRaises(TypeError, C) # because foo is abstract
187 self.assertTrue(isabstract(C))
188 class D(C):
189 def bar(self): pass # concrete override of concrete
190 self.assertEqual(D.__abstractmethods__, {"foo"})
191 self.assertRaises(TypeError, D) # because foo is still abstract
192 self.assertTrue(isabstract(D))
193 class E(D):
194 def foo(self): pass
195 self.assertEqual(E.__abstractmethods__, set())
196 E() # now foo is concrete, too
197 self.assertFalse(isabstract(E))
198 class F(E):
199 @abstractthing
200 def bar(self): pass # abstract override of concrete
201 self.assertEqual(F.__abstractmethods__, {"bar"})
202 self.assertRaises(TypeError, F) # because bar is abstract now
203 self.assertTrue(isabstract(F))
204
205 def test_descriptors_with_abstractmethod(self):
206 class C(metaclass=abc.ABCMeta):
207 @property
208 @abc.abstractmethod
209 def foo(self): return 3
210 @foo.setter
211 @abc.abstractmethod
212 def foo(self, val): pass
213 self.assertRaises(TypeError, C)
214 class D(C):
215 @C.foo.getter
216 def foo(self): return super().foo
217 self.assertRaises(TypeError, D)
218 class E(D):
219 @D.foo.setter
220 def foo(self, val): pass
221 self.assertEqual(E().foo, 3)
222 # check that the property's __isabstractmethod__ descriptor does the
223 # right thing when presented with a value that fails truth testing:
224 class NotBool(object):
225 def __nonzero__(self):
226 raise ValueError()
227 __len__ = __nonzero__
228 with self.assertRaises(ValueError):
229 class F(C):
230 def bar(self):
231 pass
232 bar.__isabstractmethod__ = NotBool()
233 foo = property(bar)
234
235
236 def test_customdescriptors_with_abstractmethod(self):
237 class Descriptor:
238 def __init__(self, fget, fset=None):
239 self._fget = fget
240 self._fset = fset
241 def getter(self, callable):
242 return Descriptor(callable, self._fget)
243 def setter(self, callable):
244 return Descriptor(self._fget, callable)
245 @property
246 def __isabstractmethod__(self):
247 return (getattr(self._fget, '__isabstractmethod__', False)
248 or getattr(self._fset, '__isabstractmethod__', False))
249 class C(metaclass=abc.ABCMeta):
250 @Descriptor
251 @abc.abstractmethod
252 def foo(self): return 3
253 @foo.setter
254 @abc.abstractmethod
255 def foo(self, val): pass
256 self.assertRaises(TypeError, C)
257 class D(C):
258 @C.foo.getter
259 def foo(self): return super().foo
260 self.assertRaises(TypeError, D)
261 class E(D):
262 @D.foo.setter
263 def foo(self, val): pass
264 self.assertFalse(E.foo.__isabstractmethod__)
265
Benjamin Peterson970d1882010-10-02 17:55:47 +0000266 def test_metaclass_abc(self):
267 # Metaclasses can be ABCs, too.
268 class A(metaclass=abc.ABCMeta):
269 @abc.abstractmethod
270 def x(self):
271 pass
272 self.assertEqual(A.__abstractmethods__, {"x"})
273 class meta(type, A):
274 def x(self):
275 return 1
276 class C(metaclass=meta):
277 pass
278
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000279 def test_registration_basics(self):
280 class A(metaclass=abc.ABCMeta):
281 pass
Christian Heimes043d6f62008-01-07 17:19:16 +0000282 class B(object):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000283 pass
284 b = B()
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000285 self.assertFalse(issubclass(B, A))
286 self.assertFalse(issubclass(B, (A,)))
Ezio Melottie9615932010-01-24 19:26:24 +0000287 self.assertNotIsInstance(b, A)
288 self.assertNotIsInstance(b, (A,))
Éric Araujo6c3787c2011-02-24 18:03:10 +0000289 B1 = A.register(B)
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000290 self.assertTrue(issubclass(B, A))
291 self.assertTrue(issubclass(B, (A,)))
Ezio Melottie9615932010-01-24 19:26:24 +0000292 self.assertIsInstance(b, A)
293 self.assertIsInstance(b, (A,))
Éric Araujo6c3787c2011-02-24 18:03:10 +0000294 self.assertIs(B1, B)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000295 class C(B):
296 pass
297 c = C()
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000298 self.assertTrue(issubclass(C, A))
299 self.assertTrue(issubclass(C, (A,)))
Ezio Melottie9615932010-01-24 19:26:24 +0000300 self.assertIsInstance(c, A)
301 self.assertIsInstance(c, (A,))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000302
Éric Araujo6c3787c2011-02-24 18:03:10 +0000303 def test_register_as_class_deco(self):
304 class A(metaclass=abc.ABCMeta):
305 pass
306 @A.register
307 class B(object):
308 pass
309 b = B()
310 self.assertTrue(issubclass(B, A))
311 self.assertTrue(issubclass(B, (A,)))
312 self.assertIsInstance(b, A)
313 self.assertIsInstance(b, (A,))
314 @A.register
315 class C(B):
316 pass
317 c = C()
318 self.assertTrue(issubclass(C, A))
319 self.assertTrue(issubclass(C, (A,)))
320 self.assertIsInstance(c, A)
321 self.assertIsInstance(c, (A,))
322 self.assertIs(C, A.register(C))
323
Christian Heimes68f5fbe2008-02-14 08:27:37 +0000324 def test_isinstance_invalidation(self):
325 class A(metaclass=abc.ABCMeta):
326 pass
327 class B:
328 pass
329 b = B()
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000330 self.assertFalse(isinstance(b, A))
331 self.assertFalse(isinstance(b, (A,)))
Ɓukasz Langaeadd8cf2013-05-25 18:41:50 +0200332 token_old = abc.get_cache_token()
Christian Heimes68f5fbe2008-02-14 08:27:37 +0000333 A.register(B)
Ɓukasz Langaeadd8cf2013-05-25 18:41:50 +0200334 token_new = abc.get_cache_token()
335 self.assertNotEqual(token_old, token_new)
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000336 self.assertTrue(isinstance(b, A))
337 self.assertTrue(isinstance(b, (A,)))
Christian Heimes68f5fbe2008-02-14 08:27:37 +0000338
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000339 def test_registration_builtins(self):
340 class A(metaclass=abc.ABCMeta):
341 pass
342 A.register(int)
Ezio Melottie9615932010-01-24 19:26:24 +0000343 self.assertIsInstance(42, A)
344 self.assertIsInstance(42, (A,))
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000345 self.assertTrue(issubclass(int, A))
346 self.assertTrue(issubclass(int, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000347 class B(A):
348 pass
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000349 B.register(str)
350 class C(str): pass
Ezio Melottie9615932010-01-24 19:26:24 +0000351 self.assertIsInstance("", A)
352 self.assertIsInstance("", (A,))
Benjamin Peterson83cd3b92010-08-17 01:07:53 +0000353 self.assertTrue(issubclass(str, A))
354 self.assertTrue(issubclass(str, (A,)))
355 self.assertTrue(issubclass(C, A))
356 self.assertTrue(issubclass(C, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000357
358 def test_registration_edge_cases(self):
359 class A(metaclass=abc.ABCMeta):
360 pass
361 A.register(A) # should pass silently
362 class A1(A):
363 pass
364 self.assertRaises(RuntimeError, A1.register, A) # cycles not allowed
Christian Heimes043d6f62008-01-07 17:19:16 +0000365 class B(object):
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000366 pass
367 A1.register(B) # ok
368 A1.register(B) # should pass silently
369 class C(A):
370 pass
371 A.register(C) # should pass silently
372 self.assertRaises(RuntimeError, C.register, A) # cycles not allowed
373 C.register(B) # ok
374
Benjamin Petersond6326642010-01-27 02:25:58 +0000375 def test_register_non_class(self):
376 class A(metaclass=abc.ABCMeta):
377 pass
Ezio Melottied3a7d22010-12-01 02:32:32 +0000378 self.assertRaisesRegex(TypeError, "Can only register classes",
379 A.register, 4)
Benjamin Petersond6326642010-01-27 02:25:58 +0000380
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000381 def test_registration_transitiveness(self):
382 class A(metaclass=abc.ABCMeta):
383 pass
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000384 self.assertTrue(issubclass(A, A))
385 self.assertTrue(issubclass(A, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000386 class B(metaclass=abc.ABCMeta):
387 pass
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000388 self.assertFalse(issubclass(A, B))
389 self.assertFalse(issubclass(A, (B,)))
390 self.assertFalse(issubclass(B, A))
391 self.assertFalse(issubclass(B, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000392 class C(metaclass=abc.ABCMeta):
393 pass
394 A.register(B)
395 class B1(B):
396 pass
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000397 self.assertTrue(issubclass(B1, A))
398 self.assertTrue(issubclass(B1, (A,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000399 class C1(C):
400 pass
401 B1.register(C1)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000402 self.assertFalse(issubclass(C, B))
403 self.assertFalse(issubclass(C, (B,)))
404 self.assertFalse(issubclass(C, B1))
405 self.assertFalse(issubclass(C, (B1,)))
406 self.assertTrue(issubclass(C1, A))
407 self.assertTrue(issubclass(C1, (A,)))
408 self.assertTrue(issubclass(C1, B))
409 self.assertTrue(issubclass(C1, (B,)))
410 self.assertTrue(issubclass(C1, B1))
411 self.assertTrue(issubclass(C1, (B1,)))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000412 C1.register(int)
413 class MyInt(int):
414 pass
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000415 self.assertTrue(issubclass(MyInt, A))
416 self.assertTrue(issubclass(MyInt, (A,)))
Ezio Melottie9615932010-01-24 19:26:24 +0000417 self.assertIsInstance(42, A)
418 self.assertIsInstance(42, (A,))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000419
Guido van Rossum894d35e2007-09-11 20:42:30 +0000420 def test_all_new_methods_are_called(self):
421 class A(metaclass=abc.ABCMeta):
422 pass
Christian Heimes043d6f62008-01-07 17:19:16 +0000423 class B(object):
Guido van Rossum894d35e2007-09-11 20:42:30 +0000424 counter = 0
425 def __new__(cls):
426 B.counter += 1
427 return super().__new__(cls)
428 class C(A, B):
429 pass
430 self.assertEqual(B.counter, 0)
431 C()
432 self.assertEqual(B.counter, 1)
433
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000434
435def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000436 support.run_unittest(TestABC)
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000437
438
439if __name__ == "__main__":
440 unittest.main()