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