]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Moved twisted/reactor.py to platform/twistedreactor.py.
authorOvidiu Predescu <ovidiu@gmail.com>
Thu, 14 Jul 2011 23:00:02 +0000 (16:00 -0700)
committerOvidiu Predescu <ovidiu@gmail.com>
Thu, 14 Jul 2011 23:00:02 +0000 (16:00 -0700)
twistedreactor.py:
  - cleaned up logging
  - don't try to crash if stop has been called (uses _running to check it)
  - don't add reader and writers if they've already been added
  - use a NullContext when calling add_handler
  - call IOLoop.close() to properly close file descriptors
  - implement run() and instruct the reactor to not install signal handlers.

import_test.py:
  - import twistedreactor too

twistedreactor_test.py:
  - do conditional includes based on twisted
  - remove superfluous logging
  - don't use assertGreater
  - use threading instead of the thread module. Join threads at the end of test.
  - properly close the file descriptor in Reader/Writer's connectionLost().
  - make use of tornado.platform.auto's set_close_exec.
  - write only one in the pipe, and check for that.

tornado/platform/twistedreactor.py [moved from tornado/twisted/reactor.py with 84% similarity]
tornado/test/import_test.py
tornado/test/twistedreactor_test.py
tornado/twisted/__init__.py [deleted file]

similarity index 84%
rename from tornado/twisted/reactor.py
rename to tornado/platform/twistedreactor.py
index 4f3d1fc7104d82443c978992a3cc539d5c969cb0..54520ead8dcc1dfbab57212e6a28b580d22a57a2 100644 (file)
@@ -18,12 +18,14 @@ A twisted-style reactor for the Tornado IOLoop.
 
 To use it, add the following to your twisted application:
 
-import tornado.twisted.reactor
-tornado.twisted.reactor.install()
+import tornado.platform.twistedreactor
+tornado.platform.twistedreactor.install()
 from twisted.internet import reactor
 """
 
-import errno, functools, sys
+import functools
+import logging
+import sys
 import time
 
 from twisted.internet.base import DelayedCall
@@ -35,6 +37,7 @@ from zope.interface import implements
 
 import tornado
 import tornado.ioloop
+from tornado.stack_context import NullContext
 from tornado.ioloop import IOLoop
 
 class TornadoDelayedCall(object):
@@ -57,7 +60,7 @@ class TornadoDelayedCall(object):
         try:
             self._func()
         except:
-            print "reactor.py _called caught exception: %s" % sys.exc_info()[0]
+            logging.error("_called caught exception", exc_info=True)
 
     def getTime(self):
         return self._time
@@ -96,7 +99,7 @@ class TornadoReactor(PosixReactorBase):
         self._writers = {}
         self._fds = {} # a map of fd to a (reader, writer) tuple
         self._delayedCalls = {}
-        # self._waker = None
+        self._running = False
         PosixReactorBase.__init__(self)
 
     # IReactorTime
@@ -144,6 +147,9 @@ class TornadoReactor(PosixReactorBase):
         """
         Add a FileDescriptor for notification of data available to read.
         """
+        if reader in self._readers:
+            # Don't add the reader if it's already there
+            return
         self._readers[reader] = True
         fd = reader.fileno()
         if fd in self._fds:
@@ -154,13 +160,17 @@ class TornadoReactor(PosixReactorBase):
                 # update it for read events as well.
                 self._ioloop.update_handler(fd, IOLoop.READ | IOLoop.WRITE)
         else:
-            self._fds[fd] = (reader, None)
-            self._ioloop.add_handler(fd, self._invoke_callback, IOLoop.READ)
+            with NullContext():
+                self._fds[fd] = (reader, None)
+                self._ioloop.add_handler(fd, self._invoke_callback,
+                                         IOLoop.READ)
 
     def addWriter(self, writer):
         """
         Add a FileDescriptor for notification of data available to write.
         """
+        if writer in self._writers:
+            return
         self._writers[writer] = True
         fd = writer.fileno()
         if fd in self._fds:
@@ -171,8 +181,10 @@ class TornadoReactor(PosixReactorBase):
                 # update it for write events as well.
                 self._ioloop.update_handler(fd, IOLoop.READ | IOLoop.WRITE)
         else:
-            self._fds[fd] = (None, writer)
-            self._ioloop.add_handler(fd, self._invoke_callback, IOLoop.WRITE)
+            with NullContext():
+                self._fds[fd] = (None, writer)
+                self._ioloop.add_handler(fd, self._invoke_callback,
+                                         IOLoop.WRITE)
 
     def removeReader(self, reader):
         """
