test_abc.py 7.84 KB
Newer Older
1 2 3 4 5
# Copyright 2007 Google, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.

"""Unit tests for abc.py."""

6
import unittest, weakref
7 8 9
from test import test_support

import abc
10
from inspect import isabstract
11 12 13 14 15 16 17


class TestABC(unittest.TestCase):

    def test_abstractmethod_basics(self):
        @abc.abstractmethod
        def foo(self): pass
18
        self.assertTrue(foo.__isabstractmethod__)
19
        def bar(self): pass
20
        self.assertFalse(hasattr(bar, "__isabstractmethod__"))
21 22 23 24

    def test_abstractproperty_basics(self):
        @abc.abstractproperty
        def foo(self): pass
25
        self.assertTrue(foo.__isabstractmethod__)
26
        def bar(self): pass
27
        self.assertFalse(hasattr(bar, "__isabstractmethod__"))
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

        class C:
            __metaclass__ = abc.ABCMeta
            @abc.abstractproperty
            def foo(self): return 3
        class D(C):
            @property
            def foo(self): return super(D, self).foo
        self.assertEqual(D().foo, 3)

    def test_abstractmethod_integration(self):
        for abstractthing in [abc.abstractmethod, abc.abstractproperty]:
            class C:
                __metaclass__ = abc.ABCMeta
                @abstractthing
                def foo(self): pass  # abstract
                def bar(self): pass  # concrete
            self.assertEqual(C.__abstractmethods__, set(["foo"]))
            self.assertRaises(TypeError, C)  # because foo is abstract
47
            self.assertTrue(isabstract(C))
48 49 50 51
            class D(C):
                def bar(self): pass  # concrete override of concrete
            self.assertEqual(D.__abstractmethods__, set(["foo"]))
            self.assertRaises(TypeError, D)  # because foo is still abstract
52
            self.assertTrue(isabstract(D))
53 54 55 56
            class E(D):
                def foo(self): pass
            self.assertEqual(E.__abstractmethods__, set())
            E()  # now foo is concrete, too
57
            self.assertFalse(isabstract(E))
58 59 60 61 62
            class F(E):
                @abstractthing
                def bar(self): pass  # abstract override of concrete
            self.assertEqual(F.__abstractmethods__, set(["bar"]))
            self.assertRaises(TypeError, F)  # because bar is abstract now
63
            self.assertTrue(isabstract(F))
64

65 66 67 68 69 70 71 72
    def test_subclass_oldstyle_class(self):
        class A:
            __metaclass__ = abc.ABCMeta
        class OldstyleClass:
            pass
        self.assertFalse(issubclass(OldstyleClass, A))
        self.assertFalse(issubclass(A, OldstyleClass))

73 74 75 76 77 78 79
    def test_type_has_no_abstractmethods(self):
        # type pretends not to have __abstractmethods__.
        self.assertRaises(AttributeError, getattr, type, "__abstractmethods__")
        class meta(type):
            pass
        self.assertRaises(AttributeError, getattr, meta, "__abstractmethods__")

80 81 82 83 84 85 86 87 88 89 90
    def test_isinstance_class(self):
        class A:
            __metaclass__ = abc.ABCMeta
        class OldstyleClass:
            pass
        self.assertFalse(isinstance(OldstyleClass, A))
        self.assertTrue(isinstance(OldstyleClass, type(OldstyleClass)))
        self.assertFalse(isinstance(A, OldstyleClass))
        # This raises a recursion depth error, but is low-priority:
        # self.assertTrue(isinstance(A, abc.ABCMeta))

91 92 93
    def test_registration_basics(self):
        class A:
            __metaclass__ = abc.ABCMeta
94
        class B(object):
95 96
            pass
        b = B()
97 98
        self.assertFalse(issubclass(B, A))
        self.assertFalse(issubclass(B, (A,)))
99 100
        self.assertNotIsInstance(b, A)
        self.assertNotIsInstance(b, (A,))
101
        A.register(B)
102 103
        self.assertTrue(issubclass(B, A))
        self.assertTrue(issubclass(B, (A,)))
104 105
        self.assertIsInstance(b, A)
        self.assertIsInstance(b, (A,))
106 107 108
        class C(B):
            pass
        c = C()
109 110
        self.assertTrue(issubclass(C, A))
        self.assertTrue(issubclass(C, (A,)))
111 112
        self.assertIsInstance(c, A)
        self.assertIsInstance(c, (A,))
113

