[Python-checkins] cpython: Issue19030: commit tests for DynamicClassAttribute

ethan.furman python-checkins at python.org
Sun Oct 13 19:52:20 CEST 2013


http://hg.python.org/cpython/rev/3752c94368dd
changeset:   86325:3752c94368dd
parent:      86323:74c3cf05fb1e
user:        Ethan Furman <ethan at stoneleaf.us>
date:        Sun Oct 13 10:52:10 2013 -0700
summary:
  Issue19030: commit tests for DynamicClassAttribute

files:
  Lib/test/test_dynamicclassattribute.py |  304 +++++++++++++
  1 files changed, 304 insertions(+), 0 deletions(-)


diff --git a/Lib/test/test_dynamicclassattribute.py b/Lib/test/test_dynamicclassattribute.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_dynamicclassattribute.py
@@ -0,0 +1,304 @@
+# Test case for DynamicClassAttribute
+# more tests are in test_descr
+
+import abc
+import sys
+import unittest
+from test.support import run_unittest
+from types import DynamicClassAttribute
+
+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
+
+    @DynamicClassAttribute
+    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):
+
+    spam = BaseClass.__dict__['spam']
+
+    @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 = DynamicClassAttribute(_get_spam, doc="spam spam spam")
+
+class PropertyDocSub(PropertyDocBase):
+    spam = PropertyDocBase.__dict__['spam']
+    @spam.getter
+    def spam(self):
+        """The decorator does not use this doc string"""
+        return self._spam
+
+class PropertySubNewGetter(BaseClass):
+    spam = BaseClass.__dict__['spam']
+    @spam.getter
+    def spam(self):
+        """new docstring"""
+        return 5
+
+class PropertyNewGetter(object):
+    @DynamicClassAttribute
+    def spam(self):
+        """original docstring"""
+        return 1
+    @spam.getter
+    def spam(self):
+        """new docstring"""
+        return 8
+
+class ClassWithAbstractVirtualProperty(metaclass=abc.ABCMeta):
+    @DynamicClassAttribute
+    @abc.abstractmethod
+    def color():
+        pass
+
+class ClassWithPropertyAbstractVirtual(metaclass=abc.ABCMeta):
+    @abc.abstractmethod
+    @DynamicClassAttribute
+    def color():
+        pass
+
+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__.__dict__['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__.__dict__['spam'].__doc__, "BaseClass.getter")
+
+    def test_property_decorator_doc(self):
+        base = PropertyDocBase()
+        sub = PropertyDocSub()
+        self.assertEqual(base.__class__.__dict__['spam'].__doc__, "spam spam spam")
+        self.assertEqual(sub.__class__.__dict__['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__.__dict__['spam'].__doc__, "new docstring")
+        newgetter = PropertyNewGetter()
+        self.assertEqual(newgetter.spam, 8)
+        self.assertEqual(newgetter.__class__.__dict__['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 = DynamicClassAttribute(foo)
+            self.assertIs(C.__dict__['foo'].__isabstractmethod__, bool(val))
+
+        # check that the DynamicClassAttribute's __isabstractmethod__ descriptor does the
+        # right thing when presented with a value that fails truth testing:
+        class NotBool(object):
+            def __nonzero__(self):
+                raise ValueError()
+            __len__ = __nonzero__
+        with self.assertRaises(ValueError):
+            class C(object):
+                def foo(self):
+                    pass
+                foo.__isabstractmethod__ = NotBool()
+                foo = DynamicClassAttribute(foo)
+
+    def test_abstract_virtual(self):
+        self.assertRaises(TypeError, ClassWithAbstractVirtualProperty)
+        self.assertRaises(TypeError, ClassWithPropertyAbstractVirtual)
+        class APV(ClassWithPropertyAbstractVirtual):
+            pass
+        self.assertRaises(TypeError, APV)
+        class AVP(ClassWithAbstractVirtualProperty):
+            pass
+        self.assertRaises(TypeError, AVP)
+        class Okay1(ClassWithAbstractVirtualProperty):
+            @DynamicClassAttribute
+            def color(self):
+                return self._color
+            def __init__(self):
+                self._color = 'cyan'
+        with self.assertRaises(AttributeError):
+            Okay1.color
+        self.assertEqual(Okay1().color, 'cyan')
+        class Okay2(ClassWithAbstractVirtualProperty):
+            @DynamicClassAttribute
+            def color(self):
+                return self._color
+            def __init__(self):
+                self._color = 'magenta'
+        with self.assertRaises(AttributeError):
+            Okay2.color
+        self.assertEqual(Okay2().color, 'magenta')
+
+
+# Issue 5890: subclasses of DynamicClassAttribute do not preserve method __doc__ strings
+class PropertySub(DynamicClassAttribute):
+    """This is a subclass of DynamicClassAttribute"""
+
+class PropertySubSlots(DynamicClassAttribute):
+    """This is a subclass of DynamicClassAttribute that defines __slots__"""
+    __slots__ = ()
+
+class PropertySubclassTests(unittest.TestCase):
+
+    @unittest.skipIf(hasattr(PropertySubSlots, '__doc__'),
+            "__doc__ is already present, __slots__ will have no effect")
+    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
+                print('\n',spam.__doc__)
+        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 DynamicClassAttribute subclass"""
+                return 1
+        self.assertEqual(
+            Foo.__dict__['spam'].__doc__,
+            "spam wrapped in DynamicClassAttribute 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 DynamicClassAttribute 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.__dict__['spam'].__doc__,
+            "spam wrapped in DynamicClassAttribute subclass")
+        class FooSub(Foo):
+            spam = Foo.__dict__['spam']
+            @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.__dict__['spam'].__doc__,
+            "spam wrapped in DynamicClassAttribute 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.__dict__['spam'].__doc__, "a new docstring")
+        class FooBase(object):
+            @PropertySub
+            def spam(self):
+                """a docstring"""
+                return 1
+        class Foo2(FooBase):
+            spam = FooBase.__dict__['spam']
+            @spam.getter
+            def spam(self):
+                """a new docstring"""
+                return 2
+        self.assertEqual(Foo.__dict__['spam'].__doc__, "a new docstring")
+
+
+
+def test_main():
+    run_unittest(PropertyTests, PropertySubclassTests)
+
+if __name__ == '__main__':
+    test_main()

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list