[Checkins] SVN: zope.interface/branches/tseaver-no_2to3/ Deprecated the "class advice" APIs from ``zope.interface.declarations``.

Tres Seaver cvs-admin at zope.org
Fri Apr 6 05:35:36 UTC 2012


Log message for revision 124990:
  Deprecated the "class advice" APIs from ``zope.interface.declarations``.
  
  Code which uses the deprecated APIs will not work as expected under Py3k.
  
  Instead of   ``implements``, ``implementsOnly``, or ``classProvides``,
  prefer the equivalent class decorators: ``@implementer``,
  ``@implementer_only``, and ``@provider``.
  

Changed:
  U   zope.interface/branches/tseaver-no_2to3/CHANGES.txt
  U   zope.interface/branches/tseaver-no_2to3/src/zope/interface/declarations.py
  U   zope.interface/branches/tseaver-no_2to3/src/zope/interface/tests/test_declarations.py

-=-
Modified: zope.interface/branches/tseaver-no_2to3/CHANGES.txt
===================================================================
--- zope.interface/branches/tseaver-no_2to3/CHANGES.txt	2012-04-06 05:35:28 UTC (rev 124989)
+++ zope.interface/branches/tseaver-no_2to3/CHANGES.txt	2012-04-06 05:35:33 UTC (rev 124990)
@@ -4,6 +4,12 @@
 4.0.0a1 (unreleased)
 --------------------
 
