(root)/
Python-3.11.7/
Lib/
test/
test_property.py
       1  # Test case for property
       2  # more tests are in test_descr
       3  
       4  import sys
       5  import unittest
       6  from test import support
       7  
       8  class ESC[4;38;5;81mPropertyBase(ESC[4;38;5;149mException):
       9      pass
      10  
      11  class ESC[4;38;5;81mPropertyGet(ESC[4;38;5;149mPropertyBase):
      12      pass
      13  
      14  class ESC[4;38;5;81mPropertySet(ESC[4;38;5;149mPropertyBase):
      15      pass
      16  
      17  class ESC[4;38;5;81mPropertyDel(ESC[4;38;5;149mPropertyBase):
      18      pass
      19  
      20  class ESC[4;38;5;81mBaseClass(ESC[4;38;5;149mobject):
      21      def __init__(self):
      22          self._spam = 5
      23  
      24      @property
      25      def spam(self):
      26          """BaseClass.getter"""
      27          return self._spam
      28  
      29      @spam.setter
      30      def spam(self, value):
      31          self._spam = value
      32  
      33      @spam.deleter
      34      def spam(self):
      35          del self._spam
      36  
      37  class ESC[4;38;5;81mSubClass(ESC[4;38;5;149mBaseClass):
      38  
      39      @BaseClass.spam.getter
      40      def spam(self):
      41          """SubClass.getter"""
      42          raise PropertyGet(self._spam)
      43  
      44      @spam.setter
      45      def spam(self, value):
      46          raise PropertySet(self._spam)
      47  
      48      @spam.deleter
      49      def spam(self):
      50          raise PropertyDel(self._spam)
      51  
      52  class ESC[4;38;5;81mPropertyDocBase(ESC[4;38;5;149mobject):
      53      _spam = 1
      54      def _get_spam(self):
      55          return self._spam
      56      spam = property(_get_spam, doc="spam spam spam")
      57  
      58  class ESC[4;38;5;81mPropertyDocSub(ESC[4;38;5;149mPropertyDocBase):
      59      @PropertyDocBase.spam.getter
      60      def spam(self):
      61          """The decorator does not use this doc string"""
      62          return self._spam
      63  
      64  class ESC[4;38;5;81mPropertySubNewGetter(ESC[4;38;5;149mBaseClass):
      65      @BaseClass.spam.getter
      66      def spam(self):
      67          """new docstring"""
      68          return 5
      69  
      70  class ESC[4;38;5;81mPropertyNewGetter(ESC[4;38;5;149mobject):
      71      @property
      72      def spam(self):
      73          """original docstring"""
      74          return 1
      75      @spam.getter
      76      def spam(self):
      77          """new docstring"""
      78          return 8
      79  
      80  class ESC[4;38;5;81mPropertyTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      81      def test_property_decorator_baseclass(self):
      82          # see #1620
      83          base = BaseClass()
      84          self.assertEqual(base.spam, 5)
      85          self.assertEqual(base._spam, 5)
      86          base.spam = 10
      87          self.assertEqual(base.spam, 10)
      88          self.assertEqual(base._spam, 10)
      89          delattr(base, "spam")
      90          self.assertTrue(not hasattr(base, "spam"))
      91          self.assertTrue(not hasattr(base, "_spam"))
      92          base.spam = 20
      93          self.assertEqual(base.spam, 20)
      94          self.assertEqual(base._spam, 20)
      95  
      96      def test_property_decorator_subclass(self):
      97          # see #1620
      98          sub = SubClass()
      99          self.assertRaises(PropertyGet, getattr, sub, "spam")
     100          self.assertRaises(PropertySet, setattr, sub, "spam", None)
     101          self.assertRaises(PropertyDel, delattr, sub, "spam")
     102  
     103      @unittest.skipIf(sys.flags.optimize >= 2,
     104                       "Docstrings are omitted with -O2 and above")
     105      def test_property_decorator_subclass_doc(self):
     106          sub = SubClass()
     107          self.assertEqual(sub.__class__.spam.__doc__, "SubClass.getter")
     108  
     109      @unittest.skipIf(sys.flags.optimize >= 2,
     110                       "Docstrings are omitted with -O2 and above")
     111      def test_property_decorator_baseclass_doc(self):
     112          base = BaseClass()
     113          self.assertEqual(base.__class__.spam.__doc__, "BaseClass.getter")
     114  
     115      def test_property_decorator_doc(self):
     116          base = PropertyDocBase()
     117          sub = PropertyDocSub()
     118          self.assertEqual(base.__class__.spam.__doc__, "spam spam spam")
     119          self.assertEqual(sub.__class__.spam.__doc__, "spam spam spam")
     120  
     121      @unittest.skipIf(sys.flags.optimize >= 2,
     122                       "Docstrings are omitted with -O2 and above")
     123      def test_property_getter_doc_override(self):
     124          newgettersub = PropertySubNewGetter()
     125          self.assertEqual(newgettersub.spam, 5)
     126          self.assertEqual(newgettersub.__class__.spam.__doc__, "new docstring")
     127          newgetter = PropertyNewGetter()
     128          self.assertEqual(newgetter.spam, 8)
     129          self.assertEqual(newgetter.__class__.spam.__doc__, "new docstring")
     130  
     131      def test_property___isabstractmethod__descriptor(self):
     132          for val in (True, False, [], [1], '', '1'):
     133              class ESC[4;38;5;81mC(ESC[4;38;5;149mobject):
     134                  def foo(self):
     135                      pass
     136                  foo.__isabstractmethod__ = val
     137                  foo = property(foo)
     138              self.assertIs(C.foo.__isabstractmethod__, bool(val))
     139  
     140          # check that the property's __isabstractmethod__ descriptor does the
     141          # right thing when presented with a value that fails truth testing:
     142          class ESC[4;38;5;81mNotBool(ESC[4;38;5;149mobject):
     143              def __bool__(self):
     144                  raise ValueError()
     145              __len__ = __bool__
     146          with self.assertRaises(ValueError):
     147              class ESC[4;38;5;81mC(ESC[4;38;5;149mobject):
     148                  def foo(self):
     149                      pass
     150                  foo.__isabstractmethod__ = NotBool()
     151                  foo = property(foo)
     152              C.foo.__isabstractmethod__
     153  
     154      @unittest.skipIf(sys.flags.optimize >= 2,
     155                       "Docstrings are omitted with -O2 and above")
     156      def test_property_builtin_doc_writable(self):
     157          p = property(doc='basic')
     158          self.assertEqual(p.__doc__, 'basic')
     159          p.__doc__ = 'extended'
     160          self.assertEqual(p.__doc__, 'extended')
     161  
     162      @unittest.skipIf(sys.flags.optimize >= 2,
     163                       "Docstrings are omitted with -O2 and above")
     164      def test_property_decorator_doc_writable(self):
     165          class ESC[4;38;5;81mPropertyWritableDoc(ESC[4;38;5;149mobject):
     166  
     167              @property
     168              def spam(self):
     169                  """Eggs"""
     170                  return "eggs"
     171  
     172          sub = PropertyWritableDoc()
     173          self.assertEqual(sub.__class__.spam.__doc__, 'Eggs')
     174          sub.__class__.spam.__doc__ = 'Spam'
     175          self.assertEqual(sub.__class__.spam.__doc__, 'Spam')
     176  
     177      @support.refcount_test
     178      def test_refleaks_in___init__(self):
     179          gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')
     180          fake_prop = property('fget', 'fset', 'fdel', 'doc')
     181          refs_before = gettotalrefcount()
     182          for i in range(100):
     183              fake_prop.__init__('fget', 'fset', 'fdel', 'doc')
     184          self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
     185  
     186      @unittest.skipIf(sys.flags.optimize >= 2,
     187                       "Docstrings are omitted with -O2 and above")
     188      def test_class_property(self):
     189          class ESC[4;38;5;81mA:
     190              @classmethod
     191              @property
     192              def __doc__(cls):
     193                  return 'A doc for %r' % cls.__name__
     194          self.assertEqual(A.__doc__, "A doc for 'A'")
     195  
     196      @unittest.skipIf(sys.flags.optimize >= 2,
     197                       "Docstrings are omitted with -O2 and above")
     198      def test_class_property_override(self):
     199          class ESC[4;38;5;81mA:
     200              """First"""
     201              @classmethod
     202              @property
     203              def __doc__(cls):
     204                  return 'Second'
     205          self.assertEqual(A.__doc__, 'Second')
     206  
     207      def test_property_set_name_incorrect_args(self):
     208          p = property()
     209  
     210          for i in (0, 1, 3):
     211              with self.assertRaisesRegex(
     212                  TypeError,
     213                  fr'^__set_name__\(\) takes 2 positional arguments but {i} were given$'
     214              ):
     215                  p.__set_name__(*([0] * i))
     216  
     217      def test_property_setname_on_property_subclass(self):
     218          # https://github.com/python/cpython/issues/100942
     219          # Copy was setting the name field without first
     220          # verifying that the copy was an actual property
     221          # instance.  As a result, the code below was
     222          # causing a segfault.
     223  
     224          class ESC[4;38;5;81mpro(ESC[4;38;5;149mproperty):
     225              def __new__(typ, *args, **kwargs):
     226                  return "abcdef"
     227  
     228          class ESC[4;38;5;81mA:
     229              pass
     230  
     231          p = property.__new__(pro)
     232          p.__set_name__(A, 1)
     233          np = p.getter(lambda self: 1)
     234  
     235  # Issue 5890: subclasses of property do not preserve method __doc__ strings
     236  class ESC[4;38;5;81mPropertySub(ESC[4;38;5;149mproperty):
     237      """This is a subclass of property"""
     238  
     239  class ESC[4;38;5;81mPropertySubSlots(ESC[4;38;5;149mproperty):
     240      """This is a subclass of property that defines __slots__"""
     241      __slots__ = ()
     242  
     243  class ESC[4;38;5;81mPropertySubclassTests(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     244  
     245      def test_slots_docstring_copy_exception(self):
     246          try:
     247              class ESC[4;38;5;81mFoo(ESC[4;38;5;149mobject):
     248                  @PropertySubSlots
     249                  def spam(self):
     250                      """Trying to copy this docstring will raise an exception"""
     251                      return 1
     252          except AttributeError:
     253              pass
     254          else:
     255              raise Exception("AttributeError not raised")
     256  
     257      @unittest.skipIf(sys.flags.optimize >= 2,
     258                       "Docstrings are omitted with -O2 and above")
     259      def test_docstring_copy(self):
     260          class ESC[4;38;5;81mFoo(ESC[4;38;5;149mobject):
     261              @PropertySub
     262              def spam(self):
     263                  """spam wrapped in property subclass"""
     264                  return 1
     265          self.assertEqual(
     266              Foo.spam.__doc__,
     267              "spam wrapped in property subclass")
     268  
     269      @unittest.skipIf(sys.flags.optimize >= 2,
     270                       "Docstrings are omitted with -O2 and above")
     271      def test_property_setter_copies_getter_docstring(self):
     272          class ESC[4;38;5;81mFoo(ESC[4;38;5;149mobject):
     273              def __init__(self): self._spam = 1
     274              @PropertySub
     275              def spam(self):
     276                  """spam wrapped in property subclass"""
     277                  return self._spam
     278              @spam.setter
     279              def spam(self, value):
     280                  """this docstring is ignored"""
     281                  self._spam = value
     282          foo = Foo()
     283          self.assertEqual(foo.spam, 1)
     284          foo.spam = 2
     285          self.assertEqual(foo.spam, 2)
     286          self.assertEqual(
     287              Foo.spam.__doc__,
     288              "spam wrapped in property subclass")
     289          class ESC[4;38;5;81mFooSub(ESC[4;38;5;149mFoo):
     290              @Foo.spam.setter
     291              def spam(self, value):
     292                  """another ignored docstring"""
     293                  self._spam = 'eggs'
     294          foosub = FooSub()
     295          self.assertEqual(foosub.spam, 1)
     296          foosub.spam = 7
     297          self.assertEqual(foosub.spam, 'eggs')
     298          self.assertEqual(
     299              FooSub.spam.__doc__,
     300              "spam wrapped in property subclass")
     301  
     302      @unittest.skipIf(sys.flags.optimize >= 2,
     303                       "Docstrings are omitted with -O2 and above")
     304      def test_property_new_getter_new_docstring(self):
     305  
     306          class ESC[4;38;5;81mFoo(ESC[4;38;5;149mobject):
     307              @PropertySub
     308              def spam(self):
     309                  """a docstring"""
     310                  return 1
     311              @spam.getter
     312              def spam(self):
     313                  """a new docstring"""
     314                  return 2
     315          self.assertEqual(Foo.spam.__doc__, "a new docstring")
     316          class ESC[4;38;5;81mFooBase(ESC[4;38;5;149mobject):
     317              @PropertySub
     318              def spam(self):
     319                  """a docstring"""
     320                  return 1
     321          class ESC[4;38;5;81mFoo2(ESC[4;38;5;149mFooBase):
     322              @FooBase.spam.getter
     323              def spam(self):
     324                  """a new docstring"""
     325                  return 2
     326          self.assertEqual(Foo.spam.__doc__, "a new docstring")
     327  
     328  
     329  class ESC[4;38;5;81m_PropertyUnreachableAttribute:
     330      msg_format = None
     331      obj = None
     332      cls = None
     333  
     334      def _format_exc_msg(self, msg):
     335          return self.msg_format.format(msg)
     336  
     337      @classmethod
     338      def setUpClass(cls):
     339          cls.obj = cls.cls()
     340  
     341      def test_get_property(self):
     342          with self.assertRaisesRegex(AttributeError, self._format_exc_msg("has no getter")):
     343              self.obj.foo
     344  
     345      def test_set_property(self):
     346          with self.assertRaisesRegex(AttributeError, self._format_exc_msg("has no setter")):
     347              self.obj.foo = None
     348  
     349      def test_del_property(self):
     350          with self.assertRaisesRegex(AttributeError, self._format_exc_msg("has no deleter")):
     351              del self.obj.foo
     352  
     353  
     354  class ESC[4;38;5;81mPropertyUnreachableAttributeWithName(ESC[4;38;5;149m_PropertyUnreachableAttribute, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     355      msg_format = r"^property 'foo' of 'PropertyUnreachableAttributeWithName\.cls' object {}$"
     356  
     357      class ESC[4;38;5;81mcls:
     358          foo = property()
     359  
     360  
     361  class ESC[4;38;5;81mPropertyUnreachableAttributeNoName(ESC[4;38;5;149m_PropertyUnreachableAttribute, ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     362      msg_format = r"^property of 'PropertyUnreachableAttributeNoName\.cls' object {}$"
     363  
     364      class ESC[4;38;5;81mcls:
     365          pass
     366  
     367      cls.foo = property()
     368  
     369  
     370  if __name__ == '__main__':
     371      unittest.main()