@@ -227,22 +239,39 @@ class TornadoReactor(PosixReactorBase):
         """
         Implement L{IReactorCore.stop}.
         """
+        self._running = False
         PosixReactorBase.stop(self)
         self.runUntilCurrent()
-        self._ioloop.stop()
+        try:
+            self._ioloop.stop()
+            self._ioloop.close()
+        except:
+            # Ignore any exceptions thrown by IOLoop
+            pass
 
     def crash(self):
+        if not self._running:
+            return
+        self._running = False
         PosixReactorBase.crash(self)
         self.runUntilCurrent()
-        self._ioloop.stop()
+        try:
+            self._ioloop.stop()
+            self._ioloop.close()
+        except:
+            # Ignore any exceptions thrown by IOLoop
+            pass
 
     def doIteration(self, delay):
         raise NotImplementedError("doIteration")
 
     def mainLoop(self):
-        self.running = True
+        self._running = True
         self._ioloop.start()
 
+    def run(self):
+        PosixReactorBase.run(self, installSignalHandlers=False)
+
 def install(ioloop=None):
     """
     Install the Tornado reactor.
index 2275a1165815a887418be70426b135971483525b..59734503a578466a4ac2d67ced595a03e057a994 100644 (file)
@@ -9,6 +9,7 @@ class ImportTest(unittest.TestCase):
         import tornado.autoreload
         # import tornado.curl_httpclient  # depends on pycurl
         # import tornado.database  # depends on MySQLdb
+        # import tornado.platform.twistedreactor # depends on twisted
         import tornado.escape
         import tornado.httpclient
         import tornado.httpserver
index 7f9a383be91582e96faa68369451b32e8bcf7aaf..cc4e2f1f7c29a36c48ca1f719c7c284ae384732a 100644 (file)
@@ -21,19 +21,21 @@ import fcntl
 import os
 import sys
 import thread
+import threading
 import unittest
 
-from twisted.internet.interfaces import IReadDescriptor, IWriteDescriptor
-from twisted.python import log
-from tornado.platform.auto import Waker
+try:
+    import twisted
+    from twisted.internet.interfaces import IReadDescriptor, IWriteDescriptor
+    from tornado.platform.twistedreactor import TornadoReactor
+    from zope.interface import implements
+except ImportError:
+    twisted = None
+    IReadDescriptor = IWriteDescriptor = None
+    def implements(f): pass
 
 from tornado.ioloop import IOLoop
-from tornado.twisted.reactor import TornadoReactor
-from tornado.testing import AsyncTestCase, LogTrapTestCase
-
-from zope.interface import implements
-
-log.startLogging(sys.stdout)
+from tornado.platform.auto import set_close_exec
 
 class ReactorWhenRunningTest(unittest.TestCase):
     def setUp(self):
@@ -67,7 +69,7 @@ class ReactorCallLaterTest(unittest.TestCase):
         self.assertEqual(self._reactor.getDelayedCalls(), [dc])
         self._reactor.run()
         self.assertTrue(self._laterCalled)
-        self.assertGreater(self._called - self._now, self._timeout)
+        self.assertTrue(self._called - self._now > self._timeout)
         self.assertEqual(self._reactor.getDelayedCalls(), [])
 
     def callLaterCallback(self):
@@ -92,8 +94,8 @@ class ReactorTwoCallLaterTest(unittest.TestCase):
         self._reactor.run()
         self.assertTrue(self._later1Called)
         self.assertTrue(self._later2Called)
-        self.assertGreater(self._called1 - self._now, self._timeout1)
-        self.assertGreater(self._called2 - self._now, self._timeout2)
+        self.assertTrue(self._called1 - self._now > self._timeout1)
+        self.assertTrue(self._called2 - self._now > self._timeout2)
         self.assertEqual(self._reactor.getDelayedCalls(), [])
 
     def callLaterCallback1(self):
@@ -110,8 +112,11 @@ class ReactorCallFromThreadTest(unittest.TestCase):
         self._reactor = TornadoReactor(IOLoop())
         self._mainThread = thread.get_ident()
 
-    def _newThreadRun(self, a, b):
-        self.assertEqual(self._thread, thread.get_ident())
+    def tearDown(self):
+        self._thread.join()
+
+    def _newThreadRun(self):
+        self.assertEqual(self._thread.ident, thread.get_ident())
         self._reactor.callFromThread(self._fnCalledFromThread)
 
     def _fnCalledFromThread(self):
@@ -119,7 +124,8 @@ class ReactorCallFromThreadTest(unittest.TestCase):
         self._reactor.stop()
 
     def _whenRunningCallback(self):
-        self._thread = thread.start_new_thread(self._newThreadRun, (None, None))
+        self._thread = threading.Thread(target=self._newThreadRun)
+        self._thread.start()
 
     def testCallFromThread(self):
         self._reactor.callWhenRunning(self._whenRunningCallback)
@@ -154,7 +160,7 @@ class Reader:
         return self._fd.fileno()
 
     def connectionLost(self, reason):
-        return
+        self._fd.close()
 
     def doRead(self):
         self._callback(self._fd)
@@ -172,16 +178,12 @@ class Writer:
         return self._fd.fileno()
 
     def connectionLost(self, reason):
-        return
+        self._fd.close()
 
     def doWrite(self):
         self._callback(self._fd)
 
 class ReactorReaderWriterTest(unittest.TestCase):
-    def _set_close_exec(self, fd):
-        flags = fcntl.fcntl(fd, fcntl.F_GETFD)
-        fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)
-
     def _set_nonblocking(self, fd):
         flags = fcntl.fcntl(fd, fcntl.F_GETFL)
         fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
@@ -191,8 +193,8 @@ class ReactorReaderWriterTest(unittest.TestCase):
         r, w = os.pipe()
         self._set_nonblocking(r)
         self._set_nonblocking(w)
-        self._set_close_exec(r)
-        self._set_close_exec(w)
+        set_close_exec(r)
+        set_close_exec(w)
         self._p1 = os.fdopen(r, "rb", 0)
         self._p2 = os.fdopen(w, "wb", 0)
 
@@ -201,28 +203,40 @@ class ReactorReaderWriterTest(unittest.TestCase):
         In this test the writer writes an 'x' to its fd. The reader
         reads it, check the value and ends the test.
         """