+- Deprecated the "class advice" APIs from ``zope.interface.declarations``:
+  ``implements``, ``implementsOnly``, and ``classProvides``.  In their place,
+  prefer the equivalent class decorators: ``@implementer``,
+  ``@implementer_only``, and ``@provider``.  Code which uses the deprecated
+  APIs will not work as expected under Py3k.
+
 - Removed use of '2to3' and associated fixers when installing under Py3k.
   The code is now in a "compatible subset" which supports Python 2.6, 2.7,
   and 3.2, including PyPy 1.8 (the version compatible with the 2.7 language

Modified: zope.interface/branches/tseaver-no_2to3/src/zope/interface/declarations.py
===================================================================
--- zope.interface/branches/tseaver-no_2to3/src/zope/interface/declarations.py	2012-04-06 05:35:28 UTC (rev 124989)
+++ zope.interface/branches/tseaver-no_2to3/src/zope/interface/declarations.py	2012-04-06 05:35:33 UTC (rev 124990)
@@ -30,6 +30,7 @@
 from types import FunctionType
 from types import MethodType
 from types import ModuleType
+import warnings
 import weakref
 
 from zope.interface.advice import addClassAdvisor
@@ -42,6 +43,12 @@
 # Registry of class-implementation specifications
 BuiltinImplementationSpecifications = {}
 
+_ADVICE_ERROR = ('Class advice impossible in Python3.  '
+                 'Use the @%s class decorator instead.')
+
+_ADVICE_WARNING = ('The %s API is deprecated, and will not work in Python3  '
+                   'Use the @%s class decorator instead.')
+
 class Declaration(Specification):
     """Interface declarations"""
 
@@ -394,9 +401,10 @@
     # This entire approach is invalid under Py3K.  Don't even try to fix
     # the coverage for this block there. :(
     if PYTHON3: #pragma NO COVER
-        raise TypeError('Class advice impossible in Python3.  Use the'
-                        '@implementer class decorator instead.'
-                       )
+        raise TypeError(_ADVICE_ERROR % 'implementer')
+    else:
+        warnings.warn(_ADVICE_WARNING % ('implements', 'implementer'),
+                      DeprecationWarning, 2)
     _implements("implements", interfaces, classImplements)
 
 def implementsOnly(*interfaces):
@@ -424,9 +432,10 @@
     # This entire approach is invalid under Py3K.  Don't even try to fix
     # the coverage for this block there. :(
     if PYTHON3: #pragma NO COVER
-        raise TypeError('Class advice impossible in Python3.  Use the'
-                        '@implementer_only class decorator instead.'
-                       )
+        raise TypeError(_ADVICE_ERROR % 'implementer_only')
+    else:
+        warnings.warn(_ADVICE_WARNING % ('implementsOnly', 'implementer_only'),
+                      DeprecationWarning, 2)
     _implements("implementsOnly", interfaces, classImplementsOnly)
 
 ##############################################################################
@@ -630,10 +639,12 @@
     """
     # This entire approach is invalid under Py3K.  Don't even try to fix
     # the coverage for this block there. :(
+                       
     if PYTHON3: #pragma NO COVER
-        raise TypeError('Class advice impossible in Python3.  Use the'
-                        '@provider class decorator instead.'
-                       )
+        raise TypeError(_ADVICE_ERROR % 'provider')
+    else:
+        warnings.warn(_ADVICE_WARNING % ('classProvides', 'provider'),
+                      DeprecationWarning, 2)
 
     frame = sys._getframe(1)
     locals = frame.f_locals

Modified: zope.interface/branches/tseaver-no_2to3/src/zope/interface/tests/test_declarations.py
===================================================================
--- zope.interface/branches/tseaver-no_2to3/src/zope/interface/tests/test_declarations.py	2012-04-06 05:35:28 UTC (rev 124989)
+++ zope.interface/branches/tseaver-no_2to3/src/zope/interface/tests/test_declarations.py	2012-04-06 05:35:33 UTC (rev 124990)
@@ -32,19 +32,28 @@
 
 class _Py3ClassAdvice(object):
 
-    def _run_generated_code(self, code, globs, locs, fails_under_py3k=True):
-        import sys
-        if sys.version_info[0] < 3:
-            exec(code, globs, locs)
-            return True
-        else:
-            try:
+    def _run_generated_code(self, code, globs, locs,
+                            fails_under_py3k=True,
+                            warnings_under_py2=1):
+        import warnings
+        from zope.interface._compat import PYTHON3
+        with warnings.catch_warnings(record=True) as log:
+            warnings.resetwarnings()
+            if not PYTHON3:
                 exec(code, globs, locs)
-            except TypeError:
-                return False
+                if warnings_under_py2:
+                    self.assertEqual(len(log), warnings_under_py2)
+                    for entry in log:
+                        self.assertEqual(entry.category, DeprecationWarning)
+                return True
             else:
-                if fails_under_py3k:
-                    self.fail("Didn't raise TypeError")
+                try:
+                    exec(code, globs, locs)
+                except TypeError:
+                    return False
+                else:
+                    if fails_under_py3k:
+                        self.fail("Didn't raise TypeError")
  
 
 class DeclarationTests(_SilencePy3Deprecations):
@@ -642,6 +651,7 @@
         return implementsOnly
 
     def test_simple(self):
+        import warnings
         from zope.interface.declarations import implementsOnly
         from zope.interface._compat import PYTHON3
         from zope.interface.interface import InterfaceClass
@@ -654,17 +664,21 @@
             'class Foo(object):'
             '    implementsOnly(IFoo)',
             ])
-        try:
-            exec(CODE, globs, locs)
-        except TypeError:
-            if not PYTHON3:
-                raise
-        else:
-            if PYTHON3:
-                self.fail("Didn't raise TypeError")
-            Foo = locs['Foo']
-            spec = Foo.__implemented__
-            self.assertEqual(list(spec), [IFoo])
+        with warnings.catch_warnings(record=True) as log:
+            warnings.resetwarnings()
+            try:
+                exec(CODE, globs, locs)
+            except TypeError:
+                if not PYTHON3:
+                    raise
+            else:
+                if PYTHON3:
+                    self.fail("Didn't raise TypeError")
+                Foo = locs['Foo']
+                spec = Foo.__implemented__
+                self.assertEqual(list(spec), [IFoo])
+                self.assertEqual(len(log), 1)
+                self.assertEqual(log[0].category, DeprecationWarning)
 
     def test_called_once_from_class_w_bases(self):
         from zope.interface.declarations import implements
@@ -684,7 +698,7 @@
             'class Bar(Foo):'
             '    implementsOnly(IBar)',
             ])
-        if self._run_generated_code(CODE, globs, locs):
+        if self._run_generated_code(CODE, globs, locs, warnings_under_py2=2):
             Bar = locs['Bar']
             spec = Bar.__implemented__
             self.assertEqual(list(spec), [IBar])
@@ -697,6 +711,7 @@
         return implements
 
     def test_called_from_function(self):
+        import warnings
         from zope.interface.declarations import implements
         from zope.interface.interface import InterfaceClass
         IFoo = InterfaceClass("IFoo")
@@ -706,13 +721,19 @@
             'def foo():',
             '    implements(IFoo)'
             ])
-        if self._run_generated_code(CODE, globs, locs, False):
+        if self._run_generated_code(CODE, globs, locs, False, 0):
             foo = locs['foo']
-            self.assertRaises(TypeError, foo)
+            with warnings.catch_warnings(record=True) as log:
+                warnings.resetwarnings()
+                self.assertRaises(TypeError, foo)
+                self.assertEqual(len(log), 1)
+                self.assertEqual(log[0].category, DeprecationWarning)
 
     def test_called_twice_from_class(self):
+        import warnings
         from zope.interface.declarations import implements
         from zope.interface.interface import InterfaceClass
+        from zope.interface._compat import PYTHON3
         IFoo = InterfaceClass("IFoo")
         IBar = InterfaceClass("IBar")
         globs = {'implements': implements, 'IFoo': IFoo, 'IBar': IBar}
@@ -722,12 +743,17 @@
             '    implements(IFoo)',
             '    implements(IBar)',
             ])
-        try:
-            exec(CODE, globs, locs)
-        except TypeError:
-            pass
-        else:
-            self.fail("Didn't raise TypeError")
+        with warnings.catch_warnings(record=True) as log:
+            warnings.resetwarnings()
+            try:
+                exec(CODE, globs, locs)
+            except TypeError:
+                if not PYTHON3:
+                    self.assertEqual(len(log), 2)
+                    for entry in log:
+                        self.assertEqual(entry.category, DeprecationWarning)
+            else:
+                self.fail("Didn't raise TypeError")
 
     def test_called_once_from_class(self):
         from zope.interface.declarations import implements
@@ -1112,8 +1138,10 @@
         return classProvides
 
     def test_called_from_function(self):
+        import warnings
         from zope.interface.declarations import classProvides
         from zope.interface.interface import InterfaceClass
+        from zope.interface._compat import PYTHON3
         IFoo = InterfaceClass("IFoo")
         globs = {'classProvides': classProvides, 'IFoo': IFoo}
         locs = {}
@@ -1123,11 +1151,18 @@
             ])
         exec(CODE, globs, locs)
         foo = locs['foo']
-        self.assertRaises(TypeError, foo)
+        with warnings.catch_warnings(record=True) as log:
+            warnings.resetwarnings()
+            self.assertRaises(TypeError, foo)
+            if not PYTHON3:
+                self.assertEqual(len(log), 1)
+                self.assertEqual(log[0].category, DeprecationWarning)
 
     def test_called_twice_from_class(self):
+        import warnings
         from zope.interface.declarations import classProvides
         from zope.interface.interface import InterfaceClass
+        from zope.interface._compat import PYTHON3
         IFoo = InterfaceClass("IFoo")
         IBar = InterfaceClass("IBar")
         globs = {'classProvides': classProvides, 'IFoo': IFoo, 'IBar': IBar}
@@ -1137,12 +1172,17 @@
             '    classProvides(IFoo)',
             '    classProvides(IBar)',
             ])
-        try:
-            exec(CODE, globs, locs)
-        except TypeError:
-            pass
-        else:
-            self.fail("Didn't raise TypeError")
+        with warnings.catch_warnings(record=True) as log:
+            warnings.resetwarnings()
+            try:
+                exec(CODE, globs, locs)
+            except TypeError:
+                if not PYTHON3:
+                    self.assertEqual(len(log), 2)
+                    for entry in log:
+                        self.assertEqual(entry.category, DeprecationWarning)
+            else:
+                self.fail("Didn't raise TypeError")
 
     def test_called_once_from_class(self):
         from zope.interface.declarations import classProvides



More information about the checkins mailing list