14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Test case for property
24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# more tests are in test_descr
34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport sys
54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport unittest
64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom test.test_support import run_unittest
74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertyBase(Exception):
94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pass
104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertyGet(PropertyBase):
124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pass
134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertySet(PropertyBase):
154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pass
164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertyDel(PropertyBase):
184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    pass
194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass BaseClass(object):
214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def __init__(self):
224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._spam = 5
234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @property
254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self):
264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """BaseClass.getter"""
274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return self._spam
284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @spam.setter
304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self, value):
314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self._spam = value
324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @spam.deleter
344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self):
354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        del self._spam
364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass SubClass(BaseClass):
384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @BaseClass.spam.getter
404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self):
414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """SubClass.getter"""
424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        raise PropertyGet(self._spam)
434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @spam.setter
454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self, value):
464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        raise PropertySet(self._spam)
474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @spam.deleter
494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self):
504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        raise PropertyDel(self._spam)
514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertyDocBase(object):
534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    _spam = 1
544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _get_spam(self):
554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return self._spam
564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    spam = property(_get_spam, doc="spam spam spam")
574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertyDocSub(PropertyDocBase):
594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @PropertyDocBase.spam.getter
604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self):
614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """The decorator does not use this doc string"""
624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return self._spam
634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertySubNewGetter(BaseClass):
654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @BaseClass.spam.getter
664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self):
674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """new docstring"""
684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 5
694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertyNewGetter(object):
714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @property
724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self):
734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """original docstring"""
744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 1
754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @spam.getter
764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def spam(self):
774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """new docstring"""
784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 8
794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertyTests(unittest.TestCase):
814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_property_decorator_baseclass(self):
824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # see #1620
834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        base = BaseClass()
844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(base.spam, 5)
854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(base._spam, 5)
864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        base.spam = 10
874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(base.spam, 10)
884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(base._spam, 10)
894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        delattr(base, "spam")
904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertTrue(not hasattr(base, "spam"))
914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertTrue(not hasattr(base, "_spam"))
924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        base.spam = 20
934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(base.spam, 20)
944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(base._spam, 20)
954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_property_decorator_subclass(self):
974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # see #1620
984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sub = SubClass()
994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertRaises(PropertyGet, getattr, sub, "spam")
1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertRaises(PropertySet, setattr, sub, "spam", None)
1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertRaises(PropertyDel, delattr, sub, "spam")
1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @unittest.skipIf(sys.flags.optimize >= 2,
1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                     "Docstrings are omitted with -O2 and above")
1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_property_decorator_subclass_doc(self):
1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sub = SubClass()
1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(sub.__class__.spam.__doc__, "SubClass.getter")
1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @unittest.skipIf(sys.flags.optimize >= 2,
1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                     "Docstrings are omitted with -O2 and above")
1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_property_decorator_baseclass_doc(self):
1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        base = BaseClass()
1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(base.__class__.spam.__doc__, "BaseClass.getter")
1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_property_decorator_doc(self):
1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        base = PropertyDocBase()
1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sub = PropertyDocSub()
1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(base.__class__.spam.__doc__, "spam spam spam")
1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(sub.__class__.spam.__doc__, "spam spam spam")
1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @unittest.skipIf(sys.flags.optimize >= 2,
1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                     "Docstrings are omitted with -O2 and above")
1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_property_getter_doc_override(self):
1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        newgettersub = PropertySubNewGetter()
1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(newgettersub.spam, 5)
1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(newgettersub.__class__.spam.__doc__, "new docstring")
1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        newgetter = PropertyNewGetter()
1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(newgetter.spam, 8)
1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(newgetter.__class__.spam.__doc__, "new docstring")
1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Issue 5890: subclasses of property do not preserve method __doc__ strings
1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertySub(property):
1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """This is a subclass of property"""
1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertySubSlots(property):
1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """This is a subclass of property that defines __slots__"""
1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    __slots__ = ()
1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass PropertySubclassTests(unittest.TestCase):
1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_slots_docstring_copy_exception(self):
1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        try:
1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            class Foo(object):
1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                @PropertySubSlots
1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                def spam(self):
1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    """Trying to copy this docstring will raise an exception"""
1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    return 1
1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        except AttributeError:
1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            pass
1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else:
1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            raise Exception("AttributeError not raised")
1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @unittest.skipIf(sys.flags.optimize >= 2,
1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                     "Docstrings are omitted with -O2 and above")
1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_docstring_copy(self):
1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        class Foo(object):
1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            @PropertySub
1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            def spam(self):
1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                """spam wrapped in property subclass"""
1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return 1
1624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(
1634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            Foo.spam.__doc__,
1644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            "spam wrapped in property subclass")
1654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @unittest.skipIf(sys.flags.optimize <= 2,
1674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                     "Docstrings are omitted with -O2 and above")
1684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_property_setter_copies_getter_docstring(self):
1694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        class Foo(object):
1704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            def __init__(self): self._spam = 1
1714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            @PropertySub
1724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            def spam(self):
1734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                """spam wrapped in property subclass"""
1744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return self._spam
1754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            @spam.setter
1764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            def spam(self, value):
1774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                """this docstring is ignored"""
1784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                self._spam = value
1794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        foo = Foo()
1804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(foo.spam, 1)
1814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        foo.spam = 2
1824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(foo.spam, 2)
1834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(
1844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            Foo.spam.__doc__,
1854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            "spam wrapped in property subclass")
1864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        class FooSub(Foo):
1874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            @Foo.spam.setter
1884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            def spam(self, value):
1894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                """another ignored docstring"""
1904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                self._spam = 'eggs'
1914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        foosub = FooSub()
1924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(foosub.spam, 1)
1934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        foosub.spam = 7
1944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(foosub.spam, 'eggs')
1954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(
1964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            FooSub.spam.__doc__,
1974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            "spam wrapped in property subclass")
1984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    @unittest.skipIf(sys.flags.optimize <= 2,
2004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                     "Docstrings are omitted with -O2 and above")
2014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def test_property_new_getter_new_docstring(self):
2024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        class Foo(object):
2044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            @PropertySub
2054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            def spam(self):
2064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                """a docstring"""
2074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return 1
2084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            @spam.getter
2094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            def spam(self):
2104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                """a new docstring"""
2114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return 2
2124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(Foo.spam.__doc__, "a new docstring")
2134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        class FooBase(object):
2144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            @PropertySub
2154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            def spam(self):
2164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                """a docstring"""
2174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return 1
2184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        class Foo2(FooBase):
2194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            @FooBase.spam.getter
2204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            def spam(self):
2214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                """a new docstring"""
2224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return 2
2234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.assertEqual(Foo.spam.__doc__, "a new docstring")
2244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_main():
2284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    run_unittest(PropertyTests, PropertySubclassTests)
2294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmif __name__ == '__main__':
2314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    test_main()
232