114 115 116 117 118 119
    def test_isinstance_invalidation(self):
        class A:
            __metaclass__ = abc.ABCMeta
        class B(object):
            pass
        b = B()
120 121
        self.assertFalse(isinstance(b, A))
        self.assertFalse(isinstance(b, (A,)))
122
        A.register(B)
123 124
        self.assertTrue(isinstance(b, A))
        self.assertTrue(isinstance(b, (A,)))
125

126 127 128 129
    def test_registration_builtins(self):
        class A:
            __metaclass__ = abc.ABCMeta
        A.register(int)
130 131
        self.assertIsInstance(42, A)
        self.assertIsInstance(42, (A,))
132 133
        self.assertTrue(issubclass(int, A))
        self.assertTrue(issubclass(int, (A,)))
134 135 136
        class B(A):
            pass
        B.register(basestring)
137 138
        self.assertIsInstance("", A)
        self.assertIsInstance("", (A,))
139 140
        self.assertTrue(issubclass(str, A))
        self.assertTrue(issubclass(str, (A,)))
141 142 143 144 145 146 147 148

    def test_registration_edge_cases(self):
        class A:
            __metaclass__ = abc.ABCMeta
        A.register(A)  # should pass silently
        class A1(A):
            pass
        self.assertRaises(RuntimeError, A1.register, A)  # cycles not allowed
149
        class B(object):
150 151 152 153 154 155 156 157 158
            pass
        A1.register(B)  # ok
        A1.register(B)  # should pass silently
        class C(A):
            pass
        A.register(C)  # should pass silently
        self.assertRaises(RuntimeError, C.register, A)  # cycles not allowed
        C.register(B)  # ok

159 160 161 162 163 164
    def test_register_non_class(self):
        class A(object):
            __metaclass__ = abc.ABCMeta
        self.assertRaisesRegexp(TypeError, "Can only register classes",
                                A.register, 4)

165 166 167
    def test_registration_transitiveness(self):
        class A:
            __metaclass__ = abc.ABCMeta
168 169
        self.assertTrue(issubclass(A, A))
        self.assertTrue(issubclass(A, (A,)))
170 171
        class B:
            __metaclass__ = abc.ABCMeta
172 173 174 175
        self.assertFalse(issubclass(A, B))
        self.assertFalse(issubclass(A, (B,)))
        self.assertFalse(issubclass(B, A))
        self.assertFalse(issubclass(B, (A,)))
176 177 178 179 180
        class C:
            __metaclass__ = abc.ABCMeta
        A.register(B)
        class B1(B):
            pass
181 182
        self.assertTrue(issubclass(B1, A))
        self.assertTrue(issubclass(B1, (A,)))
183 184 185
        class C1(C):
            pass
        B1.register(C1)
186 187 188 189 190 191 192 193 194 195
        self.assertFalse(issubclass(C, B))
        self.assertFalse(issubclass(C, (B,)))
        self.assertFalse(issubclass(C, B1))
        self.assertFalse(issubclass(C, (B1,)))
        self.assertTrue(issubclass(C1, A))
        self.assertTrue(issubclass(C1, (A,)))
        self.assertTrue(issubclass(C1, B))
        self.assertTrue(issubclass(C1, (B,)))
        self.assertTrue(issubclass(C1, B1))
        self.assertTrue(issubclass(C1, (B1,)))
196 197 198
        C1.register(int)
        class MyInt(int):
            pass
199 200
        self.assertTrue(issubclass(MyInt, A))
        self.assertTrue(issubclass(MyInt, (A,)))
201 202
        self.assertIsInstance(42, A)
        self.assertIsInstance(42, (A,))
203

204 205 206
    def test_all_new_methods_are_called(self):
        class A:
            __metaclass__ = abc.ABCMeta
207
        class B(object):
208 209 210 211 212 213 214 215 216 217
            counter = 0
            def __new__(cls):
                B.counter += 1
                return super(B, cls).__new__(cls)
        class C(A, B):
            pass
        self.assertEqual(B.counter, 0)
        C()
        self.assertEqual(B.counter, 1)

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    def test_cache_leak(self):
        # See issue #2521.
        class A(object):
            __metaclass__ = abc.ABCMeta
            @abc.abstractmethod
            def f(self):
                pass
        class C(A):
            def f(self):
                A.f(self)
        r = weakref.ref(C)
        # Trigger cache.
        C().f()
        del C
        test_support.gc_collect()
        self.assertEqual(r(), None)
234 235 236 237 238 239 240

def test_main():
    test_support.run_unittest(TestABC)


if __name__ == "__main__":
    unittest.main()