17db96d56Sopenharmony_ci# Test case for property
27db96d56Sopenharmony_ci# more tests are in test_descr
37db96d56Sopenharmony_ci
47db96d56Sopenharmony_ciimport sys
57db96d56Sopenharmony_ciimport unittest
67db96d56Sopenharmony_cifrom test import support
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ciclass PropertyBase(Exception):
97db96d56Sopenharmony_ci    pass
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ciclass PropertyGet(PropertyBase):
127db96d56Sopenharmony_ci    pass
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ciclass PropertySet(PropertyBase):
157db96d56Sopenharmony_ci    pass
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ciclass PropertyDel(PropertyBase):
187db96d56Sopenharmony_ci    pass
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ciclass BaseClass(object):
217db96d56Sopenharmony_ci    def __init__(self):
227db96d56Sopenharmony_ci        self._spam = 5
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ci    @property
257db96d56Sopenharmony_ci    def spam(self):
267db96d56Sopenharmony_ci        """BaseClass.getter"""
277db96d56Sopenharmony_ci        return self._spam
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci    @spam.setter
307db96d56Sopenharmony_ci    def spam(self, value):
317db96d56Sopenharmony_ci        self._spam = value
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci    @spam.deleter
347db96d56Sopenharmony_ci    def spam(self):
357db96d56Sopenharmony_ci        del self._spam
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_ciclass SubClass(BaseClass):
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ci    @BaseClass.spam.getter
407db96d56Sopenharmony_ci    def spam(self):
417db96d56Sopenharmony_ci        """SubClass.getter"""
427db96d56Sopenharmony_ci        raise PropertyGet(self._spam)
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci    @spam.setter
457db96d56Sopenharmony_ci    def spam(self, value):
467db96d56Sopenharmony_ci        raise PropertySet(self._spam)
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_ci    @spam.deleter
497db96d56Sopenharmony_ci    def spam(self):
507db96d56Sopenharmony_ci        raise PropertyDel(self._spam)
517db96d56Sopenharmony_ci
527db96d56Sopenharmony_ciclass PropertyDocBase(object):
537db96d56Sopenharmony_ci    _spam = 1
547db96d56Sopenharmony_ci    def _get_spam(self):
557db96d56Sopenharmony_ci        return self._spam
567db96d56Sopenharmony_ci    spam = property(_get_spam, doc="spam spam spam")
577db96d56Sopenharmony_ci
587db96d56Sopenharmony_ciclass PropertyDocSub(PropertyDocBase):
597db96d56Sopenharmony_ci    @PropertyDocBase.spam.getter
607db96d56Sopenharmony_ci    def spam(self):
617db96d56Sopenharmony_ci        """The decorator does not use this doc string"""
627db96d56Sopenharmony_ci        return self._spam
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ciclass PropertySubNewGetter(BaseClass):
657db96d56Sopenharmony_ci    @BaseClass.spam.getter
667db96d56Sopenharmony_ci    def spam(self):
677db96d56Sopenharmony_ci        """new docstring"""
687db96d56Sopenharmony_ci        return 5
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ciclass PropertyNewGetter(object):
717db96d56Sopenharmony_ci    @property
727db96d56Sopenharmony_ci    def spam(self):
737db96d56Sopenharmony_ci        """original docstring"""
747db96d56Sopenharmony_ci        return 1
757db96d56Sopenharmony_ci    @spam.getter
767db96d56Sopenharmony_ci    def spam(self):
777db96d56Sopenharmony_ci        """new docstring"""
787db96d56Sopenharmony_ci        return 8
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_ciclass PropertyTests(unittest.TestCase):
817db96d56Sopenharmony_ci    def test_property_decorator_baseclass(self):
827db96d56Sopenharmony_ci        # see #1620
837db96d56Sopenharmony_ci        base = BaseClass()
847db96d56Sopenharmony_ci        self.assertEqual(base.spam, 5)
857db96d56Sopenharmony_ci        self.assertEqual(base._spam, 5)
867db96d56Sopenharmony_ci        base.spam = 10
877db96d56Sopenharmony_ci        self.assertEqual(base.spam, 10)
887db96d56Sopenharmony_ci        self.assertEqual(base._spam, 10)
897db96d56Sopenharmony_ci        delattr(base, "spam")
907db96d56Sopenharmony_ci        self.assertTrue(not hasattr(base, "spam"))
917db96d56Sopenharmony_ci        self.assertTrue(not hasattr(base, "_spam"))
927db96d56Sopenharmony_ci        base.spam = 20
937db96d56Sopenharmony_ci        self.assertEqual(base.spam, 20)
947db96d56Sopenharmony_ci        self.assertEqual(base._spam, 20)
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci    def test_property_decorator_subclass(self):
977db96d56Sopenharmony_ci        # see #1620
987db96d56Sopenharmony_ci        sub = SubClass()
997db96d56Sopenharmony_ci        self.assertRaises(PropertyGet, getattr, sub, "spam")
1007db96d56Sopenharmony_ci        self.assertRaises(PropertySet, setattr, sub, "spam", None)
1017db96d56Sopenharmony_ci        self.assertRaises(PropertyDel, delattr, sub, "spam")
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
1047db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
1057db96d56Sopenharmony_ci    def test_property_decorator_subclass_doc(self):
1067db96d56Sopenharmony_ci        sub = SubClass()
1077db96d56Sopenharmony_ci        self.assertEqual(sub.__class__.spam.__doc__, "SubClass.getter")
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
1107db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
1117db96d56Sopenharmony_ci    def test_property_decorator_baseclass_doc(self):
1127db96d56Sopenharmony_ci        base = BaseClass()
1137db96d56Sopenharmony_ci        self.assertEqual(base.__class__.spam.__doc__, "BaseClass.getter")
1147db96d56Sopenharmony_ci
1157db96d56Sopenharmony_ci    def test_property_decorator_doc(self):
1167db96d56Sopenharmony_ci        base = PropertyDocBase()
1177db96d56Sopenharmony_ci        sub = PropertyDocSub()
1187db96d56Sopenharmony_ci        self.assertEqual(base.__class__.spam.__doc__, "spam spam spam")
1197db96d56Sopenharmony_ci        self.assertEqual(sub.__class__.spam.__doc__, "spam spam spam")
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
1227db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
1237db96d56Sopenharmony_ci    def test_property_getter_doc_override(self):
1247db96d56Sopenharmony_ci        newgettersub = PropertySubNewGetter()
1257db96d56Sopenharmony_ci        self.assertEqual(newgettersub.spam, 5)
1267db96d56Sopenharmony_ci        self.assertEqual(newgettersub.__class__.spam.__doc__, "new docstring")
1277db96d56Sopenharmony_ci        newgetter = PropertyNewGetter()
1287db96d56Sopenharmony_ci        self.assertEqual(newgetter.spam, 8)
1297db96d56Sopenharmony_ci        self.assertEqual(newgetter.__class__.spam.__doc__, "new docstring")
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_ci    def test_property___isabstractmethod__descriptor(self):
1327db96d56Sopenharmony_ci        for val in (True, False, [], [1], '', '1'):
1337db96d56Sopenharmony_ci            class C(object):
1347db96d56Sopenharmony_ci                def foo(self):
1357db96d56Sopenharmony_ci                    pass
1367db96d56Sopenharmony_ci                foo.__isabstractmethod__ = val
1377db96d56Sopenharmony_ci                foo = property(foo)
1387db96d56Sopenharmony_ci            self.assertIs(C.foo.__isabstractmethod__, bool(val))
1397db96d56Sopenharmony_ci
1407db96d56Sopenharmony_ci        # check that the property's __isabstractmethod__ descriptor does the
1417db96d56Sopenharmony_ci        # right thing when presented with a value that fails truth testing:
1427db96d56Sopenharmony_ci        class NotBool(object):
1437db96d56Sopenharmony_ci            def __bool__(self):
1447db96d56Sopenharmony_ci                raise ValueError()
1457db96d56Sopenharmony_ci            __len__ = __bool__
1467db96d56Sopenharmony_ci        with self.assertRaises(ValueError):
1477db96d56Sopenharmony_ci            class C(object):
1487db96d56Sopenharmony_ci                def foo(self):
1497db96d56Sopenharmony_ci                    pass
1507db96d56Sopenharmony_ci                foo.__isabstractmethod__ = NotBool()
1517db96d56Sopenharmony_ci                foo = property(foo)
1527db96d56Sopenharmony_ci            C.foo.__isabstractmethod__
1537db96d56Sopenharmony_ci
1547db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
1557db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
1567db96d56Sopenharmony_ci    def test_property_builtin_doc_writable(self):
1577db96d56Sopenharmony_ci        p = property(doc='basic')
1587db96d56Sopenharmony_ci        self.assertEqual(p.__doc__, 'basic')
1597db96d56Sopenharmony_ci        p.__doc__ = 'extended'
1607db96d56Sopenharmony_ci        self.assertEqual(p.__doc__, 'extended')
1617db96d56Sopenharmony_ci
1627db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
1637db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
1647db96d56Sopenharmony_ci    def test_property_decorator_doc_writable(self):
1657db96d56Sopenharmony_ci        class PropertyWritableDoc(object):
1667db96d56Sopenharmony_ci
1677db96d56Sopenharmony_ci            @property
1687db96d56Sopenharmony_ci            def spam(self):
1697db96d56Sopenharmony_ci                """Eggs"""
1707db96d56Sopenharmony_ci                return "eggs"
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ci        sub = PropertyWritableDoc()
1737db96d56Sopenharmony_ci        self.assertEqual(sub.__class__.spam.__doc__, 'Eggs')
1747db96d56Sopenharmony_ci        sub.__class__.spam.__doc__ = 'Spam'
1757db96d56Sopenharmony_ci        self.assertEqual(sub.__class__.spam.__doc__, 'Spam')
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_ci    @support.refcount_test
1787db96d56Sopenharmony_ci    def test_refleaks_in___init__(self):
1797db96d56Sopenharmony_ci        gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')
1807db96d56Sopenharmony_ci        fake_prop = property('fget', 'fset', 'fdel', 'doc')
1817db96d56Sopenharmony_ci        refs_before = gettotalrefcount()
1827db96d56Sopenharmony_ci        for i in range(100):
1837db96d56Sopenharmony_ci            fake_prop.__init__('fget', 'fset', 'fdel', 'doc')
1847db96d56Sopenharmony_ci        self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
1877db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
1887db96d56Sopenharmony_ci    def test_class_property(self):
1897db96d56Sopenharmony_ci        class A:
1907db96d56Sopenharmony_ci            @classmethod
1917db96d56Sopenharmony_ci            @property
1927db96d56Sopenharmony_ci            def __doc__(cls):
1937db96d56Sopenharmony_ci                return 'A doc for %r' % cls.__name__
1947db96d56Sopenharmony_ci        self.assertEqual(A.__doc__, "A doc for 'A'")
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
1977db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
1987db96d56Sopenharmony_ci    def test_class_property_override(self):
1997db96d56Sopenharmony_ci        class A:
2007db96d56Sopenharmony_ci            """First"""
2017db96d56Sopenharmony_ci            @classmethod
2027db96d56Sopenharmony_ci            @property
2037db96d56Sopenharmony_ci            def __doc__(cls):
2047db96d56Sopenharmony_ci                return 'Second'
2057db96d56Sopenharmony_ci        self.assertEqual(A.__doc__, 'Second')
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_ci    def test_property_set_name_incorrect_args(self):
2087db96d56Sopenharmony_ci        p = property()
2097db96d56Sopenharmony_ci
2107db96d56Sopenharmony_ci        for i in (0, 1, 3):
2117db96d56Sopenharmony_ci            with self.assertRaisesRegex(
2127db96d56Sopenharmony_ci                TypeError,
2137db96d56Sopenharmony_ci                fr'^__set_name__\(\) takes 2 positional arguments but {i} were given$'
2147db96d56Sopenharmony_ci            ):
2157db96d56Sopenharmony_ci                p.__set_name__(*([0] * i))
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci    def test_property_setname_on_property_subclass(self):
2187db96d56Sopenharmony_ci        # https://github.com/python/cpython/issues/100942
2197db96d56Sopenharmony_ci        # Copy was setting the name field without first
2207db96d56Sopenharmony_ci        # verifying that the copy was an actual property
2217db96d56Sopenharmony_ci        # instance.  As a result, the code below was
2227db96d56Sopenharmony_ci        # causing a segfault.
2237db96d56Sopenharmony_ci
2247db96d56Sopenharmony_ci        class pro(property):
2257db96d56Sopenharmony_ci            def __new__(typ, *args, **kwargs):
2267db96d56Sopenharmony_ci                return "abcdef"
2277db96d56Sopenharmony_ci
2287db96d56Sopenharmony_ci        class A:
2297db96d56Sopenharmony_ci            pass
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_ci        p = property.__new__(pro)
2327db96d56Sopenharmony_ci        p.__set_name__(A, 1)
2337db96d56Sopenharmony_ci        np = p.getter(lambda self: 1)
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_ci# Issue 5890: subclasses of property do not preserve method __doc__ strings
2367db96d56Sopenharmony_ciclass PropertySub(property):
2377db96d56Sopenharmony_ci    """This is a subclass of property"""
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ciclass PropertySubSlots(property):
2407db96d56Sopenharmony_ci    """This is a subclass of property that defines __slots__"""
2417db96d56Sopenharmony_ci    __slots__ = ()
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ciclass PropertySubclassTests(unittest.TestCase):
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ci    def test_slots_docstring_copy_exception(self):
2467db96d56Sopenharmony_ci        try:
2477db96d56Sopenharmony_ci            class Foo(object):
2487db96d56Sopenharmony_ci                @PropertySubSlots
2497db96d56Sopenharmony_ci                def spam(self):
2507db96d56Sopenharmony_ci                    """Trying to copy this docstring will raise an exception"""
2517db96d56Sopenharmony_ci                    return 1
2527db96d56Sopenharmony_ci        except AttributeError:
2537db96d56Sopenharmony_ci            pass
2547db96d56Sopenharmony_ci        else:
2557db96d56Sopenharmony_ci            raise Exception("AttributeError not raised")
2567db96d56Sopenharmony_ci
2577db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
2587db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
2597db96d56Sopenharmony_ci    def test_docstring_copy(self):
2607db96d56Sopenharmony_ci        class Foo(object):
2617db96d56Sopenharmony_ci            @PropertySub
2627db96d56Sopenharmony_ci            def spam(self):
2637db96d56Sopenharmony_ci                """spam wrapped in property subclass"""
2647db96d56Sopenharmony_ci                return 1
2657db96d56Sopenharmony_ci        self.assertEqual(
2667db96d56Sopenharmony_ci            Foo.spam.__doc__,
2677db96d56Sopenharmony_ci            "spam wrapped in property subclass")
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
2707db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
2717db96d56Sopenharmony_ci    def test_property_setter_copies_getter_docstring(self):
2727db96d56Sopenharmony_ci        class Foo(object):
2737db96d56Sopenharmony_ci            def __init__(self): self._spam = 1
2747db96d56Sopenharmony_ci            @PropertySub
2757db96d56Sopenharmony_ci            def spam(self):
2767db96d56Sopenharmony_ci                """spam wrapped in property subclass"""
2777db96d56Sopenharmony_ci                return self._spam
2787db96d56Sopenharmony_ci            @spam.setter
2797db96d56Sopenharmony_ci            def spam(self, value):
2807db96d56Sopenharmony_ci                """this docstring is ignored"""
2817db96d56Sopenharmony_ci                self._spam = value
2827db96d56Sopenharmony_ci        foo = Foo()
2837db96d56Sopenharmony_ci        self.assertEqual(foo.spam, 1)
2847db96d56Sopenharmony_ci        foo.spam = 2
2857db96d56Sopenharmony_ci        self.assertEqual(foo.spam, 2)
2867db96d56Sopenharmony_ci        self.assertEqual(
2877db96d56Sopenharmony_ci            Foo.spam.__doc__,
2887db96d56Sopenharmony_ci            "spam wrapped in property subclass")
2897db96d56Sopenharmony_ci        class FooSub(Foo):
2907db96d56Sopenharmony_ci            @Foo.spam.setter
2917db96d56Sopenharmony_ci            def spam(self, value):
2927db96d56Sopenharmony_ci                """another ignored docstring"""
2937db96d56Sopenharmony_ci                self._spam = 'eggs'
2947db96d56Sopenharmony_ci        foosub = FooSub()
2957db96d56Sopenharmony_ci        self.assertEqual(foosub.spam, 1)
2967db96d56Sopenharmony_ci        foosub.spam = 7
2977db96d56Sopenharmony_ci        self.assertEqual(foosub.spam, 'eggs')
2987db96d56Sopenharmony_ci        self.assertEqual(
2997db96d56Sopenharmony_ci            FooSub.spam.__doc__,
3007db96d56Sopenharmony_ci            "spam wrapped in property subclass")
3017db96d56Sopenharmony_ci
3027db96d56Sopenharmony_ci    @unittest.skipIf(sys.flags.optimize >= 2,
3037db96d56Sopenharmony_ci                     "Docstrings are omitted with -O2 and above")
3047db96d56Sopenharmony_ci    def test_property_new_getter_new_docstring(self):
3057db96d56Sopenharmony_ci
3067db96d56Sopenharmony_ci        class Foo(object):
3077db96d56Sopenharmony_ci            @PropertySub
3087db96d56Sopenharmony_ci            def spam(self):
3097db96d56Sopenharmony_ci                """a docstring"""
3107db96d56Sopenharmony_ci                return 1
3117db96d56Sopenharmony_ci            @spam.getter
3127db96d56Sopenharmony_ci            def spam(self):
3137db96d56Sopenharmony_ci                """a new docstring"""
3147db96d56Sopenharmony_ci                return 2
3157db96d56Sopenharmony_ci        self.assertEqual(Foo.spam.__doc__, "a new docstring")
3167db96d56Sopenharmony_ci        class FooBase(object):
3177db96d56Sopenharmony_ci            @PropertySub
3187db96d56Sopenharmony_ci            def spam(self):
3197db96d56Sopenharmony_ci                """a docstring"""
3207db96d56Sopenharmony_ci                return 1
3217db96d56Sopenharmony_ci        class Foo2(FooBase):
3227db96d56Sopenharmony_ci            @FooBase.spam.getter
3237db96d56Sopenharmony_ci            def spam(self):
3247db96d56Sopenharmony_ci                """a new docstring"""
3257db96d56Sopenharmony_ci                return 2
3267db96d56Sopenharmony_ci        self.assertEqual(Foo.spam.__doc__, "a new docstring")
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci
3297db96d56Sopenharmony_ciclass _PropertyUnreachableAttribute:
3307db96d56Sopenharmony_ci    msg_format = None
3317db96d56Sopenharmony_ci    obj = None
3327db96d56Sopenharmony_ci    cls = None
3337db96d56Sopenharmony_ci
3347db96d56Sopenharmony_ci    def _format_exc_msg(self, msg):
3357db96d56Sopenharmony_ci        return self.msg_format.format(msg)
3367db96d56Sopenharmony_ci
3377db96d56Sopenharmony_ci    @classmethod
3387db96d56Sopenharmony_ci    def setUpClass(cls):
3397db96d56Sopenharmony_ci        cls.obj = cls.cls()
3407db96d56Sopenharmony_ci
3417db96d56Sopenharmony_ci    def test_get_property(self):
3427db96d56Sopenharmony_ci        with self.assertRaisesRegex(AttributeError, self._format_exc_msg("has no getter")):
3437db96d56Sopenharmony_ci            self.obj.foo
3447db96d56Sopenharmony_ci
3457db96d56Sopenharmony_ci    def test_set_property(self):
3467db96d56Sopenharmony_ci        with self.assertRaisesRegex(AttributeError, self._format_exc_msg("has no setter")):
3477db96d56Sopenharmony_ci            self.obj.foo = None
3487db96d56Sopenharmony_ci
3497db96d56Sopenharmony_ci    def test_del_property(self):
3507db96d56Sopenharmony_ci        with self.assertRaisesRegex(AttributeError, self._format_exc_msg("has no deleter")):
3517db96d56Sopenharmony_ci            del self.obj.foo
3527db96d56Sopenharmony_ci
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ciclass PropertyUnreachableAttributeWithName(_PropertyUnreachableAttribute, unittest.TestCase):
3557db96d56Sopenharmony_ci    msg_format = r"^property 'foo' of 'PropertyUnreachableAttributeWithName\.cls' object {}$"
3567db96d56Sopenharmony_ci
3577db96d56Sopenharmony_ci    class cls:
3587db96d56Sopenharmony_ci        foo = property()
3597db96d56Sopenharmony_ci
3607db96d56Sopenharmony_ci
3617db96d56Sopenharmony_ciclass PropertyUnreachableAttributeNoName(_PropertyUnreachableAttribute, unittest.TestCase):
3627db96d56Sopenharmony_ci    msg_format = r"^property of 'PropertyUnreachableAttributeNoName\.cls' object {}$"
3637db96d56Sopenharmony_ci
3647db96d56Sopenharmony_ci    class cls:
3657db96d56Sopenharmony_ci        pass
3667db96d56Sopenharmony_ci
3677db96d56Sopenharmony_ci    cls.foo = property()
3687db96d56Sopenharmony_ci
3697db96d56Sopenharmony_ci
3707db96d56Sopenharmony_ciif __name__ == '__main__':
3717db96d56Sopenharmony_ci    unittest.main()
372