# Test case for property | |
# more tests are in test_descr | |
import sys | |
import unittest | |
from test.test_support import run_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") | |
# 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") | |
def test_main(): | |
run_unittest(PropertyTests, PropertySubclassTests) | |
if __name__ == '__main__': | |
test_main() |