14adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Test case for property
24adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# more tests are in test_descr
34adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
44adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport sys
54adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoimport unittest
64adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom test.test_support import run_unittest
74adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
84adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertyBase(Exception):
94adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pass
104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertyGet(PropertyBase):
124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pass
134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertySet(PropertyBase):
154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pass
164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertyDel(PropertyBase):
184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    pass
194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass BaseClass(object):
214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self):
224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._spam = 5
234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @property
254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self):
264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """BaseClass.getter"""
274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._spam
284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @spam.setter
304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self, value):
314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._spam = value
324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @spam.deleter
344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self):
354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        del self._spam
364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass SubClass(BaseClass):
384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @BaseClass.spam.getter
404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self):
414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """SubClass.getter"""
424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise PropertyGet(self._spam)
434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @spam.setter
454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self, value):
464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise PropertySet(self._spam)
474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @spam.deleter
494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self):
504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        raise PropertyDel(self._spam)
514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertyDocBase(object):
534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    _spam = 1
544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def _get_spam(self):
554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._spam
564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    spam = property(_get_spam, doc="spam spam spam")
574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertyDocSub(PropertyDocBase):
594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @PropertyDocBase.spam.getter
604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self):
614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """The decorator does not use this doc string"""
624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return self._spam
634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertySubNewGetter(BaseClass):
654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @BaseClass.spam.getter
664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self):
674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """new docstring"""
684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return 5
694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertyNewGetter(object):
714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @property
724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self):
734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """original docstring"""
744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return 1
754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @spam.getter
764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def spam(self):
774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        """new docstring"""
784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        return 8
794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertyTests(unittest.TestCase):
814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_property_decorator_baseclass(self):
824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # see #1620
834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base = BaseClass()
844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(base.spam, 5)
854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(base._spam, 5)
864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base.spam = 10
874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(base.spam, 10)
884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(base._spam, 10)
894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        delattr(base, "spam")
904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertTrue(not hasattr(base, "spam"))
914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertTrue(not hasattr(base, "_spam"))
924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base.spam = 20
934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(base.spam, 20)
944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(base._spam, 20)
954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_property_decorator_subclass(self):
974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # see #1620
984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        sub = SubClass()
994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(PropertyGet, getattr, sub, "spam")
1004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(PropertySet, setattr, sub, "spam", None)
1014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertRaises(PropertyDel, delattr, sub, "spam")
1024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @unittest.skipIf(sys.flags.optimize >= 2,
1044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                     "Docstrings are omitted with -O2 and above")
1054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_property_decorator_subclass_doc(self):
1064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        sub = SubClass()
1074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(sub.__class__.spam.__doc__, "SubClass.getter")
1084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @unittest.skipIf(sys.flags.optimize >= 2,
1104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                     "Docstrings are omitted with -O2 and above")
1114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_property_decorator_baseclass_doc(self):
1124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base = BaseClass()
1134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(base.__class__.spam.__doc__, "BaseClass.getter")
1144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_property_decorator_doc(self):
1164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        base = PropertyDocBase()
1174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        sub = PropertyDocSub()
1184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(base.__class__.spam.__doc__, "spam spam spam")
1194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(sub.__class__.spam.__doc__, "spam spam spam")
1204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @unittest.skipIf(sys.flags.optimize >= 2,
1224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                     "Docstrings are omitted with -O2 and above")
1234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_property_getter_doc_override(self):
1244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        newgettersub = PropertySubNewGetter()
1254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(newgettersub.spam, 5)
1264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(newgettersub.__class__.spam.__doc__, "new docstring")
1274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        newgetter = PropertyNewGetter()
1284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(newgetter.spam, 8)
1294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(newgetter.__class__.spam.__doc__, "new docstring")
1304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Issue 5890: subclasses of property do not preserve method __doc__ strings
1334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertySub(property):
1344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """This is a subclass of property"""
1354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertySubSlots(property):
1374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    """This is a subclass of property that defines __slots__"""
1384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    __slots__ = ()
1394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass PropertySubclassTests(unittest.TestCase):
1414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_slots_docstring_copy_exception(self):
1434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        try:
1444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            class Foo(object):
1454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                @PropertySubSlots
1464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                def spam(self):
1474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    """Trying to copy this docstring will raise an exception"""
1484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                    return 1
1494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        except AttributeError:
1504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            pass
1514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        else:
1524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            raise Exception("AttributeError not raised")
1534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @unittest.skipIf(sys.flags.optimize >= 2,
1554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                     "Docstrings are omitted with -O2 and above")
1564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_docstring_copy(self):
1574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        class Foo(object):
1584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            @PropertySub
1594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            def spam(self):
1604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                """spam wrapped in property subclass"""
1614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                return 1
1624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(
1634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            Foo.spam.__doc__,
1644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            "spam wrapped in property subclass")
1654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @unittest.skipIf(sys.flags.optimize >= 2,
1674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                     "Docstrings are omitted with -O2 and above")
1684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_property_setter_copies_getter_docstring(self):
1694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        class Foo(object):
1704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            def __init__(self): self._spam = 1
1714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            @PropertySub
1724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            def spam(self):
1734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                """spam wrapped in property subclass"""
1744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                return self._spam
1754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            @spam.setter
1764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            def spam(self, value):
1774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                """this docstring is ignored"""
1784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                self._spam = value
1794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        foo = Foo()
1804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(foo.spam, 1)
1814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        foo.spam = 2
1824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(foo.spam, 2)
1834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(
1844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            Foo.spam.__doc__,
1854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            "spam wrapped in property subclass")
1864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        class FooSub(Foo):
1874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            @Foo.spam.setter
1884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            def spam(self, value):
1894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                """another ignored docstring"""
1904adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                self._spam = 'eggs'
1914adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        foosub = FooSub()
1924adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(foosub.spam, 1)
1934adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        foosub.spam = 7
1944adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(foosub.spam, 'eggs')
1954adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(
1964adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            FooSub.spam.__doc__,
1974adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            "spam wrapped in property subclass")
1984adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
1994adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    @unittest.skipIf(sys.flags.optimize >= 2,
2004adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                     "Docstrings are omitted with -O2 and above")
2014adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def test_property_new_getter_new_docstring(self):
2024adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2034adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        class Foo(object):
2044adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            @PropertySub
2054adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            def spam(self):
2064adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                """a docstring"""
2074adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                return 1
2084adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            @spam.getter
2094adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            def spam(self):
2104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                """a new docstring"""
2114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                return 2
2124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(Foo.spam.__doc__, "a new docstring")
2134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        class FooBase(object):
2144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            @PropertySub
2154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            def spam(self):
2164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                """a docstring"""
2174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                return 1
2184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        class Foo2(FooBase):
2194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            @FooBase.spam.getter
2204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            def spam(self):
2214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                """a new docstring"""
2224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                return 2
2234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.assertEqual(Foo.spam.__doc__, "a new docstring")
2244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef test_main():
2284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    run_unittest(PropertyTests, PropertySubclassTests)
2294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
2304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoif __name__ == '__main__':
2314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    test_main()
232