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

Python code coverage for Lib/test/test_dynamicclassattribute.py

#countcontent
1n/a# Test case for DynamicClassAttribute
2n/a# more tests are in test_descr
3n/a
4n/aimport abc
5n/aimport sys
6n/aimport unittest
7n/afrom types import DynamicClassAttribute
8n/a
9n/aclass PropertyBase(Exception):
10n/a pass
11n/a
12n/aclass PropertyGet(PropertyBase):
13n/a pass
14n/a
15n/aclass PropertySet(PropertyBase):
16n/a pass
17n/a
18n/aclass PropertyDel(PropertyBase):
19n/a pass
20n/a
21n/aclass BaseClass(object):
22n/a def __init__(self):
23n/a self._spam = 5
24n/a
25n/a @DynamicClassAttribute
26n/a def spam(self):
27n/a """BaseClass.getter"""
28n/a return self._spam
29n/a
30n/a @spam.setter
31n/a def spam(self, value):
32n/a self._spam = value
33n/a
34n/a @spam.deleter
35n/a def spam(self):
36n/a del self._spam
37n/a
38n/aclass SubClass(BaseClass):
39n/a
40n/a spam = BaseClass.__dict__['spam']
41n/a
42n/a @spam.getter
43n/a def spam(self):
44n/a """SubClass.getter"""
45n/a raise PropertyGet(self._spam)
46n/a
47n/a @spam.setter
48n/a def spam(self, value):
49n/a raise PropertySet(self._spam)
50n/a
51n/a @spam.deleter
52n/a def spam(self):
53n/a raise PropertyDel(self._spam)
54n/a
55n/aclass PropertyDocBase(object):
56n/a _spam = 1
57n/a def _get_spam(self):
58n/a return self._spam
59n/a spam = DynamicClassAttribute(_get_spam, doc="spam spam spam")
60n/a
61n/aclass PropertyDocSub(PropertyDocBase):
62n/a spam = PropertyDocBase.__dict__['spam']
63n/a @spam.getter
64n/a def spam(self):
65n/a """The decorator does not use this doc string"""
66n/a return self._spam
67n/a
68n/aclass PropertySubNewGetter(BaseClass):
69n/a spam = BaseClass.__dict__['spam']
70n/a @spam.getter
71n/a def spam(self):
72n/a """new docstring"""
73n/a return 5
74n/a
75n/aclass PropertyNewGetter(object):
76n/a @DynamicClassAttribute
77n/a def spam(self):
78n/a """original docstring"""
79n/a return 1
80n/a @spam.getter
81n/a def spam(self):
82n/a """new docstring"""
83n/a return 8
84n/a
85n/aclass ClassWithAbstractVirtualProperty(metaclass=abc.ABCMeta):
86n/a @DynamicClassAttribute
87n/a @abc.abstractmethod
88n/a def color():
89n/a pass
90n/a
91n/aclass ClassWithPropertyAbstractVirtual(metaclass=abc.ABCMeta):
92n/a @abc.abstractmethod
93n/a @DynamicClassAttribute
94n/a def color():
95n/a pass
96n/a
97n/aclass PropertyTests(unittest.TestCase):
98n/a def test_property_decorator_baseclass(self):
99n/a # see #1620
100n/a base = BaseClass()
101n/a self.assertEqual(base.spam, 5)
102n/a self.assertEqual(base._spam, 5)
103n/a base.spam = 10
104n/a self.assertEqual(base.spam, 10)
105n/a self.assertEqual(base._spam, 10)
106n/a delattr(base, "spam")
107n/a self.assertTrue(not hasattr(base, "spam"))
108n/a self.assertTrue(not hasattr(base, "_spam"))
109n/a base.spam = 20
110n/a self.assertEqual(base.spam, 20)
111n/a self.assertEqual(base._spam, 20)
112n/a
113n/a def test_property_decorator_subclass(self):
114n/a # see #1620
115n/a sub = SubClass()
116n/a self.assertRaises(PropertyGet, getattr, sub, "spam")
117n/a self.assertRaises(PropertySet, setattr, sub, "spam", None)
118n/a self.assertRaises(PropertyDel, delattr, sub, "spam")
119n/a
120n/a @unittest.skipIf(sys.flags.optimize >= 2,
121n/a "Docstrings are omitted with -O2 and above")
122n/a def test_property_decorator_subclass_doc(self):
123n/a sub = SubClass()
124n/a self.assertEqual(sub.__class__.__dict__['spam'].__doc__, "SubClass.getter")
125n/a
126n/a @unittest.skipIf(sys.flags.optimize >= 2,
127n/a "Docstrings are omitted with -O2 and above")
128n/a def test_property_decorator_baseclass_doc(self):
129n/a base = BaseClass()
130n/a self.assertEqual(base.__class__.__dict__['spam'].__doc__, "BaseClass.getter")
131n/a
132n/a def test_property_decorator_doc(self):
133n/a base = PropertyDocBase()
134n/a sub = PropertyDocSub()
135n/a self.assertEqual(base.__class__.__dict__['spam'].__doc__, "spam spam spam")
136n/a self.assertEqual(sub.__class__.__dict__['spam'].__doc__, "spam spam spam")
137n/a
138n/a @unittest.skipIf(sys.flags.optimize >= 2,
139n/a "Docstrings are omitted with -O2 and above")
140n/a def test_property_getter_doc_override(self):
141n/a newgettersub = PropertySubNewGetter()
142n/a self.assertEqual(newgettersub.spam, 5)
143n/a self.assertEqual(newgettersub.__class__.__dict__['spam'].__doc__, "new docstring")
144n/a newgetter = PropertyNewGetter()
145n/a self.assertEqual(newgetter.spam, 8)
146n/a self.assertEqual(newgetter.__class__.__dict__['spam'].__doc__, "new docstring")
147n/a
148n/a def test_property___isabstractmethod__descriptor(self):
149n/a for val in (True, False, [], [1], '', '1'):
150n/a class C(object):
151n/a def foo(self):
152n/a pass
153n/a foo.__isabstractmethod__ = val
154n/a foo = DynamicClassAttribute(foo)
155n/a self.assertIs(C.__dict__['foo'].__isabstractmethod__, bool(val))
156n/a
157n/a # check that the DynamicClassAttribute's __isabstractmethod__ descriptor does the
158n/a # right thing when presented with a value that fails truth testing:
159n/a class NotBool(object):
160n/a def __bool__(self):
161n/a raise ValueError()
162n/a __len__ = __bool__
163n/a with self.assertRaises(ValueError):
164n/a class C(object):
165n/a def foo(self):
166n/a pass
167n/a foo.__isabstractmethod__ = NotBool()
168n/a foo = DynamicClassAttribute(foo)
169n/a
170n/a def test_abstract_virtual(self):
171n/a self.assertRaises(TypeError, ClassWithAbstractVirtualProperty)
172n/a self.assertRaises(TypeError, ClassWithPropertyAbstractVirtual)
173n/a class APV(ClassWithPropertyAbstractVirtual):
174n/a pass
175n/a self.assertRaises(TypeError, APV)
176n/a class AVP(ClassWithAbstractVirtualProperty):
177n/a pass
178n/a self.assertRaises(TypeError, AVP)
179n/a class Okay1(ClassWithAbstractVirtualProperty):
180n/a @DynamicClassAttribute
181n/a def color(self):
182n/a return self._color
183n/a def __init__(self):
184n/a self._color = 'cyan'
185n/a with self.assertRaises(AttributeError):
186n/a Okay1.color
187n/a self.assertEqual(Okay1().color, 'cyan')
188n/a class Okay2(ClassWithAbstractVirtualProperty):
189n/a @DynamicClassAttribute
190n/a def color(self):
191n/a return self._color
192n/a def __init__(self):
193n/a self._color = 'magenta'
194n/a with self.assertRaises(AttributeError):
195n/a Okay2.color
196n/a self.assertEqual(Okay2().color, 'magenta')
197n/a
198n/a
199n/a# Issue 5890: subclasses of DynamicClassAttribute do not preserve method __doc__ strings
200n/aclass PropertySub(DynamicClassAttribute):
201n/a """This is a subclass of DynamicClassAttribute"""
202n/a
203n/aclass PropertySubSlots(DynamicClassAttribute):
204n/a """This is a subclass of DynamicClassAttribute that defines __slots__"""
205n/a __slots__ = ()
206n/a
207n/aclass PropertySubclassTests(unittest.TestCase):
208n/a
209n/a @unittest.skipIf(hasattr(PropertySubSlots, '__doc__'),
210n/a "__doc__ is already present, __slots__ will have no effect")
211n/a def test_slots_docstring_copy_exception(self):
212n/a try:
213n/a class Foo(object):
214n/a @PropertySubSlots
215n/a def spam(self):
216n/a """Trying to copy this docstring will raise an exception"""
217n/a return 1
218n/a print('\n',spam.__doc__)
219n/a except AttributeError:
220n/a pass
221n/a else:
222n/a raise Exception("AttributeError not raised")
223n/a
224n/a @unittest.skipIf(sys.flags.optimize >= 2,
225n/a "Docstrings are omitted with -O2 and above")
226n/a def test_docstring_copy(self):
227n/a class Foo(object):
228n/a @PropertySub
229n/a def spam(self):
230n/a """spam wrapped in DynamicClassAttribute subclass"""
231n/a return 1
232n/a self.assertEqual(
233n/a Foo.__dict__['spam'].__doc__,
234n/a "spam wrapped in DynamicClassAttribute subclass")
235n/a
236n/a @unittest.skipIf(sys.flags.optimize >= 2,
237n/a "Docstrings are omitted with -O2 and above")
238n/a def test_property_setter_copies_getter_docstring(self):
239n/a class Foo(object):
240n/a def __init__(self): self._spam = 1
241n/a @PropertySub
242n/a def spam(self):
243n/a """spam wrapped in DynamicClassAttribute subclass"""
244n/a return self._spam
245n/a @spam.setter
246n/a def spam(self, value):
247n/a """this docstring is ignored"""
248n/a self._spam = value
249n/a foo = Foo()
250n/a self.assertEqual(foo.spam, 1)
251n/a foo.spam = 2
252n/a self.assertEqual(foo.spam, 2)
253n/a self.assertEqual(
254n/a Foo.__dict__['spam'].__doc__,
255n/a "spam wrapped in DynamicClassAttribute subclass")
256n/a class FooSub(Foo):
257n/a spam = Foo.__dict__['spam']
258n/a @spam.setter
259n/a def spam(self, value):
260n/a """another ignored docstring"""
261n/a self._spam = 'eggs'
262n/a foosub = FooSub()
263n/a self.assertEqual(foosub.spam, 1)
264n/a foosub.spam = 7
265n/a self.assertEqual(foosub.spam, 'eggs')
266n/a self.assertEqual(
267n/a FooSub.__dict__['spam'].__doc__,
268n/a "spam wrapped in DynamicClassAttribute subclass")
269n/a
270n/a @unittest.skipIf(sys.flags.optimize >= 2,
271n/a "Docstrings are omitted with -O2 and above")
272n/a def test_property_new_getter_new_docstring(self):
273n/a
274n/a class Foo(object):
275n/a @PropertySub
276n/a def spam(self):
277n/a """a docstring"""
278n/a return 1
279n/a @spam.getter
280n/a def spam(self):
281n/a """a new docstring"""
282n/a return 2
283n/a self.assertEqual(Foo.__dict__['spam'].__doc__, "a new docstring")
284n/a class FooBase(object):
285n/a @PropertySub
286n/a def spam(self):
287n/a """a docstring"""
288n/a return 1
289n/a class Foo2(FooBase):
290n/a spam = FooBase.__dict__['spam']
291n/a @spam.getter
292n/a def spam(self):
293n/a """a new docstring"""
294n/a return 2
295n/a self.assertEqual(Foo.__dict__['spam'].__doc__, "a new docstring")
296n/a
297n/a
298n/a
299n/aif __name__ == '__main__':
300n/a unittest.main()