--- /dev/null
+#!/usr/bin/env python
+#
+# Copyright 2012 Facebook
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+from __future__ import absolute_import, division, with_statement
+
+import functools
+import sys
+
+from tornado.util import raise_exc_info
+
+try:
+ from concurrent import futures
+except ImportError:
+ futures = None
+
+
+class DummyFuture(object):
+ def __init__(self, result, exc_info=None):
+ self._result = result
+ self._exc_info = exc_info
+
+ def cancel(self):
+ return False
+
+ def cancelled(self):
+ return False
+
+ def running(self):
+ return False
+
+ def done(self):
+ return True
+
+ def result(self, timeout=None):
+ if self._exc_info:
+ raise_exc_info(self._exc_info)
+ return self._result
+
+ def exception(self, timeout=None):
+ if self._exc_info:
+ return self._exc_info[1]
+ else:
+ return None
+
+ def add_done_callback(self, fn):
+ fn(self)
+
+
+class DummyExecutor(object):
+ def submit(self, fn, *args, **kwargs):
+ try:
+ return DummyFuture(fn(*args, **kwargs))
+ except Exception:
+ return DummyFuture(result=None, exc_info=sys.exc_info())
+
+dummy_executor = DummyExecutor()
+
+def run_on_executor(fn):
+ @functools.wraps(fn)
+ def wrapper(self, *args, **kwargs):
+ callback = kwargs.pop("callback")
+ future = self.executor.submit(fn, self, *args, **kwargs)
+ if callback:
+ self.io_loop.add_future(future, callback)
+ return future
+ return wrapper
import time
import traceback
+from tornado.concurrent import DummyFuture
from tornado import stack_context
try:
# avoid it when we can.
self._waker.wake()
+ if futures is not None:
+ _FUTURE_TYPES = (futures.Future, DummyFuture)
+ else:
+ _FUTURE_TYPES = DummyFuture
def add_future(self, future, callback):
"""Schedules a callback on the IOLoop when the given future is finished.
-
- Requires the concurrent.futures module (standard in python 3.2+,
- available via "pip install futures" in older versions).
"""
- assert isinstance(future, futures.Future)
+ assert isinstance(future, IOLoop._FUTURE_TYPES)
future.add_done_callback(
lambda future: self.add_callback(
functools.partial(callback, future)))
from __future__ import absolute_import, division, with_statement
import errno
+import functools
import logging
import os
import socket
import stat
from tornado import process
+from tornado.concurrent import DummyFuture, dummy_executor, run_on_executor
from tornado.ioloop import IOLoop
from tornado.iostream import IOStream, SSLIOStream
from tornado.platform.auto import set_close_exec
raise
callback(connection, address)
io_loop.add_handler(sock.fileno(), accept_handler, IOLoop.READ)
+
+
+class Resolver(object):
+ def __init__(self, io_loop=None, executor=None):
+ self.io_loop = io_loop or IOLoop.instance()
+ self.executor = executor or dummy_executor
+
+ @run_on_executor
+ def getaddrinfo(self, *args, **kwargs):
+ return socket.getaddrinfo(*args, **kwargs)
self.assertTrue(future.done())
self.assertTrue(future.result() is None)
TestIOLoopFutures = unittest.skipIf(
- futures is None, "futures module is not present")(TestIOLoopFutures)
+ futures is None, "futures module not present")(TestIOLoopFutures)
if __name__ == "__main__":
--- /dev/null
+from __future__ import absolute_import, division, with_statement
+
+import socket
+
+from tornado.netutil import Resolver
+from tornado.testing import AsyncTestCase
+from tornado.test.util import unittest
+
+try:
+ from concurrent import futures
+except ImportError:
+ futures = None
+
+class _ResolverTestMixin(object):
+ def test_localhost(self):
+ self.resolver.getaddrinfo('localhost', 80, socket.AF_UNSPEC,
+ socket.SOCK_STREAM,
+ callback=self.stop)
+ future = self.wait()
+ self.assertIn(
+ (socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, '',
+ ('127.0.0.1', 80)),
+ future.result())
+
+
+class SyncResolverTest(AsyncTestCase, _ResolverTestMixin):
+ def setUp(self):
+ super(SyncResolverTest, self).setUp()
+ self.resolver = Resolver(self.io_loop)
+
+class ThreadedResolverTest(AsyncTestCase, _ResolverTestMixin):
+ def setUp(self):
+ super(ThreadedResolverTest, self).setUp()
+ from concurrent.futures import ThreadPoolExecutor
+ self.resolver = Resolver(self.io_loop, ThreadPoolExecutor(2))
+ThreadedResolverTest = unittest.skipIf(
+ futures is None, "futures module not present")(ThreadedResolverTest)
'tornado.test.ioloop_test',
'tornado.test.iostream_test',
'tornado.test.locale_test',
+ 'tornado.test.netutil_test',
'tornado.test.options_test',
'tornado.test.process_test',
'tornado.test.simple_httpclient_test',