1 | # Copyright 2007 Google, Inc. All Rights Reserved.
|
---|
2 | # Licensed to PSF under a Contributor Agreement.
|
---|
3 |
|
---|
4 | """Unit tests for abc.py."""
|
---|
5 |
|
---|
6 | import unittest, weakref
|
---|
7 | from test import test_support
|
---|
8 |
|
---|
9 | import abc
|
---|
10 | from inspect import isabstract
|
---|
11 |
|
---|
12 |
|
---|
13 | class TestABC(unittest.TestCase):
|
---|
14 |
|
---|
15 | def test_abstractmethod_basics(self):
|
---|
16 | @abc.abstractmethod
|
---|
17 | def foo(self): pass
|
---|
18 | self.assertTrue(foo.__isabstractmethod__)
|
---|
19 | def bar(self): pass
|
---|
20 | self.assertFalse(hasattr(bar, "__isabstractmethod__"))
|
---|
21 |
|
---|
22 | def test_abstractproperty_basics(self):
|
---|
23 | @abc.abstractproperty
|
---|
24 | def foo(self): pass
|
---|
25 | self.assertTrue(foo.__isabstractmethod__)
|
---|
26 | def bar(self): pass
|
---|
27 | self.assertFalse(hasattr(bar, "__isabstractmethod__"))
|
---|
28 |
|
---|
29 | class C:
|
---|
30 | __metaclass__ = abc.ABCMeta
|
---|
31 | @abc.abstractproperty
|
---|
32 | def foo(self): return 3
|
---|
33 | class D(C):
|
---|
34 | @property
|
---|
35 | def foo(self): return super(D, self).foo
|
---|
36 | self.assertEqual(D().foo, 3)
|
---|
37 |
|
---|
38 | def test_abstractmethod_integration(self):
|
---|
39 | for abstractthing in [abc.abstractmethod, abc.abstractproperty]:
|
---|
40 | class C:
|
---|
41 | __metaclass__ = abc.ABCMeta
|
---|
42 | @abstractthing
|
---|
43 | def foo(self): pass # abstract
|
---|
44 | def bar(self): pass # concrete
|
---|
45 | self.assertEqual(C.__abstractmethods__, set(["foo"]))
|
---|
46 | self.assertRaises(TypeError, C) # because foo is abstract
|
---|
47 | self.assertTrue(isabstract(C))
|
---|
48 | class D(C):
|
---|
49 | def bar(self): pass # concrete override of concrete
|
---|
50 | self.assertEqual(D.__abstractmethods__, set(["foo"]))
|
---|
51 | self.assertRaises(TypeError, D) # because foo is still abstract
|
---|
52 | self.assertTrue(isabstract(D))
|
---|
53 | class E(D):
|
---|
54 | def foo(self): pass
|
---|
55 | self.assertEqual(E.__abstractmethods__, set())
|
---|
56 | E() # now foo is concrete, too
|
---|
57 | self.assertFalse(isabstract(E))
|
---|
58 | class F(E):
|
---|
59 | @abstractthing
|
---|
60 | def bar(self): pass # abstract override of concrete
|
---|
61 | self.assertEqual(F.__abstractmethods__, set(["bar"]))
|
---|
62 | self.assertRaises(TypeError, F) # because bar is abstract now
|
---|
63 | self.assertTrue(isabstract(F))
|
---|
64 |
|
---|
65 | def test_subclass_oldstyle_class(self):
|
---|
66 | class A:
|
---|
67 | __metaclass__ = abc.ABCMeta
|
---|
68 | class OldstyleClass:
|
---|
69 | pass
|
---|
70 | self.assertFalse(issubclass(OldstyleClass, A))
|
---|
71 | self.assertFalse(issubclass(A, OldstyleClass))
|
---|
72 |
|
---|
73 | def test_isinstance_class(self):
|
---|
74 | class A:
|
---|
75 | __metaclass__ = abc.ABCMeta
|
---|
76 | class OldstyleClass:
|
---|
77 | pass
|
---|
78 | self.assertFalse(isinstance(OldstyleClass, A))
|
---|
79 | self.assertTrue(isinstance(OldstyleClass, type(OldstyleClass)))
|
---|
80 | self.assertFalse(isinstance(A, OldstyleClass))
|
---|
81 | # This raises a recursion depth error, but is low-priority:
|
---|
82 | # self.assertTrue(isinstance(A, abc.ABCMeta))
|
---|
83 |
|
---|
84 | def test_registration_basics(self):
|
---|
85 | class A:
|
---|
86 | __metaclass__ = abc.ABCMeta
|
---|
87 | class B(object):
|
---|
88 | pass
|
---|
89 | b = B()
|
---|
90 | self.assertFalse(issubclass(B, A))
|
---|
91 | self.assertFalse(issubclass(B, (A,)))
|
---|
92 | self.assertNotIsInstance(b, A)
|
---|
93 | self.assertNotIsInstance(b, (A,))
|
---|
94 | A.register(B)
|
---|
95 | self.assertTrue(issubclass(B, A))
|
---|
96 | self.assertTrue(issubclass(B, (A,)))
|
---|
97 | self.assertIsInstance(b, A)
|
---|
98 | self.assertIsInstance(b, (A,))
|
---|
99 | class C(B):
|
---|
100 | pass
|
---|
101 | c = C()
|
---|
102 | self.assertTrue(issubclass(C, A))
|
---|
103 | self.assertTrue(issubclass(C, (A,)))
|
---|
104 | self.assertIsInstance(c, A)
|
---|
105 | self.assertIsInstance(c, (A,))
|
---|
106 |
|
---|
107 | def test_isinstance_invalidation(self):
|
---|
108 | class A:
|
---|
109 | __metaclass__ = abc.ABCMeta
|
---|
110 | class B(object):
|
---|
111 | pass
|
---|
112 | b = B()
|
---|
113 | self.assertFalse(isinstance(b, A))
|
---|
114 | self.assertFalse(isinstance(b, (A,)))
|
---|
115 | A.register(B)
|
---|
116 | self.assertTrue(isinstance(b, A))
|
---|
117 | self.assertTrue(isinstance(b, (A,)))
|
---|
118 |
|
---|
119 | def test_registration_builtins(self):
|
---|
120 | class A:
|
---|
121 | __metaclass__ = abc.ABCMeta
|
---|
122 | A.register(int)
|
---|
123 | self.assertIsInstance(42, A)
|
---|
124 | self.assertIsInstance(42, (A,))
|
---|
125 | self.assertTrue(issubclass(int, A))
|
---|
126 | self.assertTrue(issubclass(int, (A,)))
|
---|
127 | class B(A):
|
---|
128 | pass
|
---|
129 | B.register(basestring)
|
---|
130 | self.assertIsInstance("", A)
|
---|
131 | self.assertIsInstance("", (A,))
|
---|
132 | self.assertTrue(issubclass(str, A))
|
---|
133 | self.assertTrue(issubclass(str, (A,)))
|
---|
134 |
|
---|
135 | def test_registration_edge_cases(self):
|
---|
136 | class A:
|
---|
137 | __metaclass__ = abc.ABCMeta
|
---|
138 | A.register(A) # should pass silently
|
---|
139 | class A1(A):
|
---|
140 | pass
|
---|
141 | self.assertRaises(RuntimeError, A1.register, A) # cycles not allowed
|
---|
142 | class B(object):
|
---|
143 | pass
|
---|
144 | A1.register(B) # ok
|
---|
145 | A1.register(B) # should pass silently
|
---|
146 | class C(A):
|
---|
147 | pass
|
---|
148 | A.register(C) # should pass silently
|
---|
149 | self.assertRaises(RuntimeError, C.register, A) # cycles not allowed
|
---|
150 | C.register(B) # ok
|
---|
151 |
|
---|
152 | def test_register_non_class(self):
|
---|
153 | class A(object):
|
---|
154 | __metaclass__ = abc.ABCMeta
|
---|
155 | self.assertRaisesRegexp(TypeError, "Can only register classes",
|
---|
156 | A.register, 4)
|
---|
157 |
|
---|
158 | def test_registration_transitiveness(self):
|
---|
159 | class A:
|
---|
160 | __metaclass__ = abc.ABCMeta
|
---|
161 | self.assertTrue(issubclass(A, A))
|
---|
162 | self.assertTrue(issubclass(A, (A,)))
|
---|
163 | class B:
|
---|
164 | __metaclass__ = abc.ABCMeta
|
---|
165 | self.assertFalse(issubclass(A, B))
|
---|
166 | self.assertFalse(issubclass(A, (B,)))
|
---|
167 | self.assertFalse(issubclass(B, A))
|
---|
168 | self.assertFalse(issubclass(B, (A,)))
|
---|
169 | class C:
|
---|
170 | __metaclass__ = abc.ABCMeta
|
---|
171 | A.register(B)
|
---|
172 | class B1(B):
|
---|
173 | pass
|
---|
174 | self.assertTrue(issubclass(B1, A))
|
---|
175 | self.assertTrue(issubclass(B1, (A,)))
|
---|
176 | class C1(C):
|
---|
177 | pass
|
---|
178 | B1.register(C1)
|
---|
179 | self.assertFalse(issubclass(C, B))
|
---|
180 | self.assertFalse(issubclass(C, (B,)))
|
---|
181 | self.assertFalse(issubclass(C, B1))
|
---|
182 | self.assertFalse(issubclass(C, (B1,)))
|
---|
183 | self.assertTrue(issubclass(C1, A))
|
---|
184 | self.assertTrue(issubclass(C1, (A,)))
|
---|
185 | self.assertTrue(issubclass(C1, B))
|
---|
186 | self.assertTrue(issubclass(C1, (B,)))
|
---|
187 | self.assertTrue(issubclass(C1, B1))
|
---|
188 | self.assertTrue(issubclass(C1, (B1,)))
|
---|
189 | C1.register(int)
|
---|
190 | class MyInt(int):
|
---|
191 | pass
|
---|
192 | self.assertTrue(issubclass(MyInt, A))
|
---|
193 | self.assertTrue(issubclass(MyInt, (A,)))
|
---|
194 | self.assertIsInstance(42, A)
|
---|
195 | self.assertIsInstance(42, (A,))
|
---|
196 |
|
---|
197 | def test_all_new_methods_are_called(self):
|
---|
198 | class A:
|
---|
199 | __metaclass__ = abc.ABCMeta
|
---|
200 | class B(object):
|
---|
201 | counter = 0
|
---|
202 | def __new__(cls):
|
---|
203 | B.counter += 1
|
---|
204 | return super(B, cls).__new__(cls)
|
---|
205 | class C(A, B):
|
---|
206 | pass
|
---|
207 | self.assertEqual(B.counter, 0)
|
---|
208 | C()
|
---|
209 | self.assertEqual(B.counter, 1)
|
---|
210 |
|
---|
211 | def test_cache_leak(self):
|
---|
212 | # See issue #2521.
|
---|
213 | class A(object):
|
---|
214 | __metaclass__ = abc.ABCMeta
|
---|
215 | @abc.abstractmethod
|
---|
216 | def f(self):
|
---|
217 | pass
|
---|
218 | class C(A):
|
---|
219 | def f(self):
|
---|
220 | A.f(self)
|
---|
221 | r = weakref.ref(C)
|
---|
222 | # Trigger cache.
|
---|
223 | C().f()
|
---|
224 | del C
|
---|
225 | test_support.gc_collect()
|
---|
226 | self.assertEqual(r(), None)
|
---|
227 |
|
---|
228 | def test_main():
|
---|
229 | test_support.run_unittest(TestABC)
|
---|
230 |
|
---|
231 |
|
---|
232 | if __name__ == "__main__":
|
---|
233 | unittest.main()
|
---|