]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Add a convert_yield adapter for twisted Deferreds.
authorBen Darnell <ben@bendarnell.com>
Mon, 19 Jan 2015 16:20:45 +0000 (11:20 -0500)
committerBen Darnell <ben@bendarnell.com>
Mon, 19 Jan 2015 16:20:45 +0000 (11:20 -0500)
tornado/platform/twisted.py
tornado/test/twisted_test.py

index ccb44de8b8a8884880549369f261fe548e3a9b5a..09b328366b6796dccaa69f7d40f59794fd814dd5 100644 (file)
@@ -70,8 +70,10 @@ import datetime
 import functools
 import numbers
 import socket
+import sys
 
 import twisted.internet.abstract
+from twisted.internet.defer import Deferred
 from twisted.internet.posixbase import PosixReactorBase
 from twisted.internet.interfaces import \
     IReactorFDSet, IDelayedCall, IReactorTime, IReadDescriptor, IWriteDescriptor
@@ -84,6 +86,7 @@ import twisted.names.resolve
 
 from zope.interface import implementer
 
+from tornado.concurrent import Future
 from tornado.escape import utf8
 from tornado import gen
 import tornado.ioloop
@@ -564,3 +567,17 @@ class TwistedResolver(Resolver):
             (resolved_family, (resolved, port)),
         ]
         raise gen.Return(result)
+
+if hasattr(gen.convert_yielded, 'register'):
+    @gen.convert_yielded.register(Deferred)
+    def _(d):
+        f = Future()
+        def errback(failure):
+            try:
+                failure.raiseException()
+                # Should never happen, but just in case
+                raise Exception("errback called without error")
+            except:
+                f.set_exc_info(sys.exc_info())
+        d.addCallbacks(f.set_result, errback)
+        return f
index 2922a61e000507536aa5546cff0748bf7aab4c38..3ceffa77c7f9aa7d2bebf9cb748de6abef192169 100644 (file)
@@ -27,7 +27,7 @@ import threading
 
 try:
     import fcntl
-    from twisted.internet.defer import Deferred
+    from twisted.internet.defer import Deferred, inlineCallbacks, returnValue
     from twisted.internet.interfaces import IReadDescriptor, IWriteDescriptor
     from twisted.internet.protocol import Protocol
     from twisted.python import log
@@ -40,7 +40,7 @@ except ImportError:
 # The core of Twisted 12.3.0 is available on python 3, but twisted.web is not
 # so test for it separately.
 try:
-    from twisted.web.client import Agent
+    from twisted.web.client import Agent, readBody
     from twisted.web.resource import Resource
     from twisted.web.server import Site
     have_twisted_web = True
@@ -52,6 +52,7 @@ try:
 except ImportError:
     import _thread as thread  # py3
 
+from tornado import gen
 from tornado.httpclient import AsyncHTTPClient
 from tornado.httpserver import HTTPServer
 from tornado.ioloop import IOLoop
@@ -65,6 +66,8 @@ from tornado.web import RequestHandler, Application
 skipIfNoTwisted = unittest.skipUnless(have_twisted,
                                       "twisted module not present")
 
+skipIfNoSingleDispatch = unittest.skipIf(
+    gen.singledispatch is None, "singledispatch module not present")
 
 def save_signal_handlers():
     saved = {}
@@ -432,6 +435,21 @@ class CompatibilityTests(unittest.TestCase):
         self.assertTrue(chunks)
         return ''.join(chunks)
 
+    def twisted_coroutine_fetch(self, url, runner):
+        body = [None]
+        @gen.coroutine
+        def f():
+            # This is simpler than the non-coroutine version, but it cheats
+            # by reading the body in one blob instead of streaming it with
+            # a Protocol.
+            client = Agent(self.reactor)
+            response = yield client.request('GET', url)
+            body[0] = yield readBody(response)
+            self.stop_loop()
+        self.io_loop.add_callback(f)
+        runner()
+        return body[0]
+
     def testTwistedServerTornadoClientIOLoop(self):
         self.start_twisted_server()
         response = self.tornado_fetch(
@@ -456,6 +474,37 @@ class CompatibilityTests(unittest.TestCase):
             'http://localhost:%d' % self.tornado_port, self.run_reactor)
         self.assertEqual(response, 'Hello from tornado!')
 
+    @skipIfNoSingleDispatch
+    def testTornadoServerTwistedCoroutineClientIOLoop(self):
+        self.start_tornado_server()
+        response = self.twisted_coroutine_fetch(
+            'http://localhost:%d' % self.tornado_port, self.run_ioloop)
+        self.assertEqual(response, 'Hello from tornado!')
+
+
+@skipIfNoSingleDispatch
+class ConvertDeferredTest(unittest.TestCase):
+    def test_success(self):
+        @inlineCallbacks
+        def fn():
+            if False:
+                # inlineCallbacks doesn't work with regular functions;
+                # must have a yield even if it's unreachable.
+                yield
+            returnValue(42)
+        f = gen.convert_yielded(fn())
+        self.assertEqual(f.result(), 42)
+
+    def test_failure(self):
+        @inlineCallbacks
+        def fn():
+            if False:
+                yield
+            1 / 0
+        f = gen.convert_yielded(fn())
+        with self.assertRaises(ZeroDivisionError):
+            f.result()
+
 
 if have_twisted:
     # Import and run as much of twisted's test suite as possible.