ยปCore Development>Code coverage>Lib/test/test_isinstance.py

Python code coverage for Lib/test/test_isinstance.py

#countcontent
1n/a# Tests some corner cases with isinstance() and issubclass(). While these
2n/a# tests use new style classes and properties, they actually do whitebox
3n/a# testing of error conditions uncovered when using extension types.
4n/a
5n/aimport unittest
6n/aimport sys
7n/a
8n/a
9n/a
10n/aclass TestIsInstanceExceptions(unittest.TestCase):
11n/a # Test to make sure that an AttributeError when accessing the instance's
12n/a # class's bases is masked. This was actually a bug in Python 2.2 and
13n/a # 2.2.1 where the exception wasn't caught but it also wasn't being cleared
14n/a # (leading to an "undetected error" in the debug build). Set up is,
15n/a # isinstance(inst, cls) where:
16n/a #
17n/a # - cls isn't a type, or a tuple
18n/a # - cls has a __bases__ attribute
19n/a # - inst has a __class__ attribute
20n/a # - inst.__class__ as no __bases__ attribute
21n/a #
22n/a # Sounds complicated, I know, but this mimics a situation where an
23n/a # extension type raises an AttributeError when its __bases__ attribute is
24n/a # gotten. In that case, isinstance() should return False.
25n/a def test_class_has_no_bases(self):
26n/a class I(object):
27n/a def getclass(self):
28n/a # This must return an object that has no __bases__ attribute
29n/a return None
30n/a __class__ = property(getclass)
31n/a
32n/a class C(object):
33n/a def getbases(self):
34n/a return ()
35n/a __bases__ = property(getbases)
36n/a
37n/a self.assertEqual(False, isinstance(I(), C()))
38n/a
39n/a # Like above except that inst.__class__.__bases__ raises an exception
40n/a # other than AttributeError
41n/a def test_bases_raises_other_than_attribute_error(self):
42n/a class E(object):
43n/a def getbases(self):
44n/a raise RuntimeError
45n/a __bases__ = property(getbases)
46n/a
47n/a class I(object):
48n/a def getclass(self):
49n/a return E()
50n/a __class__ = property(getclass)
51n/a
52n/a class C(object):
53n/a def getbases(self):
54n/a return ()
55n/a __bases__ = property(getbases)
56n/a
57n/a self.assertRaises(RuntimeError, isinstance, I(), C())
58n/a
59n/a # Here's a situation where getattr(cls, '__bases__') raises an exception.
60n/a # If that exception is not AttributeError, it should not get masked
61n/a def test_dont_mask_non_attribute_error(self):
62n/a class I: pass
63n/a
64n/a class C(object):
65n/a def getbases(self):
66n/a raise RuntimeError
67n/a __bases__ = property(getbases)
68n/a
69n/a self.assertRaises(RuntimeError, isinstance, I(), C())
70n/a
71n/a # Like above, except that getattr(cls, '__bases__') raises an
72n/a # AttributeError, which /should/ get masked as a TypeError
73n/a def test_mask_attribute_error(self):
74n/a class I: pass
75n/a
76n/a class C(object):
77n/a def getbases(self):
78n/a raise AttributeError
79n/a __bases__ = property(getbases)
80n/a
81n/a self.assertRaises(TypeError, isinstance, I(), C())
82n/a
83n/a # check that we don't mask non AttributeErrors
84n/a # see: http://bugs.python.org/issue1574217
85n/a def test_isinstance_dont_mask_non_attribute_error(self):
86n/a class C(object):
87n/a def getclass(self):
88n/a raise RuntimeError
89n/a __class__ = property(getclass)
90n/a
91n/a c = C()
92n/a self.assertRaises(RuntimeError, isinstance, c, bool)
93n/a
94n/a # test another code path
95n/a class D: pass
96n/a self.assertRaises(RuntimeError, isinstance, c, D)
97n/a
98n/a
99n/a# These tests are similar to above, but tickle certain code paths in
100n/a# issubclass() instead of isinstance() -- really PyObject_IsSubclass()
101n/a# vs. PyObject_IsInstance().
102n/aclass TestIsSubclassExceptions(unittest.TestCase):
103n/a def test_dont_mask_non_attribute_error(self):
104n/a class C(object):
105n/a def getbases(self):
106n/a raise RuntimeError
107n/a __bases__ = property(getbases)
108n/a
109n/a class S(C): pass
110n/a
111n/a self.assertRaises(RuntimeError, issubclass, C(), S())
112n/a
113n/a def test_mask_attribute_error(self):
114n/a class C(object):
115n/a def getbases(self):
116n/a raise AttributeError
117n/a __bases__ = property(getbases)
118n/a
119n/a class S(C): pass
120n/a
121n/a self.assertRaises(TypeError, issubclass, C(), S())
122n/a
123n/a # Like above, but test the second branch, where the __bases__ of the
124n/a # second arg (the cls arg) is tested. This means the first arg must
125n/a # return a valid __bases__, and it's okay for it to be a normal --
126n/a # unrelated by inheritance -- class.
127n/a def test_dont_mask_non_attribute_error_in_cls_arg(self):
128n/a class B: pass
129n/a
130n/a class C(object):
131n/a def getbases(self):
132n/a raise RuntimeError
133n/a __bases__ = property(getbases)
134n/a
135n/a self.assertRaises(RuntimeError, issubclass, B, C())
136n/a
137n/a def test_mask_attribute_error_in_cls_arg(self):
138n/a class B: pass
139n/a
140n/a class C(object):
141n/a def getbases(self):
142n/a raise AttributeError
143n/a __bases__ = property(getbases)
144n/a
145n/a self.assertRaises(TypeError, issubclass, B, C())
146n/a
147n/a
148n/a
149n/a# meta classes for creating abstract classes and instances
150n/aclass AbstractClass(object):
151n/a def __init__(self, bases):
152n/a self.bases = bases
153n/a
154n/a def getbases(self):
155n/a return self.bases
156n/a __bases__ = property(getbases)
157n/a
158n/a def __call__(self):
159n/a return AbstractInstance(self)
160n/a
161n/aclass AbstractInstance(object):
162n/a def __init__(self, klass):
163n/a self.klass = klass
164n/a
165n/a def getclass(self):
166n/a return self.klass
167n/a __class__ = property(getclass)
168n/a
169n/a# abstract classes
170n/aAbstractSuper = AbstractClass(bases=())
171n/a
172n/aAbstractChild = AbstractClass(bases=(AbstractSuper,))
173n/a
174n/a# normal classes
175n/aclass Super:
176n/a pass
177n/a
178n/aclass Child(Super):
179n/a pass
180n/a
181n/a# new-style classes
182n/aclass NewSuper(object):
183n/a pass
184n/a
185n/aclass NewChild(NewSuper):
186n/a pass
187n/a
188n/a
189n/a
190n/aclass TestIsInstanceIsSubclass(unittest.TestCase):
191n/a # Tests to ensure that isinstance and issubclass work on abstract
192n/a # classes and instances. Before the 2.2 release, TypeErrors were
193n/a # raised when boolean values should have been returned. The bug was
194n/a # triggered by mixing 'normal' classes and instances were with
195n/a # 'abstract' classes and instances. This case tries to test all
196n/a # combinations.
197n/a
198n/a def test_isinstance_normal(self):
199n/a # normal instances
200n/a self.assertEqual(True, isinstance(Super(), Super))
201n/a self.assertEqual(False, isinstance(Super(), Child))
202n/a self.assertEqual(False, isinstance(Super(), AbstractSuper))
203n/a self.assertEqual(False, isinstance(Super(), AbstractChild))
204n/a
205n/a self.assertEqual(True, isinstance(Child(), Super))
206n/a self.assertEqual(False, isinstance(Child(), AbstractSuper))
207n/a
208n/a def test_isinstance_abstract(self):
209n/a # abstract instances
210n/a self.assertEqual(True, isinstance(AbstractSuper(), AbstractSuper))
211n/a self.assertEqual(False, isinstance(AbstractSuper(), AbstractChild))
212n/a self.assertEqual(False, isinstance(AbstractSuper(), Super))
213n/a self.assertEqual(False, isinstance(AbstractSuper(), Child))
214n/a
215n/a self.assertEqual(True, isinstance(AbstractChild(), AbstractChild))
216n/a self.assertEqual(True, isinstance(AbstractChild(), AbstractSuper))
217n/a self.assertEqual(False, isinstance(AbstractChild(), Super))
218n/a self.assertEqual(False, isinstance(AbstractChild(), Child))
219n/a
220n/a def test_subclass_normal(self):
221n/a # normal classes
222n/a self.assertEqual(True, issubclass(Super, Super))
223n/a self.assertEqual(False, issubclass(Super, AbstractSuper))
224n/a self.assertEqual(False, issubclass(Super, Child))
225n/a
226n/a self.assertEqual(True, issubclass(Child, Child))
227n/a self.assertEqual(True, issubclass(Child, Super))
228n/a self.assertEqual(False, issubclass(Child, AbstractSuper))
229n/a
230n/a def test_subclass_abstract(self):
231n/a # abstract classes
232n/a self.assertEqual(True, issubclass(AbstractSuper, AbstractSuper))
233n/a self.assertEqual(False, issubclass(AbstractSuper, AbstractChild))
234n/a self.assertEqual(False, issubclass(AbstractSuper, Child))
235n/a
236n/a self.assertEqual(True, issubclass(AbstractChild, AbstractChild))
237n/a self.assertEqual(True, issubclass(AbstractChild, AbstractSuper))
238n/a self.assertEqual(False, issubclass(AbstractChild, Super))
239n/a self.assertEqual(False, issubclass(AbstractChild, Child))
240n/a
241n/a def test_subclass_tuple(self):
242n/a # test with a tuple as the second argument classes
243n/a self.assertEqual(True, issubclass(Child, (Child,)))
244n/a self.assertEqual(True, issubclass(Child, (Super,)))
245n/a self.assertEqual(False, issubclass(Super, (Child,)))
246n/a self.assertEqual(True, issubclass(Super, (Child, Super)))
247n/a self.assertEqual(False, issubclass(Child, ()))
248n/a self.assertEqual(True, issubclass(Super, (Child, (Super,))))
249n/a
250n/a self.assertEqual(True, issubclass(NewChild, (NewChild,)))
251n/a self.assertEqual(True, issubclass(NewChild, (NewSuper,)))
252n/a self.assertEqual(False, issubclass(NewSuper, (NewChild,)))
253n/a self.assertEqual(True, issubclass(NewSuper, (NewChild, NewSuper)))
254n/a self.assertEqual(False, issubclass(NewChild, ()))
255n/a self.assertEqual(True, issubclass(NewSuper, (NewChild, (NewSuper,))))
256n/a
257n/a self.assertEqual(True, issubclass(int, (int, (float, int))))
258n/a self.assertEqual(True, issubclass(str, (str, (Child, NewChild, str))))
259n/a
260n/a def test_subclass_recursion_limit(self):
261n/a # make sure that issubclass raises RecursionError before the C stack is
262n/a # blown
263n/a self.assertRaises(RecursionError, blowstack, issubclass, str, str)
264n/a
265n/a def test_isinstance_recursion_limit(self):
266n/a # make sure that issubclass raises RecursionError before the C stack is
267n/a # blown
268n/a self.assertRaises(RecursionError, blowstack, isinstance, '', str)
269n/a
270n/adef blowstack(fxn, arg, compare_to):
271n/a # Make sure that calling isinstance with a deeply nested tuple for its
272n/a # argument will raise RecursionError eventually.
273n/a tuple_arg = (compare_to,)
274n/a for cnt in range(sys.getrecursionlimit()+5):
275n/a tuple_arg = (tuple_arg,)
276n/a fxn(arg, tuple_arg)
277n/a
278n/a
279n/aif __name__ == '__main__':
280n/a unittest.main()