-``tornado.httpclient`` --- Non-blocking HTTP client
+``tornado.httpclient`` --- Asynchronous HTTP client
===================================================
.. automodule:: tornado.httpclient
Running an IOLoop
^^^^^^^^^^^^^^^^^
+ .. automethod:: IOLoop.current
+ .. automethod:: IOLoop.make_current
.. 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
not-quite-compliant with the HTTP spec, or sites that use little-exercised
features of HTTP.
-* ``simple_httpclient`` only supports SSL on Python 2.6 and above.
-
-* ``curl_httpclient`` is faster
+* ``curl_httpclient`` is faster.
* ``curl_httpclient`` was the default prior to Tornado 2.0.
try:
response = http_client.fetch("http://www.google.com/")
print response.body
- except httpclient.HTTPError, e:
+ except httpclient.HTTPError as e:
print "Error:", e
+ httpclient.close()
"""
def __init__(self, async_client_class=None, **kwargs):
self._io_loop = IOLoop()
Example usage::
- import ioloop
-
def handle_request(response):
if response.error:
print "Error:", response.error
else:
print response.body
- ioloop.IOLoop.instance().stop()
- http_client = httpclient.AsyncHTTPClient()
+ http_client = AsyncHTTPClient()
http_client.fetch("http://www.google.com/", handle_request)
- ioloop.IOLoop.instance().start()
-
- The constructor for this class is magic in several respects: It actually
- creates an instance of an implementation-specific subclass, and instances
- are reused as a kind of pseudo-singleton (one per IOLoop). The keyword
- argument force_instance=True can be used to suppress this singleton
- behavior. Constructor arguments other than io_loop and force_instance
- are deprecated. The implementation subclass as well as arguments to
- its constructor can be set with the static method configure()
+
+ The constructor for this class is magic in several respects: It
+ actually creates an instance of an implementation-specific
+ subclass, and instances are reused as a kind of pseudo-singleton
+ (one per `.IOLoop`). The keyword argument ``force_instance=True``
+ can be used to suppress this singleton behavior. Constructor
+ arguments other than ``io_loop`` and ``force_instance`` are
+ deprecated. The implementation subclass as well as arguments to
+ its constructor can be set with the static method `configure()`
"""
@classmethod
def configurable_base(cls):
self.defaults.update(defaults)
def close(self):
- """Destroys this http client, freeing any file descriptors used.
+ """Destroys this HTTP client, freeing any file descriptors used.
Not needed in normal use, but may be helpful in unittests that
create and destroy http clients. No other methods may be called
- on the AsyncHTTPClient after close().
+ on the `AsyncHTTPClient` after ``close()``.
"""
if self._async_clients().get(self.io_loop) is self:
del self._async_clients()[self.io_loop]
def fetch(self, request, callback=None, **kwargs):
- """Executes a request, calling callback with an `HTTPResponse`.
+ """Executes a request, asynchronously returning an `HTTPResponse`.
The request may be either a string URL or an `HTTPRequest` object.
If it is a string, we construct an `HTTPRequest` using any additional
kwargs: ``HTTPRequest(request, **kwargs)``
- If an error occurs during the fetch, the HTTPResponse given to the
- callback has a non-None error attribute that contains the exception
- encountered during the request. You can call response.rethrow() to
- throw the exception (if any) in the callback.
+ This method returns a `~concurrent.futures.Future` whose
+ result is an `HTTPResponse`. The ``Future`` wil raise an
+ `HTTPError` if the request returned a non-200 response code.
+
+ If a ``callback`` is given, it will be invoked with the `HTTPResponse`.
+ In the callback interface, `HTTPError` is not automatically raised.
+ Instead, you must check the response's ``error`` attribute or
+ call its `~HTTPResponse.rethrow` method.
"""
if not isinstance(request, HTTPRequest):
request = HTTPRequest(url=request, **kwargs)
@classmethod
def configure(cls, impl, **kwargs):
- """Configures the AsyncHTTPClient subclass to use.
+ """Configures the `AsyncHTTPClient` subclass to use.
- AsyncHTTPClient() actually creates an instance of a subclass.
+ ``AsyncHTTPClient()`` actually creates an instance of a subclass.
This method may be called with either a class object or the
- fully-qualified name of such a class (or None to use the default,
- SimpleAsyncHTTPClient)
+ fully-qualified name of such a class (or ``None`` to use the default,
+ ``SimpleAsyncHTTPClient``)
If additional keyword arguments are given, they will be passed
to the constructor of each subclass instance created. The
- keyword argument max_clients determines the maximum number of
- simultaneous fetch() operations that can execute in parallel
- on each IOLoop. Additional arguments may be supported depending
- on the implementation class in use.
+ keyword argument ``max_clients`` determines the maximum number
+ of simultaneous `~AsyncHTTPClient.fetch()` operations that can
+ execute in parallel on each `.IOLoop`. Additional arguments
+ may be supported depending on the implementation class in use.
Example::
validate_cert=None, ca_certs=None,
allow_ipv6=None,
client_key=None, client_cert=None):
- r"""Creates an `HTTPRequest`.
-
- All parameters except ``url`` are optional.
+ r"""All parameters except ``url`` are optional.
:arg string url: URL to fetch
:arg string method: HTTP method, e.g. "GET" or "POST"
:arg string auth_password: Password for HTTP "Basic" authentication
:arg float connect_timeout: Timeout for initial connection in seconds
:arg float request_timeout: Timeout for entire request in seconds
- :arg datetime if_modified_since: Timestamp for ``If-Modified-Since``
- header
+ :arg if_modified_since: Timestamp for ``If-Modified-Since`` header
+ :type if_modified_since: `datetime` or `float`
:arg bool follow_redirects: Should redirects be followed automatically
or return the 3xx response?
:arg int max_redirects: Limit for ``follow_redirects``
or None to use defaults. Note that in ``curl_httpclient``, if
any request uses a custom ``ca_certs`` file, they all must (they
don't have to all use the same ``ca_certs``, but it's not possible
- to mix requests with ca_certs and requests that use the defaults.
+ to mix requests with ``ca_certs`` and requests that use the defaults.
:arg bool allow_ipv6: Use IPv6 when available? Default is false in
``simple_httpclient`` and true in ``curl_httpclient``
:arg string client_key: Filename for client SSL key, if any
* code: numeric HTTP status code, e.g. 200 or 404
* reason: human-readable reason phrase describing the status code
- (with curl_httpclient, this is a default value rather than the
- server's actual response)
+ (with curl_httpclient, this is a default value rather than the
+ server's actual response)
- * headers: httputil.HTTPHeaders object
+ * headers: `tornado.httputil.HTTPHeaders` object
- * buffer: cStringIO object for response body
+ * buffer: ``cStringIO`` object for response body
- * body: response body as string (created on demand from self.buffer)
+ * body: response body as string (created on demand from ``self.buffer``)
* error: Exception object, if any
* request_time: seconds from request start to finish
* time_info: dictionary of diagnostic timing information from the request.
- Available data are subject to change, but currently uses timings
- available from http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html,
- plus 'queue', which is the delay (if any) introduced by waiting for
- a slot under AsyncHTTPClient's max_clients setting.
+ Available data are subject to change, but currently uses timings
+ available from http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html,
+ plus ``queue``, which is the delay (if any) introduced by waiting for
+ a slot under `AsyncHTTPClient`'s ``max_clients`` setting.
"""
def __init__(self, request, code, headers=None, buffer=None,
effective_url=None, error=None, request_time=None,
Attributes:
- code - HTTP error integer error code, e.g. 404. Error code 599 is
- used when no HTTP response was received, e.g. for a timeout.
+ * ``code`` - HTTP error integer error code, e.g. 404. Error code 599 is
+ used when no HTTP response was received, e.g. for a timeout.
- response - HTTPResponse object, if any.
+ * ``response`` - `HTTPResponse` object, if any.
- Note that if follow_redirects is False, redirects become HTTPErrors,
- and you can look at error.response.headers['Location'] to see the
+ Note that if ``follow_redirects`` is False, redirects become HTTPErrors,
+ and you can look at ``error.response.headers['Location']`` to see the
destination of the redirect.
"""
def __init__(self, code, message=None, response=None):
requests). A simple example server that echoes back the URI you
requested::
- import httpserver
- import ioloop
+ import tornado.httpserver
+ import tornado.ioloop
def handle_request(request):
message = "You requested %s\n" % request.uri
len(message), message))
request.finish()
- http_server = httpserver.HTTPServer(handle_request)
+ http_server = tornado.httpserver.HTTPServer(handle_request)
http_server.listen(8888)
- ioloop.IOLoop.instance().start()
+ tornado.ioloop.IOLoop.instance().start()
`HTTPServer` is a very basic connection handler. It parses the request
headers and body, but the request callback is responsible for producing
if Tornado is run behind an SSL-decoding proxy that does not set one of
the supported ``xheaders``.
- `HTTPServer` can serve SSL traffic with Python 2.6+ and OpenSSL.
- To make this server serve SSL traffic, send the ssl_options dictionary
+ To make this server serve SSL traffic, send the ``ssl_options`` dictionary
argument with the arguments required for the `ssl.wrap_socket` method,
- including "certfile" and "keyfile". In Python 3.2+ you can pass
- an `ssl.SSLContext` object instead of a dict::
+ including ``certfile`` and ``keyfile``. (In Python 3.2+ you can pass
+ an `ssl.SSLContext` object instead of a dict)::
HTTPServer(applicaton, ssl_options={
"certfile": os.path.join(data_dir, "mydomain.crt"),
class HTTPHeaders(dict):
- """A dictionary that maintains Http-Header-Case for all keys.
+ """A dictionary that maintains ``Http-Header-Case`` for all keys.
Supports multiple values per key via a pair of new methods,
- add() and get_list(). The regular dictionary interface returns a single
- value per key, with multiple values joined by a comma.
+ `add()` and `get_list()`. The regular dictionary interface
+ returns a single value per key, with multiple values joined by a
+ comma.
>>> h = HTTPHeaders({"content-type": "text/html"})
>>> list(h.keys())
class HTTPFile(ObjectDict):
- """Represents an HTTP file. For backwards compatibility, its instance
- attributes are also accessible as dictionary keys.
+ """Represents a file uploaded via a form.
+
+ For backwards compatibility, its instance attributes are also
+ accessible as dictionary keys.
* ``filename``
* ``body``
def parse_body_arguments(content_type, body, arguments, files):
"""Parses a form request body.
- Supports "application/x-www-form-urlencoded" and "multipart/form-data".
- The content_type parameter should be a string and body should be
- a byte string. The arguments and files parameters are dictionaries
- that will be updated with the parsed contents.
+ Supports ``application/x-www-form-urlencoded`` and
+ ``multipart/form-data``. The ``content_type`` parameter should be
+ a string and ``body`` should be a byte string. The ``arguments``
+ and ``files`` parameters are dictionaries that will be updated
+ with the parsed contents.
"""
if content_type.startswith("application/x-www-form-urlencoded"):
uri_arguments = parse_qs_bytes(native_str(body), keep_blank_values=True)
def parse_multipart_form_data(boundary, data, arguments, files):
- """Parses a multipart/form-data body.
+ """Parses a ``multipart/form-data`` body.
- The boundary and data parameters are both byte strings.
+ The ``boundary`` and ``data`` parameters are both byte strings.
The dictionaries given in the arguments and files parameters
will be updated with the contents of the body.
"""
class IOLoop(Configurable):
"""A level-triggered I/O loop.
- We use epoll (Linux) or kqueue (BSD and Mac OS X; requires python
- 2.6+) if they are available, or else we fall back on select(). If
- you are implementing a system that needs to handle thousands of
- simultaneous connections, you should use a system that supports either
- epoll or kqueue.
+ We use ``epoll`` (Linux) or ``kqueue`` (BSD and Mac OS X) if they
+ are available, or else we fall back on select(). If you are
+ implementing a system that needs to handle thousands of
+ simultaneous connections, you should use a system that supports
+ either ``epoll`` or ``kqueue``.
Example usage for a simple TCP server::
@staticmethod
def instance():
- """Returns a global IOLoop instance.
+ """Returns a global `IOLoop` instance.
- Most single-threaded applications have a single, global IOLoop.
- Use this method instead of passing around IOLoop instances
- throughout your code.
-
- A common pattern for classes that depend on IOLoops is to use
- a default argument to enable programs with multiple IOLoops
- but not require the argument for simpler applications::
-
- class MyClass(object):
- def __init__(self, io_loop=None):
- self.io_loop = io_loop or IOLoop.instance()
+ Most applications have a single, global `IOLoop` running on the
+ main thread. Use this method to get this instance from
+ another thread. To get the current thread's `IOLoop`, use `current()`.
"""
if not hasattr(IOLoop, "_instance"):
with IOLoop._instance_lock:
return hasattr(IOLoop, "_instance")
def install(self):
- """Installs this IOloop object as the singleton instance.
+ """Installs this `IOLoop` object as the singleton instance.
This is normally not necessary as `instance()` will create
- an IOLoop on demand, but you may want to call `install` to use
- a custom subclass of IOLoop.
+ an `IOLoop` on demand, but you may want to call `install` to use
+ a custom subclass of `IOLoop`.
"""
assert not IOLoop.initialized()
IOLoop._instance = self
by `make_current`, returns that instance. Otherwise returns
`IOLoop.instance()`, i.e. the main thread's `IOLoop`.
+ A common pattern for classes that depend on ``IOLoops`` is to use
+ a default argument to enable programs with multiple ``IOLoops``
+ but not require the argument for simpler applications::
+
+ class MyClass(object):
+ def __init__(self, io_loop=None):
+ self.io_loop = io_loop or IOLoop.current()
+
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
pass
def close(self, all_fds=False):
- """Closes the IOLoop, freeing any resources used.
+ """Closes the `IOLoop`, freeing any resources used.
If ``all_fds`` is true, all file descriptors registered on the
- IOLoop will be closed (not just the ones created by the IOLoop itself).
+ IOLoop will be closed (not just the ones created by the
+ `IOLoop` itself).
- Many applications will only use a single IOLoop that runs for the
- entire lifetime of the process. In that case closing the IOLoop
+ Many applications will only use a single `IOLoop` that runs for the
+ entire lifetime of the process. In that case closing the `IOLoop`
is not necessary since everything will be cleaned up when the
process exits. `IOLoop.close` is provided mainly for scenarios
such as unit tests, which create and destroy a large number of
- IOLoops.
+ ``IOLoops``.
- An IOLoop must be completely stopped before it can be closed. This
+ An `IOLoop` must be completely stopped before it can be closed. This
means that `IOLoop.stop()` must be called *and* `IOLoop.start()` must
be allowed to return before attempting to call `IOLoop.close()`.
Therefore the call to `close` will usually appear just after
raise NotImplementedError()
def add_handler(self, fd, handler, events):
- """Registers the given handler to receive the given events for fd."""
+ """Registers the given handler to receive the given events for fd.
+
+ The ``events`` argument is a bitwise or of the constants
+ ``IOLoop.READ``, ``IOLoop.WRITE``, and ``IOLoop.ERROR``.
+
+ When an event occurs, ``handler(fd, events)`` will be run.
+ """
raise NotImplementedError()
def update_handler(self, fd, events):
raise NotImplementedError()
def set_blocking_signal_threshold(self, seconds, action):
- """Sends a signal if the ioloop is blocked for more than s seconds.
+ """Sends a signal if the `IOLoop` is blocked for more than
+ ``s`` seconds.
- Pass seconds=None to disable. Requires python 2.6 on a unixy
+ Pass ``seconds=None`` to disable. Requires Python 2.6 on a unixy
platform.
- The action parameter is a python signal handler. Read the
- documentation for the python 'signal' module for more information.
- If action is None, the process will be killed if it is blocked for
- too long.
+ The action parameter is a Python signal handler. Read the
+ documentation for the `signal` module for more information.
+ If ``action`` is None, the process will be killed if it is
+ blocked for too long.
"""
raise NotImplementedError()
def set_blocking_log_threshold(self, seconds):
- """Logs a stack trace if the ioloop is blocked for more than s seconds.
- Equivalent to set_blocking_signal_threshold(seconds, self.log_stack)
+ """Logs a stack trace if the `IOLoop` is blocked for more than
+ ``s`` seconds.
+
+ Equivalent to ``set_blocking_signal_threshold(seconds,
+ self.log_stack)``
"""
self.set_blocking_signal_threshold(seconds, self.log_stack)
def log_stack(self, signal, frame):
"""Signal handler to log the stack trace of the current thread.
- For use with set_blocking_signal_threshold.
+ For use with `set_blocking_signal_threshold`.
"""
gen_log.warning('IOLoop blocked for %f seconds in\n%s',
self._blocking_signal_threshold,
def start(self):
"""Starts the I/O loop.
- The loop will run until one of the I/O handlers calls stop(), which
+ The loop will run until one of the callbacks calls `stop()`, which
will make the loop stop after the current event iteration completes.
"""
raise NotImplementedError()
def stop(self):
"""Stop the I/O loop.
- If the event loop is not currently running, the next call to start()
+ If the event loop is not currently running, the next call to `start()`
will return immediately.
To use asynchronous methods from otherwise-synchronous code (such as
async_method(ioloop=ioloop, callback=ioloop.stop)
ioloop.start()
- ioloop.start() will return after async_method has run its callback,
- whether that callback was invoked before or after ioloop.start.
+ ``ioloop.start()`` will return after ``async_method`` has run
+ its callback, whether that callback was invoked before or
+ after ``ioloop.start``.
- Note that even after `stop` has been called, the IOLoop is not
+ Note that even after `stop` has been called, the `IOLoop` is not
completely stopped until `IOLoop.start` has also returned.
Some work that was scheduled before the call to `stop` may still
- be run before the IOLoop shuts down.
+ be run before the `IOLoop` shuts down.
"""
raise NotImplementedError()
return future_cell[0].result()
def time(self):
- """Returns the current time according to the IOLoop's clock.
+ """Returns the current time according to the `IOLoop`'s clock.
The return value is a floating-point number relative to an
unspecified time in the past.
- By default, the IOLoop's time function is `time.time`. However,
+ By default, the `IOLoop`'s time function is `time.time`. However,
it may be configured to use e.g. `time.monotonic` instead.
Calls to `add_timeout` that pass a number instead of a
`datetime.timedelta` should use this function to compute the
return time.time()
def add_timeout(self, deadline, callback):
- """Calls the given callback at the time deadline from the I/O loop.
+ """Runs the ``callback`` at the time ``deadline`` from the I/O loop.
- Returns a handle that may be passed to remove_timeout to cancel.
+ Returns an opaque handle that may be passed to
+ `remove_timeout` to cancel.
- ``deadline`` may be a number denoting a time relative to
- `IOLoop.time`, or a ``datetime.timedelta`` object for a
- deadline relative to the current time.
+ ``deadline`` may be a number denoting a time (on the same
+ scale as `IOLoop.time`, normally `time.time`), or a
+ `datetime.timedelta` object for a deadline relative to the
+ current time.
Note that it is not safe to call `add_timeout` from other threads.
Instead, you must use `add_callback` to transfer control to the
- IOLoop's thread, and then call `add_timeout` from there.
+ `IOLoop`'s thread, and then call `add_timeout` from there.
"""
raise NotImplementedError()
def remove_timeout(self, timeout):
"""Cancels a pending timeout.
- The argument is a handle as returned by add_timeout. It is
+ The argument is a handle as returned by `add_timeout`. It is
safe to call `remove_timeout` even if the callback has already
been run.
"""
"""Calls the given callback on the next I/O loop iteration.
It is safe to call this method from any thread at any time,
- except from a signal handler. Note that this is the *only*
- method in IOLoop that makes this thread-safety guarantee; all
- other interaction with the IOLoop must be done from that
- IOLoop's thread. add_callback() may be used to transfer
- control from other threads to the IOLoop's thread.
+ except from a signal handler. Note that this is the **only**
+ method in `IOLoop` that makes this thread-safety guarantee; all
+ other interaction with the `IOLoop` must be done from that
+ `IOLoop`'s thread. `add_callback()` may be used to transfer
+ control from other threads to the `IOLoop`'s thread.
To add a callback from a signal handler, see
`add_callback_from_signal`.
otherwise.
Callbacks added with this method will be run without any
- stack_context, to avoid picking up the context of the function
+ `.stack_context`, to avoid picking up the context of the function
that was interrupted by the signal.
"""
raise NotImplementedError()
def add_future(self, future, callback):
- """Schedules a callback on the IOLoop when the given future is finished.
+ """Schedules a callback on the ``IOLoop`` when the given
+ `~concurrent.futures.Future` is finished.
- The callback is invoked with one argument, the future.
+ The callback is invoked with one argument, the
+ `~concurrent.futures.Future`.
"""
assert isinstance(future, Future)
callback = stack_context.wrap(callback)
self.handle_callback_exception(callback)
def handle_callback_exception(self, callback):
- """This method is called whenever a callback run by the IOLoop
+ """This method is called whenever a callback run by the `IOLoop`
throws an exception.
By default simply logs the exception as an error. Subclasses
may override this method to customize reporting of exceptions.
The exception itself is not passed explicitly, but is available
- in sys.exc_info.
+ in `sys.exc_info`.
"""
app_log.error("Exception in callback %r", callback, exc_info=True)
class PeriodicCallback(object):
"""Schedules the given callback to be called periodically.
- The callback is called every callback_time milliseconds.
+ The callback is called every ``callback_time`` milliseconds.
- `start` must be called after the PeriodicCallback is created.
+ `start` must be called after the `PeriodicCallback` is created.
"""
def __init__(self, callback, callback_time, io_loop=None):
self.callback = callback
def read_from_fd(self):
"""Attempts to read from the underlying file.
- Returns ``None`` if there was nothing to read (the socket returned
- EWOULDBLOCK or equivalent), otherwise returns the data. When possible,
- should return no more than ``self.read_chunk_size`` bytes at a time.
+ Returns ``None`` if there was nothing to read (the socket
+ returned `~errno.EWOULDBLOCK` or equivalent), otherwise
+ returns the data. When possible, should return no more than
+ ``self.read_chunk_size`` bytes at a time.
"""
raise NotImplementedError()
def get_fd_error(self):
"""Returns information about any error on the underlying file.
- This method is called after the IOLoop has signaled an error on the
+ This method is called after the `.IOLoop` has signaled an error on the
file descriptor, and should return an Exception (such as `socket.error`
with additional information, or None if no such information is
available.
return None
def read_until_regex(self, regex, callback):
- """Call callback when we read the given regex pattern."""
+ """Run ``callback`` when we read the given regex pattern.
+
+ The callback will get the data read (including the data that
+ matched the regex and anything that came before it) as an argument.
+ """
self._set_read_callback(callback)
self._read_regex = re.compile(regex)
self._try_inline_read()
def read_until(self, delimiter, callback):
- """Call callback when we read the given delimiter."""
+ """Run ``callback`` when we read the given delimiter.
+
+ The callback will get the data read (including the delimiter)
+ as an argument.
+ """
self._set_read_callback(callback)
self._read_delimiter = delimiter
self._try_inline_read()
def read_bytes(self, num_bytes, callback, streaming_callback=None):
- """Call callback when we read the given number of bytes.
+ """Run callback when we read the given number of bytes.
If a ``streaming_callback`` is given, it will be called with chunks
of data as they become available, and the argument to the final
- ``callback`` will be empty.
+ ``callback`` will be empty. Otherwise, the ``callback`` gets
+ the data as an argument.
"""
self._set_read_callback(callback)
assert isinstance(num_bytes, numbers.Integral)
If a ``streaming_callback`` is given, it will be called with chunks
of data as they become available, and the argument to the final
- ``callback`` will be empty.
+ ``callback`` will be empty. Otherwise, the ``callback`` gets the
+ data as an argument.
Subject to ``max_buffer_size`` limit from `IOStream` constructor if
a ``streaming_callback`` is not used.
def write(self, data, callback=None):
"""Write the given data to this stream.
- If callback is given, we call it when all of the buffered write
+ If ``callback`` is given, we call it when all of the buffered write
data has been successfully written to the stream. If there was
previously buffered write data and an old write callback, that
callback is simply overwritten with this new callback.
class IOStream(BaseIOStream):
- r"""Socket-based IOStream implementation.
+ r"""Socket-based `IOStream` implementation.
This class supports the read and write methods from `BaseIOStream`
plus a `connect` method.
- The socket parameter may either be connected or unconnected. For
- server operations the socket is the result of calling socket.accept().
- For client operations the socket is created with socket.socket(),
- and may either be connected before passing it to the IOStream or
- connected with IOStream.connect.
+ The ``socket`` parameter may either be connected or unconnected.
+ For server operations the socket is the result of calling
+ `socket.accept <socket.socket.accept>`. For client operations the
+ socket is created with `socket.socket`, and may either be
+ connected before passing it to the `IOStream` or connected with
+ `IOStream.connect`.
A very simple (and broken) HTTP client using this class::
- from tornado import ioloop
- from tornado import iostream
+ import tornado.ioloop
+ import tornado.iostream
import socket
def send_request():
- stream.write("GET / HTTP/1.0\r\nHost: friendfeed.com\r\n\r\n")
- stream.read_until("\r\n\r\n", on_headers)
+ stream.write(b"GET / HTTP/1.0\r\nHost: friendfeed.com\r\n\r\n")
+ stream.read_until(b"\r\n\r\n", on_headers)
def on_headers(data):
headers = {}
- for line in data.split("\r\n"):
- parts = line.split(":")
+ for line in data.split(b"\r\n"):
+ parts = line.split(b":")
if len(parts) == 2:
headers[parts[0].strip()] = parts[1].strip()
- stream.read_bytes(int(headers["Content-Length"]), on_body)
+ stream.read_bytes(int(headers[b"Content-Length"]), on_body)
def on_body(data):
print data
stream.close()
- ioloop.IOLoop.instance().stop()
+ tornado.ioloop.IOLoop.instance().stop()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
- stream = iostream.IOStream(s)
+ stream = tornado.iostream.IOStream(s)
stream.connect(("friendfeed.com", 80), send_request)
- ioloop.IOLoop.instance().start()
+ tornado.ioloop.IOLoop.instance().start()
"""
def __init__(self, socket, *args, **kwargs):
self.socket = socket
May only be called if the socket passed to the constructor was
not previously connected. The address parameter is in the
- same format as for socket.connect, i.e. a (host, port) tuple.
- If callback is specified, it will be called when the
- connection is completed.
+ same format as for `socket.connect <socket.socket.connect>`,
+ i.e. a ``(host, port)`` tuple. If ``callback`` is specified,
+ it will be called when the connection is completed.
If specified, the ``server_hostname`` parameter will be used
in SSL connections for certificate validation (if requested in
the ``ssl_options``) and SNI (if supported; requires
Python 3.2+).
- Note that it is safe to call IOStream.write while the
- connection is pending, in which case the data will be written
- as soon as the connection is ready. Calling IOStream read
- methods before the socket is connected works on some platforms
- but is non-portable.
+ Note that it is safe to call `IOStream.write
+ <BaseIOStream.write>` while the connection is pending, in
+ which case the data will be written as soon as the connection
+ is ready. Calling `IOStream` read methods before the socket is
+ connected works on some platforms but is non-portable.
"""
self._connecting = True
try:
ssl.wrap_socket(sock, do_handshake_on_connect=False, **kwargs)
- before constructing the SSLIOStream. Unconnected sockets will be
- wrapped when IOStream.connect is finished.
+ before constructing the `SSLIOStream`. Unconnected sockets will be
+ wrapped when `IOStream.connect` is finished.
"""
def __init__(self, *args, **kwargs):
- """Creates an SSLIOStream.
-
- The ``ssl_options`` keyword argument may either be a dictionary
+ """The ``ssl_options`` keyword argument may either be a dictionary
of keywords arguments for `ssl.wrap_socket`, or an `ssl.SSLContext`
object.
"""
class PipeIOStream(BaseIOStream):
- """Pipe-based IOStream implementation.
+ """Pipe-based `IOStream` implementation.
The constructor takes an integer file descriptor (such as one returned
- by `os.pipe`) rather than an open file object.
+ by `os.pipe`) rather than an open file object. Pipes are generally
+ one-way, so a `PipeIOStream` can be used for reading or writing but not
+ both.
"""
def __init__(self, fd, *args, **kwargs):
self.fd = fd
To load a locale and generate a translated string::
- user_locale = locale.get("es_LA")
+ user_locale = tornado.locale.get("es_LA")
print user_locale.translate("Sign out")
-locale.get() returns the closest matching locale, not necessarily the
+`tornado.locale.get()` returns the closest matching locale, not necessarily the
specific locale you requested. You can support pluralization with
-additional arguments to translate(), e.g.::
+additional arguments to `~Locale.translate()`, e.g.::
people = [...]
message = user_locale.translate(
"%(list)s is online", "%(list)s are online", len(people))
print message % {"list": user_locale.list(people)}
-The first string is chosen if len(people) == 1, otherwise the second
+The first string is chosen if ``len(people) == 1``, otherwise the second
string is chosen.
-Applications should call one of load_translations (which uses a simple
-CSV format) or load_gettext_translations (which uses the .mo format
-supported by gettext and related tools). If neither method is called,
-the locale.translate method will simply return the original string.
+Applications should call one of `load_translations` (which uses a simple
+CSV format) or `load_gettext_translations` (which uses the ``.mo`` format
+supported by `gettext` and related tools). If neither method is called,
+the `Locale.translate` method will simply return the original string.
"""
from __future__ import absolute_import, division, print_function, with_statement
or a loose match for the code (e.g., "en" for "en_US"), we return
the locale. Otherwise we move to the next code in the list.
- By default we return en_US if no translations are found for any of
+ By default we return ``en_US`` if no translations are found for any of
the specified locales. You can change the default locale with
- set_default_locale() below.
+ `set_default_locale()`.
"""
return Locale.get_closest(*locale_codes)
def set_default_locale(code):
- """Sets the default locale, used in get_closest_locale().
+ """Sets the default locale.
The default locale is assumed to be the language used for all strings
in the system. The translations loaded from disk are mappings from
"""Loads translations from CSV files in a directory.
Translations are strings with optional Python-style named placeholders
- (e.g., "My name is %(name)s") and their associated translations.
+ (e.g., ``My name is %(name)s``) and their associated translations.
- The directory should have translation files of the form LOCALE.csv,
- e.g. es_GT.csv. The CSV files should have two or three columns: string,
+ The directory should have translation files of the form ``LOCALE.csv``,
+ e.g. ``es_GT.csv``. The CSV files should have two or three columns: string,
translation, and an optional plural indicator. Plural indicators should
be one of "plural" or "singular". A given string can have both singular
- and plural forms. For example "%(name)s liked this" may have a
+ and plural forms. For example ``%(name)s liked this`` may have a
different verb conjugation depending on whether %(name)s is one
name or a list of names. There should be two rows in the CSV file for
that string, one with plural indicator "singular", and one "plural".
For strings with no verbs that would change on translation, simply
use "unknown" or the empty string (or don't include the column at all).
- The file is read using the csv module in the default "excel" dialect.
+ The file is read using the `csv` module in the default "excel" dialect.
In this format there should not be spaces after the commas.
- Example translation es_LA.csv::
+ Example translation ``es_LA.csv``::
"I love you","Te amo"
"%(name)s liked this","A %(name)s les gustó esto","plural"
def load_gettext_translations(directory, domain):
- """Loads translations from gettext's locale tree
+ """Loads translations from `gettext`'s locale tree
- Locale tree is similar to system's /usr/share/locale, like:
+ Locale tree is similar to system's ``/usr/share/locale``, like::
- {directory}/{lang}/LC_MESSAGES/{domain}.mo
+ {directory}/{lang}/LC_MESSAGES/{domain}.mo
Three steps are required to have you app translated:
- 1. Generate POT translation file
- xgettext --language=Python --keyword=_:1,2 -d cyclone file1.py file2.html etc
+ 1. Generate POT translation file::
- 2. Merge against existing POT file:
- msgmerge old.po cyclone.po > new.po
+ xgettext --language=Python --keyword=_:1,2 -d mydomain file1.py file2.html etc
- 3. Compile:
- msgfmt cyclone.po -o {directory}/pt_BR/LC_MESSAGES/cyclone.mo
+ 2. Merge against existing POT file::
+
+ msgmerge old.po mydomain.po > new.po
+
+ 3. Compile::
+
+ msgfmt mydomain.po -o {directory}/pt_BR/LC_MESSAGES/mydomain.mo
"""
import gettext
global _translations
def translate(self, message, plural_message=None, count=None):
"""Returns the translation for the given message for this locale.
- If plural_message is given, you must also provide count. We return
- plural_message when count != 1, and we return the singular form
- for the given message when count == 1.
+ If ``plural_message`` is given, you must also provide
+ ``count``. We return ``plural_message`` when ``count != 1``,
+ and we return the singular form for the given message when
+ ``count == 1``.
"""
raise NotImplementedError()
"""Formats the given date (which should be GMT).
By default, we return a relative time (e.g., "2 minutes ago"). You
- can return an absolute date string with relative=False.
+ can return an absolute date string with ``relative=False``.
You can force a full format date ("July 10, 1980") with
- full_format=True.
+ ``full_format=True``.
This method is primarily intended for dates in the past.
For dates in the future, we fall back to full format.
"""Formats the given date as a day of week.
Example: "Monday, January 22". You can remove the day of week with
- dow=False.
+ ``dow=False``.
"""
local_date = date - datetime.timedelta(minutes=gmt_offset)
_ = self.translate
class GettextLocale(Locale):
- """Locale implementation using the gettext module."""
+ """Locale implementation using the `gettext` module."""
def __init__(self, code, translations):
try:
# python 2