+        self.shouldWrite = True
         def checkReadInput(fd):
-            self.assertTrue(fd.read().startswith('x'))
+            self.assertEquals(fd.read(), 'x')
             self._reactor.stop()
+        def writeOnce(fd):
+            if self.shouldWrite:
+                self.shouldWrite = False
+                fd.write('x')
         self._reader = Reader(self._p1, checkReadInput)
-        self._writer = Writer(self._p2, lambda fd: fd.write('x'))
+        self._writer = Writer(self._p2, writeOnce)
+
+        # Test that adding and removing the writer doesn't cause
+        # unintended effects.
         self._reactor.addWriter(self._writer)
         self._reactor.removeWriter(self._writer)
         self._reactor.addWriter(self._writer)
-        # Test the add/remove reader functionality
-        self._reactor.addReader(self._writer)
-        self._reactor.removeReader(self._writer)
 
+        # Test that adding and removing the reader doesn't cause
+        # unintended effects.
         self._reactor.addReader(self._reader)
         self._reactor.removeReader(self._reader)
         self._reactor.addReader(self._reader)
-        # Test the add/remove writer functionality
-        self._reactor.addWriter(self._reader)
-        self._reactor.removeWriter(self._reader)
 
     def testReadWrite(self):
         self._reactor.callWhenRunning(self._testReadWrite)
         self._reactor.run()
 
+if twisted is None:
+    del ReactorWhenRunningTest
+    del ReactorCallLaterTest
+    del ReactorTwoCallLaterTest
+    del ReactorCallFromThreadTest
+    del ReactorCallInThread
+    del ReactorReaderWriterTest
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/tornado/twisted/__init__.py b/tornado/twisted/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000