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