r47126 - Merge oldstyle-decorator-8244-2: Add a decorator which optionally updates old-style classes to new-ones

hawkowl-TA+aISz0psMTMxyoc4vAAJOcrHinNvQL0E9HWUfgJXw@public.gmane.org Thu, 31 Mar 2016 09:39:57 -0600 (MDT)
Newsgroups gmane.comp.python.twisted.commits
Message-ID <[email protected]>
Author: hawkowl
Date: Thu Mar 31 09:39:51 2016
New Revision: 47126

Added:
   trunk/twisted/python/_oldstyle.py
   trunk/twisted/test/test_nooldstyle.py
   trunk/twisted/topfiles/8244.misc
Modified:
   trunk/twisted/python/dist3.py
   trunk/twisted/python/test/test_util.py
   trunk/twisted/python/util.py

Log:
Merge oldstyle-decorator-8244-2: Add a decorator which optionally updates old-style classes to new-ones

Author: hawkowl
Reviewer: glyph
Fixes: #8244

Modified: trunk/twisted/python/dist3.py
==============================================================================
--- trunk/twisted/python/dist3.py	(original)
+++ trunk/twisted/python/dist3.py	Thu Mar 31 09:39:51 2016
@@ -163,6 +163,7 @@
     "twisted.python.__init__",
     "twisted.python._appdirs",
     "twisted.python._tzhelper",
+    "twisted.python._oldstyle",
     "twisted.python._url",
     "twisted.python.compat",
     "twisted.python.components",
@@ -359,9 +360,10 @@
     "twisted.test.test_loopback",
     "twisted.test.test_modules",
     "twisted.test.test_monkey",
+    "twisted.test.test_nooldstyle",
     "twisted.test.test_paths",
-    "twisted.test.test_plugin",
     "twisted.test.test_persisted",
+    "twisted.test.test_plugin",
     "twisted.test.test_policies",
     "twisted.test.test_process",
     "twisted.test.test_randbytes",
@@ -378,8 +380,8 @@
     "twisted.test.test_threadable",
     "twisted.test.test_threadpool",
     "twisted.test.test_threads",
-    "twisted.test.test_twisted",
     "twisted.test.test_twistd",
+    "twisted.test.test_twisted",
     "twisted.test.test_udp",
     "twisted.test.test_unix",
     "twisted.test.test_usage",

Modified: trunk/twisted/python/test/test_util.py
==============================================================================
--- trunk/twisted/python/test/test_util.py	(original)
+++ trunk/twisted/python/test/test_util.py	Thu Mar 31 09:39:51 2016
@@ -1117,3 +1117,66 @@
         items = []
         util.padTo(4, items)
         self.assertEqual([], items)
+
+
+
+class ReplaceIfTests(unittest.TestCase):
+    """
+    Tests for L{util._replaceIf}.
+    """
+
+    def test_replacesIfTrue(self):
+        """
+        L{util._replaceIf} swaps out the body of a function if the conditional
+        is C{True}.
+        """
+        @util._replaceIf(True, lambda: "hi")
+        def test():
+            return "bye"
+
+        self.assertEqual(test(), "hi")
+        self.assertEqual(test.__name__, "test")
+        self.assertEqual(test.__module__, "twisted.python.test.test_util")
+
+
+    def test_keepsIfFalse(self):
+        """
+        L{util._replaceIf} keeps the original body of the function if the
+        conditional is C{False}.
+        """
+        @util._replaceIf(False, lambda: "hi")
+        def test():
+            return "bye"
+
+        self.assertEqual(test(), "bye")
+
+
+    def test_multipleReplace(self):
+        """
+        In the case that multiple conditions are true, the first one
+        (to the reader) is chosen by L{util._replaceIf}
+        """
+        @util._replaceIf(True, lambda: "hi")
+        @util._replaceIf(False, lambda: "bar")
+        @util._replaceIf(True, lambda: "baz")
+        def test():
+            return "bye"
+
+        self.assertEqual(test(), "hi")
+
+
+    def test_boolsOnly(self):
+        """
+        L{util._replaceIf}'s condition argument only accepts bools.
+        """
+        with self.assertRaises(ValueError) as e:
+
+            @util._replaceIf("hi", "there")
+            def test():
+                """
+                Some test function.
+                """
+
+        self.assertEqual(e.exception.args[0],
+                         ("condition argument to _replaceIf requires a bool, "
+                          "not 'hi'"))

Modified: trunk/twisted/python/util.py
==============================================================================
--- trunk/twisted/python/util.py	(original)
+++ trunk/twisted/python/util.py	Thu Mar 31 09:39:51 2016
@@ -14,6 +14,8 @@
 except ImportError:
     setgroups = getgroups = None
 
+from functools import wraps
+
 from twisted.python.compat import _PY3, unicode
 from twisted.python.versions import Version
 from twisted.python.deprecate import deprecatedModuleAttribute
@@ -905,6 +907,37 @@
 
 
 
+def _replaceIf(condition, alternative):
+    """
+    If C{condition}, replace this function with C{alternative}.
+
+    @param condition: A L{bool} which says whether this should be replaced.
+
+    @param alternative: An alternative function that will be swapped in instead
+        of the original, if C{condition} is truthy.
+
+    @return: A decorator.
+    """
+    def decorator(func):
+
+        if condition is True:
+            call = alternative
+        elif condition is False:
+            call = func
+        else:
+            raise ValueError(("condition argument to _replaceIf requires a "
+                              "bool, not {}").format(repr(condition)))
+
+        @wraps(func)
+        def wrapped(*args, **kwargs):
+            return call(*args, **kwargs)
+
+        return wrapped
+
+    return decorator
+
+
+
 __all__ = [
     "uniquify", "padTo", "getPluginDirs", "addPluginDir", "sibpath",
     "getPassword", "println", "makeStatBar", "OrderedDict",