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 187# Issue 5890: subclasses of property do not preserve method __doc__ strings 188class PropertySub(property): 189 """This is a subclass of property""" 190 191class PropertySubSlots(property): 192 """This is a subclass of property that defines __slots__""" 193 __slots__ = () 194 195class PropertySubclassTests(unittest.TestCase): 196 197 def test_slots_docstring_copy_exception(self): 198 try: 199 class Foo(object): 200 @PropertySubSlots 201 def spam(self): 202 """Trying to copy this docstring will raise an exception""" 203 return 1 204 except AttributeError: 205 pass 206 else: 207 raise Exception("AttributeError not raised") 208 209 @unittest.skipIf(sys.flags.optimize >= 2, 210 "Docstrings are omitted with -O2 and above") 211 def test_docstring_copy(self): 212 class Foo(object): 213 @PropertySub 214 def spam(self): 215 """spam wrapped in property subclass""" 216 return 1 217 self.assertEqual( 218 Foo.spam.__doc__, 219 "spam wrapped in property subclass") 220 221 @unittest.skipIf(sys.flags.optimize >= 2, 222 "Docstrings are omitted with -O2 and above") 223 def test_property_setter_copies_getter_docstring(self): 224 class Foo(object): 225 def __init__(self): self._spam = 1 226 @PropertySub 227 def spam(self): 228 """spam wrapped in property subclass""" 229 return self._spam 230 @spam.setter 231 def spam(self, value): 232 """this docstring is ignored""" 233 self._spam = value 234 foo = Foo() 235 self.assertEqual(foo.spam, 1) 236 foo.spam = 2 237 self.assertEqual(foo.spam, 2) 238 self.assertEqual( 239 Foo.spam.__doc__, 240 "spam wrapped in property subclass") 241 class FooSub(Foo): 242 @Foo.spam.setter 243 def spam(self, value): 244 """another ignored docstring""" 245 self._spam = 'eggs' 246 foosub = FooSub() 247 self.assertEqual(foosub.spam, 1) 248 foosub.spam = 7 249 self.assertEqual(foosub.spam, 'eggs') 250 self.assertEqual( 251 FooSub.spam.__doc__, 252 "spam wrapped in property subclass") 253 254 @unittest.skipIf(sys.flags.optimize >= 2, 255 "Docstrings are omitted with -O2 and above") 256 def test_property_new_getter_new_docstring(self): 257 258 class Foo(object): 259 @PropertySub 260 def spam(self): 261 """a docstring""" 262 return 1 263 @spam.getter 264 def spam(self): 265 """a new docstring""" 266 return 2 267 self.assertEqual(Foo.spam.__doc__, "a new docstring") 268 class FooBase(object): 269 @PropertySub 270 def spam(self): 271 """a docstring""" 272 return 1 273 class Foo2(FooBase): 274 @FooBase.spam.getter 275 def spam(self): 276 """a new docstring""" 277 return 2 278 self.assertEqual(Foo.spam.__doc__, "a new docstring") 279 280 281 282if __name__ == '__main__': 283 unittest.main() 284