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