# Test case for property # more tests are in test_descr import sys import unittest class PropertyBase(Exception): pass class PropertyGet(PropertyBase): pass class PropertySet(PropertyBase): pass class PropertyDel(PropertyBase): pass class BaseClass(object): def __init__(self): self._spam = 5 @property def spam(self): """BaseClass.getter""" return self._spam @spam.setter def spam(self, value): self._spam = value @spam.deleter def spam(self): del self._spam class SubClass(BaseClass): @BaseClass.spam.getter def spam(self): """SubClass.getter""" raise PropertyGet(self._spam) @spam.setter def spam(self, value): raise PropertySet(self._spam) @spam.deleter def spam(self): raise PropertyDel(self._spam) class PropertyDocBase(object): _spam = 1 def _get_spam(self): return self._spam spam = property(_get_spam, doc="spam spam spam") class PropertyDocSub(PropertyDocBase): @PropertyDocBase.spam.getter def spam(self): """The decorator does not use this doc string""" return self._spam class PropertySubNewGetter(BaseClass): @BaseClass.spam.getter def spam(self): """new docstring""" return 5 class PropertyNewGetter(object): @property def spam(self): """original docstring""" return 1 @spam.getter def spam(self): """new docstring""" return 8 class PropertyTests(unittest.TestCase): def test_property_decorator_baseclass(self): # see #1620 base = BaseClass() self.assertEqual(base.spam, 5) self.assertEqual(base._spam, 5) base.spam = 10 self.assertEqual(base.spam, 10) self.assertEqual(base._spam, 10) delattr(base, "spam") self.assertTrue(not hasattr(base, "spam")) self.assertTrue(not hasattr(base, "_spam")) base.spam = 20 self.assertEqual(base.spam, 20) self.assertEqual(base._spam, 20) def test_property_decorator_subclass(self): # see #1620 sub = SubClass() self.assertRaises(PropertyGet, getattr, sub, "spam") self.assertRaises(PropertySet, setattr, sub, "spam", None) self.assertRaises(PropertyDel, delattr, sub, "spam") @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") def test_property_decorator_subclass_doc(self): sub = SubClass() self.assertEqual(sub.__class__.spam.__doc__, "SubClass.getter") @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") def test_property_decorator_baseclass_doc(self): base = BaseClass() self.assertEqual(base.__class__.spam.__doc__, "BaseClass.getter") def test_property_decorator_doc(self): base = PropertyDocBase() sub = PropertyDocSub() self.assertEqual(base.__class__.spam.__doc__, "spam spam spam") self.assertEqual(sub.__class__.spam.__doc__, "spam spam spam") @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") def test_property_getter_doc_override(self): newgettersub = PropertySubNewGetter() self.assertEqual(newgettersub.spam, 5) self.assertEqual(newgettersub.__class__.spam.__doc__, "new docstring") newgetter = PropertyNewGetter() self.assertEqual(newgetter.spam, 8) self.assertEqual(newgetter.__class__.spam.__doc__, "new docstring") def test_property___isabstractmethod__descriptor(self): for val in (True, False, [], [1], '', '1'): class C(object): def foo(self): pass foo.__isabstractmethod__ = val foo = property(foo) self.assertIs(C.foo.__isabstractmethod__, bool(val)) # check that the property's __isabstractmethod__ descriptor does the # right thing when presented with a value that fails truth testing: class NotBool(object): def __bool__(self): raise ValueError() __len__ = __bool__ with self.assertRaises(ValueError): class C(object): def foo(self): pass foo.__isabstractmethod__ = NotBool() foo = property(foo) C.foo.__isabstractmethod__ # Issue 5890: subclasses of property do not preserve method __doc__ strings class PropertySub(property): """This is a subclass of property""" class PropertySubSlots(property): """This is a subclass of property that defines __slots__""" __slots__ = () class PropertySubclassTests(unittest.TestCase): def test_slots_docstring_copy_exception(self): try: class Foo(object): @PropertySubSlots def spam(self): """Trying to copy this docstring will raise an exception""" return 1 except AttributeError: pass else: raise Exception("AttributeError not raised") @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") def test_docstring_copy(self): class Foo(object): @PropertySub def spam(self): """spam wrapped in property subclass""" return 1 self.assertEqual( Foo.spam.__doc__, "spam wrapped in property subclass") @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") def test_property_setter_copies_getter_docstring(self): class Foo(object): def __init__(self): self._spam = 1 @PropertySub def spam(self): """spam wrapped in property subclass""" return self._spam @spam.setter def spam(self, value): """this docstring is ignored""" self._spam = value foo = Foo() self.assertEqual(foo.spam, 1) foo.spam = 2 self.assertEqual(foo.spam, 2) self.assertEqual( Foo.spam.__doc__, "spam wrapped in property subclass") class FooSub(Foo): @Foo.spam.setter def spam(self, value): """another ignored docstring""" self._spam = 'eggs' foosub = FooSub() self.assertEqual(foosub.spam, 1) foosub.spam = 7 self.assertEqual(foosub.spam, 'eggs') self.assertEqual( FooSub.spam.__doc__, "spam wrapped in property subclass") @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") def test_property_new_getter_new_docstring(self): class Foo(object): @PropertySub def spam(self): """a docstring""" return 1 @spam.getter def spam(self): """a new docstring""" return 2 self.assertEqual(Foo.spam.__doc__, "a new docstring") class FooBase(object): @PropertySub def spam(self): """a docstring""" return 1 class Foo2(FooBase): @FooBase.spam.getter def spam(self): """a new docstring""" return 2 self.assertEqual(Foo.spam.__doc__, "a new docstring") if __name__ == '__main__': unittest.main()