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