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