| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- # Test case for property
- # more tests are in test_descr
- import sys
- import unittest
- from test import support
- class PropertyBase(Exception):
- pass
- class PropertyGet(PropertyBase):
- pass
- class PropertySet(PropertyBase):
- pass
- class PropertyDel(PropertyBase):
- pass
- class BaseClass(object):
- def __init__(self):
- self._spam = 5
- @property
- def spam(self):
- """BaseClass.getter"""
- return self._spam
- @spam.setter
- def spam(self, value):
- self._spam = value
- @spam.deleter
- def spam(self):
- del self._spam
- class SubClass(BaseClass):
- @BaseClass.spam.getter
- def spam(self):
- """SubClass.getter"""
- raise PropertyGet(self._spam)
- @spam.setter
- def spam(self, value):
- raise PropertySet(self._spam)
- @spam.deleter
- def spam(self):
- raise PropertyDel(self._spam)
- class PropertyDocBase(object):
- _spam = 1
- def _get_spam(self):
- return self._spam
- spam = property(_get_spam, doc="spam spam spam")
- class PropertyDocSub(PropertyDocBase):
- @PropertyDocBase.spam.getter
- def spam(self):
- """The decorator does not use this doc string"""
- return self._spam
- class PropertySubNewGetter(BaseClass):
- @BaseClass.spam.getter
- def spam(self):
- """new docstring"""
- return 5
- class PropertyNewGetter(object):
- @property
- def spam(self):
- """original docstring"""
- return 1
- @spam.getter
- def spam(self):
- """new docstring"""
- return 8
- class PropertyTests(unittest.TestCase):
- def test_property_decorator_baseclass(self):
- # see #1620
- base = BaseClass()
- self.assertEqual(base.spam, 5)
- self.assertEqual(base._spam, 5)
- base.spam = 10
- self.assertEqual(base.spam, 10)
- self.assertEqual(base._spam, 10)
- delattr(base, "spam")
- self.assertTrue(not hasattr(base, "spam"))
- self.assertTrue(not hasattr(base, "_spam"))
- base.spam = 20
- self.assertEqual(base.spam, 20)
- self.assertEqual(base._spam, 20)
- def test_property_decorator_subclass(self):
- # see #1620
- sub = SubClass()
- self.assertRaises(PropertyGet, getattr, sub, "spam")
- self.assertRaises(PropertySet, setattr, sub, "spam", None)
- self.assertRaises(PropertyDel, delattr, sub, "spam")
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_property_decorator_subclass_doc(self):
- sub = SubClass()
- self.assertEqual(sub.__class__.spam.__doc__, "SubClass.getter")
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_property_decorator_baseclass_doc(self):
- base = BaseClass()
- self.assertEqual(base.__class__.spam.__doc__, "BaseClass.getter")
- def test_property_decorator_doc(self):
- base = PropertyDocBase()
- sub = PropertyDocSub()
- self.assertEqual(base.__class__.spam.__doc__, "spam spam spam")
- self.assertEqual(sub.__class__.spam.__doc__, "spam spam spam")
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_property_getter_doc_override(self):
- newgettersub = PropertySubNewGetter()
- self.assertEqual(newgettersub.spam, 5)
- self.assertEqual(newgettersub.__class__.spam.__doc__, "new docstring")
- newgetter = PropertyNewGetter()
- self.assertEqual(newgetter.spam, 8)
- self.assertEqual(newgetter.__class__.spam.__doc__, "new docstring")
- def test_property___isabstractmethod__descriptor(self):
- for val in (True, False, [], [1], '', '1'):
- class C(object):
- def foo(self):
- pass
- foo.__isabstractmethod__ = val
- foo = property(foo)
- self.assertIs(C.foo.__isabstractmethod__, bool(val))
- # check that the property's __isabstractmethod__ descriptor does the
- # right thing when presented with a value that fails truth testing:
- class NotBool(object):
- def __bool__(self):
- raise ValueError()
- __len__ = __bool__
- with self.assertRaises(ValueError):
- class C(object):
- def foo(self):
- pass
- foo.__isabstractmethod__ = NotBool()
- foo = property(foo)
- C.foo.__isabstractmethod__
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_property_builtin_doc_writable(self):
- p = property(doc='basic')
- self.assertEqual(p.__doc__, 'basic')
- p.__doc__ = 'extended'
- self.assertEqual(p.__doc__, 'extended')
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_property_decorator_doc_writable(self):
- class PropertyWritableDoc(object):
- @property
- def spam(self):
- """Eggs"""
- return "eggs"
- sub = PropertyWritableDoc()
- self.assertEqual(sub.__class__.spam.__doc__, 'Eggs')
- sub.__class__.spam.__doc__ = 'Spam'
- self.assertEqual(sub.__class__.spam.__doc__, 'Spam')
- @support.refcount_test
- def test_refleaks_in___init__(self):
- gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')
- fake_prop = property('fget', 'fset', 'fdel', 'doc')
- refs_before = gettotalrefcount()
- for i in range(100):
- fake_prop.__init__('fget', 'fset', 'fdel', 'doc')
- self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_class_property(self):
- class A:
- @classmethod
- @property
- def __doc__(cls):
- return 'A doc for %r' % cls.__name__
- self.assertEqual(A.__doc__, "A doc for 'A'")
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_class_property_override(self):
- class A:
- """First"""
- @classmethod
- @property
- def __doc__(cls):
- return 'Second'
- self.assertEqual(A.__doc__, 'Second')
- def test_property_set_name_incorrect_args(self):
- p = property()
- for i in (0, 1, 3):
- with self.assertRaisesRegex(
- TypeError,
- fr'^__set_name__\(\) takes 2 positional arguments but {i} were given$'
- ):
- p.__set_name__(*([0] * i))
- def test_property_setname_on_property_subclass(self):
- # https://github.com/python/cpython/issues/100942
- # Copy was setting the name field without first
- # verifying that the copy was an actual property
- # instance. As a result, the code below was
- # causing a segfault.
- class pro(property):
- def __new__(typ, *args, **kwargs):
- return "abcdef"
- class A:
- pass
- p = property.__new__(pro)
- p.__set_name__(A, 1)
- np = p.getter(lambda self: 1)
- # Issue 5890: subclasses of property do not preserve method __doc__ strings
- class PropertySub(property):
- """This is a subclass of property"""
- class PropertySubSlots(property):
- """This is a subclass of property that defines __slots__"""
- __slots__ = ()
- class PropertySubclassTests(unittest.TestCase):
- def test_slots_docstring_copy_exception(self):
- try:
- class Foo(object):
- @PropertySubSlots
- def spam(self):
- """Trying to copy this docstring will raise an exception"""
- return 1
- except AttributeError:
- pass
- else:
- raise Exception("AttributeError not raised")
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_docstring_copy(self):
- class Foo(object):
- @PropertySub
- def spam(self):
- """spam wrapped in property subclass"""
- return 1
- self.assertEqual(
- Foo.spam.__doc__,
- "spam wrapped in property subclass")
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_property_setter_copies_getter_docstring(self):
- class Foo(object):
- def __init__(self): self._spam = 1
- @PropertySub
- def spam(self):
- """spam wrapped in property subclass"""
- return self._spam
- @spam.setter
- def spam(self, value):
- """this docstring is ignored"""
- self._spam = value
- foo = Foo()
- self.assertEqual(foo.spam, 1)
- foo.spam = 2
- self.assertEqual(foo.spam, 2)
- self.assertEqual(
- Foo.spam.__doc__,
- "spam wrapped in property subclass")
- class FooSub(Foo):
- @Foo.spam.setter
- def spam(self, value):
- """another ignored docstring"""
- self._spam = 'eggs'
- foosub = FooSub()
- self.assertEqual(foosub.spam, 1)
- foosub.spam = 7
- self.assertEqual(foosub.spam, 'eggs')
- self.assertEqual(
- FooSub.spam.__doc__,
- "spam wrapped in property subclass")
- @unittest.skipIf(sys.flags.optimize >= 2,
- "Docstrings are omitted with -O2 and above")
- def test_property_new_getter_new_docstring(self):
- class Foo(object):
- @PropertySub
- def spam(self):
- """a docstring"""
- return 1
- @spam.getter
- def spam(self):
- """a new docstring"""
- return 2
- self.assertEqual(Foo.spam.__doc__, "a new docstring")
- class FooBase(object):
- @PropertySub
- def spam(self):
- """a docstring"""
- return 1
- class Foo2(FooBase):
- @FooBase.spam.getter
- def spam(self):
- """a new docstring"""
- return 2
- self.assertEqual(Foo.spam.__doc__, "a new docstring")
- class _PropertyUnreachableAttribute:
- msg_format = None
- obj = None
- cls = None
- def _format_exc_msg(self, msg):
- return self.msg_format.format(msg)
- @classmethod
- def setUpClass(cls):
- cls.obj = cls.cls()
- def test_get_property(self):
- with self.assertRaisesRegex(AttributeError, self._format_exc_msg("has no getter")):
- self.obj.foo
- def test_set_property(self):
- with self.assertRaisesRegex(AttributeError, self._format_exc_msg("has no setter")):
- self.obj.foo = None
- def test_del_property(self):
- with self.assertRaisesRegex(AttributeError, self._format_exc_msg("has no deleter")):
- del self.obj.foo
- class PropertyUnreachableAttributeWithName(_PropertyUnreachableAttribute, unittest.TestCase):
- msg_format = r"^property 'foo' of 'PropertyUnreachableAttributeWithName\.cls' object {}$"
- class cls:
- foo = property()
- class PropertyUnreachableAttributeNoName(_PropertyUnreachableAttribute, unittest.TestCase):
- msg_format = r"^property of 'PropertyUnreachableAttributeNoName\.cls' object {}$"
- class cls:
- pass
- cls.foo = property()
- if __name__ == '__main__':
- unittest.main()
|