From: Ben Darnell Date: Fri, 15 Mar 2013 03:45:48 +0000 (-0400) Subject: Rename WebSocketConnect to websocket_connect. X-Git-Tag: v3.0.0~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=059f0e8dbe7ea459a5bc6a7d4dbd3b1afd40a7f8;p=thirdparty%2Ftornado.git Rename WebSocketConnect to websocket_connect. Add docs for undocumented functions and modules. --- diff --git a/docs/concurrent.rst b/docs/concurrent.rst new file mode 100644 index 000000000..c41a3dc01 --- /dev/null +++ b/docs/concurrent.rst @@ -0,0 +1,5 @@ +``tornado.concurrent`` --- Work with threads and futures +======================================================== + +.. automodule:: tornado.concurrent + :members: diff --git a/docs/ioloop.rst b/docs/ioloop.rst index 171ff38be..c22f414d3 100644 --- a/docs/ioloop.rst +++ b/docs/ioloop.rst @@ -14,6 +14,8 @@ .. automethod:: IOLoop.instance .. automethod:: IOLoop.initialized .. automethod:: IOLoop.install + .. automethod:: IOLoop.current + .. automethod:: IOLoop.make_current .. automethod:: IOLoop.start .. automethod:: IOLoop.stop .. automethod:: IOLoop.run_sync diff --git a/docs/networking.rst b/docs/networking.rst index f71de718a..e11b0531a 100644 --- a/docs/networking.rst +++ b/docs/networking.rst @@ -7,3 +7,4 @@ Asynchronous networking iostream httpclient netutil + tcpserver diff --git a/docs/releases/next.rst b/docs/releases/next.rst index 89478dfd6..e5a146297 100644 --- a/docs/releases/next.rst +++ b/docs/releases/next.rst @@ -430,6 +430,6 @@ Multiple modules ~~~~~~~~~~~~~~~~~~~ * Client-side WebSocket support is now available: - `tornado.websocket.WebSocketConnect` + `tornado.websocket.websocket_connect` * `WebSocketHandler` has new methods `ping` and `on_pong` to send pings to the browser (not supported on the ``draft76`` protocol) diff --git a/docs/tcpserver.rst b/docs/tcpserver.rst new file mode 100644 index 000000000..3456cc903 --- /dev/null +++ b/docs/tcpserver.rst @@ -0,0 +1,5 @@ +``tornado.tcpserver`` --- Basic `IOStream`-based TCP server +=========================================================== + +.. automodule:: tornado.tcpserver + :members: diff --git a/docs/utilities.rst b/docs/utilities.rst index 077cfda3a..239c3c0ba 100644 --- a/docs/utilities.rst +++ b/docs/utilities.rst @@ -4,6 +4,7 @@ Utilities .. toctree:: autoreload + concurrent gen httputil log diff --git a/docs/websocket.rst b/docs/websocket.rst index 0b6894407..793a665fb 100644 --- a/docs/websocket.rst +++ b/docs/websocket.rst @@ -31,3 +31,11 @@ .. automethod:: WebSocketHandler.async_callback .. automethod:: WebSocketHandler.ping .. automethod:: WebSocketHandler.on_pong + + + Client-side support + ------------------- + + .. autofunction:: websocket_connect + .. autoclass:: WebSocketClientConnection + :members: diff --git a/tornado/concurrent.py b/tornado/concurrent.py index 6b0121d7d..f8ad0e2fb 100644 --- a/tornado/concurrent.py +++ b/tornado/concurrent.py @@ -132,6 +132,11 @@ dummy_executor = DummyExecutor() def run_on_executor(fn): + """Decorator to run a synchronous method asynchronously on an executor. + + The decorated method may be called with a ``callback`` keyword + argument and returns a future. + """ @functools.wraps(fn) def wrapper(self, *args, **kwargs): callback = kwargs.pop("callback", None) @@ -165,6 +170,7 @@ def return_future(f): `gen.engine` function, or passing it to `IOLoop.add_future`). Usage:: + @return_future def future_func(arg1, arg2, callback): # Do stuff (possibly asynchronous) diff --git a/tornado/httpserver.py b/tornado/httpserver.py index 13ed97cb4..c52adbf8d 100644 --- a/tornado/httpserver.py +++ b/tornado/httpserver.py @@ -191,6 +191,11 @@ class HTTPConnection(object): self._close_callback = None def set_close_callback(self, callback): + """Sets a callback that will be run when the connection is closed. + + Use this instead of accessing `HTTPConnection.stream.set_close_callback` + directly (which was the recommended approach prior to Tornado 3.0). + """ self._close_callback = stack_context.wrap(callback) self.stream.set_close_callback(self._on_connection_close) diff --git a/tornado/ioloop.py b/tornado/ioloop.py index 2c5152215..e63ac631c 100644 --- a/tornado/ioloop.py +++ b/tornado/ioloop.py @@ -163,12 +163,31 @@ class IOLoop(Configurable): @staticmethod def current(): + """Returns the current thread's `IOLoop`. + + If an `IOLoop` is currently running or has been marked as current + by `make_current`, returns that instance. Otherwise returns + `IOLoop.instance()`, i.e. the main thread's `IOLoop`. + + In general you should use `IOLoop.current` as the default when + constructing an asynchronous object, and use `IOLoop.instance` + when you mean to communicate to the main thread from a different + one. + """ current = getattr(IOLoop._current, "instance", None) if current is None: return IOLoop.instance() return current def make_current(self): + """Makes this the `IOLoop` for the current thread. + + An `IOLoop` automatically becomes current for its thread + when it is started, but it is sometimes useful to call + `make_current` explictly before starting the `IOLoop`, + so that code run at startup time can find the right + instance. + """ IOLoop._current.instance = self @staticmethod diff --git a/tornado/netutil.py b/tornado/netutil.py index 86a3fa437..cbf0f8004 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -160,6 +160,22 @@ def is_valid_ip(ip): class Resolver(Configurable): + """Configurable asynchronous DNS resolver interface. + + By default, a blocking implementation is used (which simply + calls `socket.getaddrinfo`). An alternative implementation + can be chosen with the `Resolver.configure` class method:: + + Resolver.configure('tornado.netutil.ThreadedResolver') + + The implementations of this interface included with Tornado are + + * `tornado.netutil.BlockingResolver` + * `tornado.netutil.ThreadedResolver` + * `tornado.netutil.OverrideResolver` + * `tornado.platform.twisted.TwistedResolver` + * `tornado.platform.caresresolver.CaresResolver` + """ @classmethod def configurable_base(cls): return Resolver @@ -199,11 +215,27 @@ class ExecutorResolver(Resolver): class BlockingResolver(ExecutorResolver): + """Default `Resolver` implementation, using `socket.getaddrinfo`. + + The `IOLoop` will be blocked during the resolution, although the + callback will not be run until the next `IOLoop` iteration. + """ def initialize(self, io_loop=None): super(BlockingResolver, self).initialize(io_loop=io_loop) class ThreadedResolver(ExecutorResolver): + """Multithreaded non-blocking `Resolver` implementation. + + Requires the `concurrent.futures` package to be installed + (available in the standard library since Python 3.2, + installable with ``pip install futures`` in older versions). + + The thread pool size can be configured with:: + + Resolver.configure('tornado.netutil.ThreadedResolver', + num_threads=10) + """ def initialize(self, io_loop=None, num_threads=10): from concurrent.futures import ThreadPoolExecutor super(ThreadedResolver, self).initialize( diff --git a/tornado/test/websocket_test.py b/tornado/test/websocket_test.py index 5cd7f0f97..eb961d24f 100644 --- a/tornado/test/websocket_test.py +++ b/tornado/test/websocket_test.py @@ -1,6 +1,6 @@ from tornado.testing import AsyncHTTPTestCase, gen_test from tornado.web import Application -from tornado.websocket import WebSocketHandler, WebSocketConnect +from tornado.websocket import WebSocketHandler, websocket_connect class EchoHandler(WebSocketHandler): @@ -16,7 +16,7 @@ class WebSocketTest(AsyncHTTPTestCase): @gen_test def test_websocket_gen(self): - ws = yield WebSocketConnect( + ws = yield websocket_connect( 'ws://localhost:%d/echo' % self.get_http_port(), io_loop=self.io_loop) ws.write_message('hello') @@ -24,7 +24,7 @@ class WebSocketTest(AsyncHTTPTestCase): self.assertEqual(response, 'hello') def test_websocket_callbacks(self): - WebSocketConnect( + websocket_connect( 'ws://localhost:%d/echo' % self.get_http_port(), io_loop=self.io_loop, callback=self.stop) ws = self.wait().result() diff --git a/tornado/websocket.py b/tornado/websocket.py index 4bff6cd03..cf1e6d1cf 100644 --- a/tornado/websocket.py +++ b/tornado/websocket.py @@ -718,7 +718,8 @@ class WebSocketProtocol13(WebSocketProtocol): self.stream.io_loop.time() + 5, self._abort) -class _WebSocketClientConnection(simple_httpclient._HTTPConnection): +class WebSocketClientConnection(simple_httpclient._HTTPConnection): + """WebSocket client connection.""" def __init__(self, io_loop, request): self.connect_future = Future() self.read_future = None @@ -735,7 +736,7 @@ class _WebSocketClientConnection(simple_httpclient._HTTPConnection): 'Sec-WebSocket-Version': '13', }) - super(_WebSocketClientConnection, self).__init__( + super(WebSocketClientConnection, self).__init__( io_loop, None, request, lambda: None, lambda response: None, 104857600, Resolver(io_loop=io_loop)) @@ -759,9 +760,17 @@ class _WebSocketClientConnection(simple_httpclient._HTTPConnection): self.connect_future.set_result(self) def write_message(self, message, binary=False): + """Sends a message to the WebSocket server.""" self.protocol.write_message(message, binary) def read_message(self, callback=None): + """Reads a message from the WebSocket server. + + Returns a future whose result is the message, or None + if the connection is closed. If a callback argument + is given it will be called with the future when it is + ready. + """ assert self.read_future is None future = Future() if self.read_queue: @@ -783,13 +792,17 @@ class _WebSocketClientConnection(simple_httpclient._HTTPConnection): pass -def WebSocketConnect(url, io_loop=None, callback=None): +def websocket_connect(url, io_loop=None, callback=None): + """Client-side websocket support. + + Takes a url and returns a Future whose result is a `WebSocketConnection`. + """ if io_loop is None: io_loop = IOLoop.current() request = httpclient.HTTPRequest(url) request = httpclient._RequestProxy( request, httpclient.HTTPRequest._DEFAULTS) - conn = _WebSocketClientConnection(io_loop, request) + conn = WebSocketClientConnection(io_loop, request) if callback is not None: io_loop.add_future(conn.connect_future, callback) return conn.connect_future