|  | # Test case for property | 
|  | # more tests are in test_descr | 
|  |  | 
|  | import sys | 
|  | import unittest | 
|  | from test import support | 
|  |  | 
|  | 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') | 
|  |  | 
|  | @support.refcount_test | 
|  | def test_refleaks_in___init__(self): | 
|  | gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount') | 
|  | fake_prop = property('fget', 'fset', 'fdel', 'doc') | 
|  | refs_before = gettotalrefcount() | 
|  | for i in range(100): | 
|  | fake_prop.__init__('fget', 'fset', 'fdel', 'doc') | 
|  | self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10) | 
|  |  | 
|  |  | 
|  | # 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() |