| # 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__ |
| |
| @unittest.skipIf(sys.flags.optimize >= 2, |
| "Docstrings are omitted with -O2 and above") |
| def test_property_builtin_doc_writable(self): |
| p = property(doc='basic') |
| self.assertEqual(p.__doc__, 'basic') |
| p.__doc__ = 'extended' |
| self.assertEqual(p.__doc__, 'extended') |
| |
| @unittest.skipIf(sys.flags.optimize >= 2, |
| "Docstrings are omitted with -O2 and above") |
| def test_property_decorator_doc_writable(self): |
| class PropertyWritableDoc(object): |
| |
| @property |
| def spam(self): |
| """Eggs""" |
| return "eggs" |
| |
| sub = PropertyWritableDoc() |
| self.assertEqual(sub.__class__.spam.__doc__, 'Eggs') |
| sub.__class__.spam.__doc__ = 'Spam' |
| self.assertEqual(sub.__class__.spam.__doc__, 'Spam') |
| |
| # 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() |