diff --git a/docs/Makefile b/docs/Makefile
index b156c257..7001b801 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,6 +1,8 @@
.PHONY: all
all: sphinx
+# No -W for doctests because that disallows tests with empty output.
+SPHINX_DOCTEST_OPTS=-n -d build/doctress .
SPHINXOPTS=-n -W -d build/doctrees .
.PHONY: sphinx
@@ -25,7 +27,7 @@ pdf: latex
.PHONY: doctest
doctest:
- sphinx-build -b doctest $(SPHINXOPTS) build/doctest
+ sphinx-build -b doctest $(SPHINX_DOCTEST_OPTS) build/doctest
clean:
rm -rf build
diff --git a/docs/auth.rst b/docs/auth.rst
index dd2ca554..b2dad547 100644
--- a/docs/auth.rst
+++ b/docs/auth.rst
@@ -1,6 +1,10 @@
``tornado.auth`` --- Third-party login with OpenID and OAuth
============================================================
+.. testsetup::
+
+ import tornado.auth, tornado.gen, tornado.web
+
.. automodule:: tornado.auth
Common protocols
diff --git a/docs/concurrent.rst b/docs/concurrent.rst
index 051c91ab..72047811 100644
--- a/docs/concurrent.rst
+++ b/docs/concurrent.rst
@@ -1,6 +1,11 @@
``tornado.concurrent`` --- Work with threads and futures
========================================================
+.. testsetup::
+
+ from tornado.concurrent import *
+ from tornado import gen
+
.. automodule:: tornado.concurrent
:members:
:exclude-members: Future, TracebackFuture
diff --git a/docs/gen.rst b/docs/gen.rst
index a6f81ed1..8a3c99b9 100644
--- a/docs/gen.rst
+++ b/docs/gen.rst
@@ -1,6 +1,11 @@
``tornado.gen`` --- Simplify asynchronous code
==============================================
+.. testsetup::
+
+ from tornado.web import *
+ from tornado import gen
+
.. automodule:: tornado.gen
Decorators
diff --git a/docs/guide/async.rst b/docs/guide/async.rst
index 7430031f..6a3e26bb 100644
--- a/docs/guide/async.rst
+++ b/docs/guide/async.rst
@@ -60,7 +60,9 @@ things asynchronous).
Examples
~~~~~~~~
-Here is a sample synchronous function::
+Here is a sample synchronous function:
+
+.. testcode::
from tornado.httpclient import HTTPClient
@@ -69,8 +71,13 @@ Here is a sample synchronous function::
response = http_client.fetch(url)
return response.body
+.. testoutput::
+ :hide:
+
And here is the same function rewritten to be asynchronous with a
-callback argument::
+callback argument:
+
+.. testcode::
from tornado.httpclient import AsyncHTTPClient
@@ -80,7 +87,12 @@ callback argument::
callback(response.body)
http_client.fetch(url, callback=handle_response)
-And again with a `.Future` instead of a callback::
+.. testoutput::
+ :hide:
+
+And again with a `.Future` instead of a callback:
+
+.. testcode::
from tornado.concurrent import Future
@@ -92,6 +104,9 @@ And again with a `.Future` instead of a callback::
lambda f: my_future.set_result(f.result()))
return my_future
+.. testoutput::
+ :hide:
+
The raw `.Future` version is more complex, but ``Futures`` are
nonetheless recommended practice in Tornado because they have two
major advantages. Error handling is more consistent since the
@@ -100,7 +115,9 @@ the ad-hoc error handling common in callback-oriented interfaces), and
``Futures`` lend themselves well to use with coroutines. Coroutines
will be discussed in depth in the next section of this guide. Here is
the coroutine version of our sample function, which is very similar to
-the original synchronous version::
+the original synchronous version:
+
+.. testcode::
from tornado import gen
@@ -110,6 +127,9 @@ the original synchronous version::
response = yield http_client.fetch(url)
raise gen.Return(response.body)
+.. testoutput::
+ :hide:
+
The statement ``raise gen.Return(response.body)`` is an artifact of
Python 2 (and 3.2), in which generators aren't allowed to return
values. To overcome this, Tornado coroutines raise a special kind of
diff --git a/docs/guide/coroutines.rst b/docs/guide/coroutines.rst
index f10dda30..a3fed1fb 100644
--- a/docs/guide/coroutines.rst
+++ b/docs/guide/coroutines.rst
@@ -1,6 +1,10 @@
Coroutines
==========
+.. testsetup::
+
+ from tornado import gen
+
**Coroutines** are the recommended way to write asynchronous code in
Tornado. Coroutines use the Python ``yield`` keyword to suspend and
resume execution instead of a chain of callbacks (cooperative
@@ -65,7 +69,9 @@ Interaction with callbacks
To interact with asynchronous code that uses callbacks instead of
`.Future`, wrap the call in a `.Task`. This will add the callback
-argument for you and return a `.Future` which you can yield::
+argument for you and return a `.Future` which you can yield:
+
+.. testcode::
@gen.coroutine
def call_task():
@@ -74,6 +80,9 @@ argument for you and return a `.Future` which you can yield::
# some_function(other_args, callback=callback)
yield gen.Task(some_function, other_args)
+.. testoutput::
+ :hide:
+
Calling blocking functions
^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -91,7 +100,9 @@ Parallelism
^^^^^^^^^^^
The coroutine decorator recognizes lists and dicts whose values are
-``Futures``, and waits for all of those ``Futures`` in parallel::
+``Futures``, and waits for all of those ``Futures`` in parallel:
+
+.. testcode::
@gen.coroutine
def parallel_fetch(url1, url2):
@@ -109,11 +120,16 @@ The coroutine decorator recognizes lists and dicts whose values are
for url in urls}
# responses is a dict {url: HTTPResponse}
+.. testoutput::
+ :hide:
+
Interleaving
^^^^^^^^^^^^
Sometimes it is useful to save a `.Future` instead of yielding it
-immediately, so you can start another operation before waiting::
+immediately, so you can start another operation before waiting:
+
+.. testcode::
@gen.coroutine
def get(self):
@@ -125,6 +141,9 @@ immediately, so you can start another operation before waiting::
fetch_future = self.fetch_next_chunk()
yield self.flush()
+.. testoutput::
+ :hide:
+
Looping
^^^^^^^
@@ -136,7 +155,7 @@ from `Motor `_::
import motor
db = motor.MotorClient().test
-
+
@gen.coroutine
def loop_example(collection):
cursor = db.collection.find()
diff --git a/docs/guide/running.rst b/docs/guide/running.rst
index 7ae3f4ff..7b1b415f 100644
--- a/docs/guide/running.rst
+++ b/docs/guide/running.rst
@@ -4,7 +4,9 @@ Running and deploying
Since Tornado supplies its own HTTPServer, running and deploying it is
a little different from other Python web frameworks. Instead of
configuring a WSGI container to find your application, you write a
-``main()`` function that starts the server::
+``main()`` function that starts the server:
+
+.. testcode::
def main():
app = make_app()
@@ -14,6 +16,9 @@ configuring a WSGI container to find your application, you write a
if __name__ == '__main__':
main()
+.. testoutput::
+ :hide:
+
Configure your operating system or process manager to run this program to
start the server. Please note that it may be necessary to increase the number
of open files per process (to avoid "Too many open files"-Error).
@@ -29,7 +34,9 @@ Typically it is best to run one process per CPU.
Tornado includes a built-in multi-process mode to start several
processes at once. This requires a slight alteration to the standard
-main function::
+main function:
+
+.. testcode::
def main():
app = make_app()
@@ -38,6 +45,9 @@ main function::
server.start(0) # forks one process per cpu
IOLoop.current().start()
+.. testoutput::
+ :hide:
+
This is the easiest way to start multiple processes and have them all
share the same port, although it has some limitations. First, each
child process will have its own IOLoop, so it is important that
@@ -279,7 +289,9 @@ decorator, `.AsyncHTTPClient`, the ``auth`` module, and WebSockets.
You can convert a Tornado `.Application` to a WSGI application
with `tornado.wsgi.WSGIAdapter`. In this example, configure
-your WSGI container to find the ``application`` object::
+your WSGI container to find the ``application`` object:
+
+.. testcode::
import tornado.web
import tornado.wsgi
@@ -293,6 +305,9 @@ your WSGI container to find the ``application`` object::
])
application = tornado.wsgi.WSGIAdapter(tornado_app)
+.. testoutput::
+ :hide:
+
See the `appengine example application
`_ for a
full-featured AppEngine app built on Tornado.
diff --git a/docs/guide/security.rst b/docs/guide/security.rst
index 57a1cba7..793fb050 100644
--- a/docs/guide/security.rst
+++ b/docs/guide/security.rst
@@ -1,11 +1,17 @@
Authentication and security
===========================
+.. testsetup::
+
+ import tornado.web
+
Cookies and secure cookies
~~~~~~~~~~~~~~~~~~~~~~~~~~
You can set cookies in the user's browser with the ``set_cookie``
-method::
+method:
+
+.. testcode::
class MainHandler(tornado.web.RequestHandler):
def get(self):
@@ -15,6 +21,9 @@ method::
else:
self.write("Your cookie was set!")
+.. testoutput::
+ :hide:
+
Cookies are not secure and can easily be modified by clients. If you
need to set cookies to, e.g., identify the currently logged in user,
you need to sign your cookies to prevent forgery. Tornado supports
@@ -22,17 +31,24 @@ signed cookies with the `~.RequestHandler.set_secure_cookie` and
`~.RequestHandler.get_secure_cookie` methods. To use these methods,
you need to specify a secret key named ``cookie_secret`` when you
create your application. You can pass in application settings as
-keyword arguments to your application::
+keyword arguments to your application:
+
+.. testcode::
application = tornado.web.Application([
(r"/", MainHandler),
], cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__")
+.. testoutput::
+ :hide:
+
Signed cookies contain the encoded value of the cookie in addition to a
timestamp and an `HMAC `_ signature.
If the cookie is old or if the signature doesn't match,
``get_secure_cookie`` will return ``None`` just as if the cookie isn't
-set. The secure version of the example above::
+set. The secure version of the example above:
+
+.. testcode::
class MainHandler(tornado.web.RequestHandler):
def get(self):
@@ -42,6 +58,9 @@ set. The secure version of the example above::
else:
self.write("Your cookie was set!")
+.. testoutput::
+ :hide:
+
Tornado's secure cookies guarantee integrity but not confidentiality.
That is, the cookie cannot be modified but its contents can be seen by the
user. The ``cookie_secret`` is a symmetric key and must be kept secret --
@@ -69,7 +88,9 @@ To implement user authentication in your application, you need to
override the ``get_current_user()`` method in your request handlers to
determine the current user based on, e.g., the value of a cookie. Here
is an example that lets users log into the application simply by
-specifying a nickname, which is then saved in a cookie::
+specifying a nickname, which is then saved in a cookie:
+
+.. testcode::
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
@@ -99,12 +120,17 @@ specifying a nickname, which is then saved in a cookie::
(r"/login", LoginHandler),
], cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__")
+.. testoutput::
+ :hide:
+
You can require that the user be logged in using the `Python
decorator `_
`tornado.web.authenticated`. If a request goes to a method with this
decorator, and the user is not logged in, they will be redirected to
``login_url`` (another application setting). The example above could be
-rewritten::
+rewritten:
+
+.. testcode::
class MainHandler(BaseHandler):
@tornado.web.authenticated
@@ -121,6 +147,9 @@ rewritten::
(r"/login", LoginHandler),
], **settings)
+.. testoutput::
+ :hide:
+
If you decorate ``post()`` methods with the ``authenticated``
decorator, and the user is not logged in, the server will send a
``403`` response. The ``@authenticated`` decorator is simply
@@ -144,7 +173,9 @@ download a user's address book or publish a Twitter message on their
behalf.
Here is an example handler that uses Google for authentication, saving
-the Google credentials in a cookie for later access::
+the Google credentials in a cookie for later access:
+
+.. testcode::
class GoogleHandler(tornado.web.RequestHandler, tornado.auth.GoogleMixin):
@tornado.web.asynchronous
@@ -160,6 +191,9 @@ the Google credentials in a cookie for later access::
return
# Save the user with, e.g., set_secure_cookie()
+.. testoutput::
+ :hide:
+
See the `tornado.auth` module documentation for more details.
.. _xsrf:
@@ -181,7 +215,9 @@ value in the form submission do not match, then the request is likely
forged.
Tornado comes with built-in XSRF protection. To include it in your site,
-include the application setting ``xsrf_cookies``::
+include the application setting ``xsrf_cookies``:
+
+.. testcode::
settings = {
"cookie_secret": "__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",
@@ -193,6 +229,9 @@ include the application setting ``xsrf_cookies``::
(r"/login", LoginHandler),
], **settings)
+.. testoutput::
+ :hide:
+
If ``xsrf_cookies`` is set, the Tornado web application will set the
``_xsrf`` cookie for all users and reject all ``POST``, ``PUT``, and
``DELETE`` requests that do not contain a correct ``_xsrf`` value. If
diff --git a/docs/guide/structure.rst b/docs/guide/structure.rst
index e83a3f30..57d7b82a 100644
--- a/docs/guide/structure.rst
+++ b/docs/guide/structure.rst
@@ -1,5 +1,9 @@
.. currentmodule:: tornado.web
+.. testsetup::
+
+ import tornado.web
+
Structure of a Tornado web application
======================================
@@ -8,7 +12,9 @@ A Tornado web application generally consists of one or more
routes incoming requests to handlers, and a ``main()`` function
to start the server.
-A minimal "hello world" example looks something like this::
+A minimal "hello world" example looks something like this:
+
+.. testcode::
from tornado.ioloop import IOLoop
from tornado.web import RequestHandler, Application, url
@@ -27,6 +33,9 @@ A minimal "hello world" example looks something like this::
app.listen(8888)
IOLoop.current().start()
+.. testoutput::
+ :hide:
+
The ``Application`` object
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -109,7 +118,7 @@ Request data in the formats used by HTML forms will be parsed for you
and is made available in methods like `~.RequestHandler.get_query_argument`
and `~.RequestHandler.get_body_argument`.
-::
+.. testcode::
class MyFormHandler(RequestHandler):
def get(self):
@@ -122,6 +131,9 @@ and `~.RequestHandler.get_body_argument`.
self.set_header("Content-Type", "text/plain")
self.write("You wrote " + self.get_body_argument("message"))
+.. testoutput::
+ :hide:
+
Since the HTML form encoding is ambiguous as to whether an argument is
a single value or a list with one element, `.RequestHandler` has
distinct methods to allow the application to indicate whether or not
@@ -302,7 +314,9 @@ to ensure that this method is called, or else the user's browser will
simply hang.
Here is an example that makes a call to the FriendFeed API using
-Tornado's built-in `.AsyncHTTPClient`::
+Tornado's built-in `.AsyncHTTPClient`:
+
+.. testcode::
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
@@ -318,12 +332,17 @@ Tornado's built-in `.AsyncHTTPClient`::
"from the FriendFeed API")
self.finish()
+.. testoutput::
+ :hide:
+
When ``get()`` returns, the request has not finished. When the HTTP
client eventually calls ``on_response()``, the request is still open,
and the response is finally flushed to the client with the call to
``self.finish()``.
-For comparison, here is the same example using a coroutine::
+For comparison, here is the same example using a coroutine:
+
+.. testcode::
class MainHandler(tornado.web.RequestHandler):
@tornado.gen.coroutine
@@ -334,6 +353,9 @@ For comparison, here is the same example using a coroutine::
self.write("Fetched " + str(len(json["entries"])) + " entries "
"from the FriendFeed API")
+.. testoutput::
+ :hide:
+
For a more advanced asynchronous example, take a look at the `chat
example application
`_, which
diff --git a/docs/guide/templates.rst b/docs/guide/templates.rst
index 2156ad6c..8755d25e 100644
--- a/docs/guide/templates.rst
+++ b/docs/guide/templates.rst
@@ -1,6 +1,10 @@
Templates and UI
================
+.. testsetup::
+
+ import tornado.web
+
Tornado includes a simple, fast, and flexible templating language.
This section describes that language as well as related issues
such as internationalization.
@@ -51,13 +55,16 @@ Python control sequences and expressions embedded within the markup::
If you saved this template as "template.html" and put it in the same
directory as your Python file, you could render this template with:
-::
+.. testcode::
class MainHandler(tornado.web.RequestHandler):
def get(self):
items = ["Item 1", "Item 2", "Item 3"]
self.render("template.html", title="My title", items=items)
+.. testoutput::
+ :hide:
+
Tornado templates support *control statements* and *expressions*.
Control statements are surrounded by ``{%`` and ``%}``, e.g.,
``{% if len(items) > 2 %}``. Expressions are surrounded by ``{{`` and
@@ -178,7 +185,9 @@ By default, we detect the user's locale using the ``Accept-Language``
header sent by the user's browser. We choose ``en_US`` if we can't find
an appropriate ``Accept-Language`` value. If you let user's set their
locale as a preference, you can override this default locale selection
-by overriding `.RequestHandler.get_user_locale`::
+by overriding `.RequestHandler.get_user_locale`:
+
+.. testcode::
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
@@ -192,6 +201,9 @@ by overriding `.RequestHandler.get_user_locale`::
return None
return self.current_user.prefs["locale"]
+.. testoutput::
+ :hide:
+
If ``get_user_locale`` returns ``None``, we fall back on the
``Accept-Language`` header.
diff --git a/docs/web.rst b/docs/web.rst
index 360d21af..0845641c 100644
--- a/docs/web.rst
+++ b/docs/web.rst
@@ -1,6 +1,10 @@
``tornado.web`` --- ``RequestHandler`` and ``Application`` classes
==================================================================
+.. testsetup::
+
+ from tornado.web import *
+
.. automodule:: tornado.web
Request handlers
diff --git a/docs/websocket.rst b/docs/websocket.rst
index d5e7921b..b3596d4c 100644
--- a/docs/websocket.rst
+++ b/docs/websocket.rst
@@ -1,6 +1,10 @@
``tornado.websocket`` --- Bidirectional communication to the browser
====================================================================
+.. testsetup::
+
+ import tornado.websocket
+
.. automodule:: tornado.websocket
.. autoclass:: WebSocketHandler
diff --git a/tornado/auth.py b/tornado/auth.py
index 00c833aa..85f967cb 100644
--- a/tornado/auth.py
+++ b/tornado/auth.py
@@ -32,7 +32,9 @@ They all take slightly different arguments due to the fact all these
services implement authentication and authorization slightly differently.
See the individual service classes below for complete documentation.
-Example usage for Google OpenID::
+Example usage for Google OpenID:
+
+.. testcode::
class GoogleOAuth2LoginHandler(tornado.web.RequestHandler,
tornado.auth.GoogleOAuth2Mixin):
@@ -51,6 +53,10 @@ Example usage for Google OpenID::
response_type='code',
extra_params={'approval_prompt': 'auto'})
+.. testoutput::
+ :hide:
+
+
.. versionchanged:: 4.0
All of the callback interfaces in this module are now guaranteed
to run their callback with an argument of ``None`` on error.
@@ -630,7 +636,9 @@ class TwitterMixin(OAuthMixin):
URL you registered as your application's callback URL.
When your application is set up, you can use this mixin like this
- to authenticate the user with Twitter and get access to their stream::
+ to authenticate the user with Twitter and get access to their stream:
+
+ .. testcode::
class TwitterLoginHandler(tornado.web.RequestHandler,
tornado.auth.TwitterMixin):
@@ -642,6 +650,9 @@ class TwitterMixin(OAuthMixin):
else:
yield self.authorize_redirect()
+ .. testoutput::
+ :hide:
+
The user object returned by `~OAuthMixin.get_authenticated_user`
includes the attributes ``username``, ``name``, ``access_token``,
and all of the custom Twitter user attributes described at
@@ -690,7 +701,9 @@ class TwitterMixin(OAuthMixin):
`~OAuthMixin.get_authenticated_user`. The user returned through that
process includes an 'access_token' attribute that can be used
to make authenticated requests via this method. Example
- usage::
+ usage:
+
+ .. testcode::
class MainHandler(tornado.web.RequestHandler,
tornado.auth.TwitterMixin):
@@ -707,6 +720,9 @@ class TwitterMixin(OAuthMixin):
return
self.finish("Posted a message!")
+ .. testoutput::
+ :hide:
+
"""
if path.startswith('http:') or path.startswith('https:'):
# Raw urls are useful for e.g. search which doesn't follow the
@@ -769,7 +785,9 @@ class FriendFeedMixin(OAuthMixin):
for the URL you registered as your application's Callback URL.
When your application is set up, you can use this mixin like this
- to authenticate the user with FriendFeed and get access to their feed::
+ to authenticate the user with FriendFeed and get access to their feed:
+
+ .. testcode::
class FriendFeedLoginHandler(tornado.web.RequestHandler,
tornado.auth.FriendFeedMixin):
@@ -781,6 +799,10 @@ class FriendFeedMixin(OAuthMixin):
else:
yield self.authorize_redirect()
+ .. testoutput::
+ :hide:
+
+
The user object returned by `~OAuthMixin.get_authenticated_user()` includes the
attributes ``username``, ``name``, and ``description`` in addition to
``access_token``. You should save the access token with the user;
@@ -812,7 +834,9 @@ class FriendFeedMixin(OAuthMixin):
can be used to make authenticated requests via this
method.
- Example usage::
+ Example usage:
+
+ .. testcode::
class MainHandler(tornado.web.RequestHandler,
tornado.auth.FriendFeedMixin):
@@ -830,6 +854,9 @@ class FriendFeedMixin(OAuthMixin):
return
self.finish("Posted a message!")
+ .. testoutput::
+ :hide:
+
"""
# Add the OAuth resource request signature if we have credentials
url = "http://friendfeed-api.com/v2" + path
@@ -901,7 +928,9 @@ class GoogleMixin(OpenIdMixin, OAuthMixin):
the values for the user, including ``email``, ``name``, and
``locale``.
- Example usage::
+ Example usage:
+
+ .. testcode::
class GoogleLoginHandler(tornado.web.RequestHandler,
tornado.auth.GoogleMixin):
@@ -912,6 +941,10 @@ class GoogleMixin(OpenIdMixin, OAuthMixin):
# Save the user with e.g. set_secure_cookie()
else:
yield self.authenticate_redirect()
+
+ .. testoutput::
+ :hide:
+
"""
_OPENID_ENDPOINT = "https://www.google.com/accounts/o8/ud"
_OAUTH_ACCESS_TOKEN_URL = "https://www.google.com/accounts/OAuthGetAccessToken"
@@ -1002,7 +1035,9 @@ class GoogleOAuth2Mixin(OAuth2Mixin):
def get_authenticated_user(self, redirect_uri, code, callback):
"""Handles the login for the Google user, returning a user object.
- Example usage::
+ Example usage:
+
+ .. testcode::
class GoogleOAuth2LoginHandler(tornado.web.RequestHandler,
tornado.auth.GoogleOAuth2Mixin):
@@ -1020,6 +1055,10 @@ class GoogleOAuth2Mixin(OAuth2Mixin):
scope=['profile', 'email'],
response_type='code',
extra_params={'approval_prompt': 'auto'})
+
+ .. testoutput::
+ :hide:
+
"""
http = self.get_auth_http_client()
body = urllib_parse.urlencode({
@@ -1066,7 +1105,9 @@ class FacebookMixin(object):
``facebook_api_key`` and ``facebook_secret``.
When your application is set up, you can use this mixin like this
- to authenticate the user with Facebook::
+ to authenticate the user with Facebook:
+
+ .. testcode::
class FacebookHandler(tornado.web.RequestHandler,
tornado.auth.FacebookMixin):
@@ -1082,6 +1123,9 @@ class FacebookMixin(object):
raise tornado.web.HTTPError(500, "Facebook auth failed")
# Save the user using, e.g., set_secure_cookie()
+ .. testoutput::
+ :hide:
+
The user object returned by `get_authenticated_user` includes the
attributes ``facebook_uid`` and ``name`` in addition to session attributes
like ``session_key``. You should save the session key with the user; it is
@@ -1176,7 +1220,9 @@ class FacebookMixin(object):
The available Facebook methods are documented here:
http://wiki.developers.facebook.com/index.php/API
- Here is an example for the stream.get() method::
+ Here is an example for the stream.get() method:
+
+ .. testcode::
class MainHandler(tornado.web.RequestHandler,
tornado.auth.FacebookMixin):
@@ -1195,6 +1241,9 @@ class FacebookMixin(object):
return
self.render("stream.html", stream=stream)
+ .. testoutput::
+ :hide:
+
"""
self.require_setting("facebook_api_key", "Facebook Connect")
self.require_setting("facebook_secret", "Facebook Connect")
@@ -1275,9 +1324,12 @@ class FacebookGraphMixin(OAuth2Mixin):
code, callback, extra_fields=None):
"""Handles the login for the Facebook user, returning a user object.
- Example usage::
+ Example usage:
- class FacebookGraphLoginHandler(LoginHandler, tornado.auth.FacebookGraphMixin):
+ .. testcode::
+
+ class FacebookGraphLoginHandler(tornado.web.RequestHandler,
+ tornado.auth.FacebookGraphMixin):
@tornado.gen.coroutine
def get(self):
if self.get_argument("code", False):
@@ -1292,6 +1344,10 @@ class FacebookGraphMixin(OAuth2Mixin):
redirect_uri='/auth/facebookgraph/',
client_id=self.settings["facebook_api_key"],
extra_params={"scope": "read_stream,offline_access"})
+
+ .. testoutput::
+ :hide:
+
"""
http = self.get_auth_http_client()
args = {
@@ -1359,7 +1415,9 @@ class FacebookGraphMixin(OAuth2Mixin):
process includes an ``access_token`` attribute that can be
used to make authenticated requests via this method.
- Example usage::
+ Example usage:
+
+ ..testcode::
class MainHandler(tornado.web.RequestHandler,
tornado.auth.FacebookGraphMixin):
@@ -1377,6 +1435,9 @@ class FacebookGraphMixin(OAuth2Mixin):
return
self.finish("Posted a message!")
+ .. testoutput::
+ :hide:
+
The given path is relative to ``self._FACEBOOK_BASE_URL``,
by default "https://graph.facebook.com".
diff --git a/tornado/concurrent.py b/tornado/concurrent.py
index a3f15dcd..4b0a7804 100644
--- a/tornado/concurrent.py
+++ b/tornado/concurrent.py
@@ -379,7 +379,9 @@ def return_future(f):
wait for the function to complete (perhaps by yielding it in a
`.gen.engine` function, or passing it to `.IOLoop.add_future`).
- Usage::
+ Usage:
+
+ .. testcode::
@return_future
def future_func(arg1, arg2, callback):
@@ -391,6 +393,8 @@ def return_future(f):
yield future_func(arg1, arg2)
callback()
+ ..
+
Note that ``@return_future`` and ``@gen.engine`` can be applied to the
same function, provided ``@return_future`` appears first. However,
consider using ``@gen.coroutine`` instead of this combination.
diff --git a/tornado/gen.py b/tornado/gen.py
index f59f0d89..3d87d717 100644
--- a/tornado/gen.py
+++ b/tornado/gen.py
@@ -3,7 +3,9 @@ work in an asynchronous environment. Code using the ``gen`` module
is technically asynchronous, but it is written as a single generator
instead of a collection of separate functions.
-For example, the following asynchronous handler::
+For example, the following asynchronous handler:
+
+.. testcode::
class AsyncHandler(RequestHandler):
@asynchronous
@@ -16,7 +18,12 @@ For example, the following asynchronous handler::
do_something_with_response(response)
self.render("template.html")
-could be written with ``gen`` as::
+.. testoutput::
+ :hide:
+
+could be written with ``gen`` as:
+
+.. testcode::
class GenAsyncHandler(RequestHandler):
@gen.coroutine
@@ -26,12 +33,17 @@ could be written with ``gen`` as::
do_something_with_response(response)
self.render("template.html")
+.. testoutput::
+ :hide:
+
Most asynchronous functions in Tornado return a `.Future`;
yielding this object returns its `~.Future.result`.
You can also yield a list or dict of ``Futures``, which will be
started at the same time and run in parallel; a list or dict of results will
-be returned when they are all finished::
+be returned when they are all finished:
+
+.. testcode::
@gen.coroutine
def get(self):
@@ -43,6 +55,9 @@ be returned when they are all finished::
response3 = response_dict['response3']
response4 = response_dict['response4']
+.. testoutput::
+ :hide:
+
If the `~functools.singledispatch` library is available (standard in
Python 3.4, available via the `singledispatch
`_ package on older
@@ -280,20 +295,18 @@ class WaitIterator(object):
If you need to get the result of each future as soon as possible,
or if you need the result of some futures even if others produce
- errors, you can use ``WaitIterator``:
-
- ::
+ errors, you can use ``WaitIterator``::
wait_iterator = gen.WaitIterator(future1, future2)
while not wait_iterator.done():
try:
result = yield wait_iterator.next()
except Exception as e:
- print "Error {} from {}".format(e, wait_iterator.current_future)
+ print("Error {} from {}".format(e, wait_iterator.current_future))
else:
- print "Result {} recieved from {} at {}".format(
+ print("Result {} recieved from {} at {}".format(
result, wait_iterator.current_future,
- wait_iterator.current_index)
+ wait_iterator.current_index))
Because results are returned as soon as they are available the
output from the iterator *will not be in the same order as the
diff --git a/tornado/ioloop.py b/tornado/ioloop.py
index 680dc401..775bfba8 100644
--- a/tornado/ioloop.py
+++ b/tornado/ioloop.py
@@ -76,34 +76,40 @@ class IOLoop(Configurable):
simultaneous connections, you should use a system that supports
either ``epoll`` or ``kqueue``.
- Example usage for a simple TCP server::
+ Example usage for a simple TCP server:
+
+ .. testcode::
import errno
import functools
- import ioloop
+ import tornado.ioloop
import socket
def connection_ready(sock, fd, events):
while True:
try:
connection, address = sock.accept()
- except socket.error, e:
+ except socket.error as e:
if e.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
raise
return
connection.setblocking(0)
handle_connection(connection, address)
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock.setblocking(0)
- sock.bind(("", port))
- sock.listen(128)
+ if __name__ == '__main__':
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.setblocking(0)
+ sock.bind(("", port))
+ sock.listen(128)
- io_loop = ioloop.IOLoop.instance()
- callback = functools.partial(connection_ready, sock)
- io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
- io_loop.start()
+ io_loop = tornado.ioloop.IOLoop.instance()
+ callback = functools.partial(connection_ready, sock)
+ io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
+ io_loop.start()
+
+ .. testoutput::
+ :hide:
"""
# Constants from the epoll module
diff --git a/tornado/iostream.py b/tornado/iostream.py
index 371a02d3..6d039a4a 100644
--- a/tornado/iostream.py
+++ b/tornado/iostream.py
@@ -928,7 +928,9 @@ class IOStream(BaseIOStream):
connected before passing it to the `IOStream` or connected with
`IOStream.connect`.
- A very simple (and broken) HTTP client using this class::
+ A very simple (and broken) HTTP client using this class:
+
+ .. testcode::
import tornado.ioloop
import tornado.iostream
@@ -947,14 +949,19 @@ class IOStream(BaseIOStream):
stream.read_bytes(int(headers[b"Content-Length"]), on_body)
def on_body(data):
- print data
+ print(data)
stream.close()
tornado.ioloop.IOLoop.instance().stop()
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
- stream = tornado.iostream.IOStream(s)
- stream.connect(("friendfeed.com", 80), send_request)
- tornado.ioloop.IOLoop.instance().start()
+ if __name__ == '__main__':
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+ stream = tornado.iostream.IOStream(s)
+ stream.connect(("friendfeed.com", 80), send_request)
+ tornado.ioloop.IOLoop.instance().start()
+
+ .. testoutput::
+ :hide:
+
"""
def __init__(self, socket, *args, **kwargs):
self.socket = socket
diff --git a/tornado/web.py b/tornado/web.py
index c1614db7..c8802733 100644
--- a/tornado/web.py
+++ b/tornado/web.py
@@ -19,7 +19,9 @@ features that allow it to scale to large numbers of open connections,
making it ideal for `long polling
`_.
-Here is a simple "Hello, world" example app::
+Here is a simple "Hello, world" example app:
+
+.. testcode::
import tornado.ioloop
import tornado.web
@@ -35,6 +37,10 @@ Here is a simple "Hello, world" example app::
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
+.. testoutput::
+ :hide:
+
+
See the :doc:`guide` for additional information.
Thread-safety notes
@@ -1470,10 +1476,12 @@ def asynchronous(method):
method returns. It is up to the request handler to call
`self.finish() ` to finish the HTTP
request. Without this decorator, the request is automatically
- finished when the ``get()`` or ``post()`` method returns. Example::
+ finished when the ``get()`` or ``post()`` method returns. Example:
- class MyRequestHandler(web.RequestHandler):
- @web.asynchronous
+ .. testcode::
+
+ class MyRequestHandler(RequestHandler):
+ @asynchronous
def get(self):
http = httpclient.AsyncHTTPClient()
http.fetch("http://friendfeed.com/", self._on_download)
@@ -1482,6 +1490,9 @@ def asynchronous(method):
self.write("Downloaded!")
self.finish()
+ .. testoutput::
+ :hide:
+
.. versionadded:: 3.1
The ability to use ``@gen.coroutine`` without ``@asynchronous``.
"""
diff --git a/tornado/websocket.py b/tornado/websocket.py
index 7c786636..b6994942 100644
--- a/tornado/websocket.py
+++ b/tornado/websocket.py
@@ -74,17 +74,22 @@ class WebSocketHandler(tornado.web.RequestHandler):
http://tools.ietf.org/html/rfc6455.
Here is an example WebSocket handler that echos back all received messages
- back to the client::
+ back to the client:
- class EchoWebSocket(websocket.WebSocketHandler):
+ .. testcode::
+
+ class EchoWebSocket(tornado.websocket.WebSocketHandler):
def open(self):
- print "WebSocket opened"
+ print("WebSocket opened")
def on_message(self, message):
self.write_message(u"You said: " + message)
def on_close(self):
- print "WebSocket closed"
+ print("WebSocket closed")
+
+ .. testoutput::
+ :hide:
WebSockets are not standard HTTP connections. The "handshake" is
HTTP, but after the handshake, the protocol is
diff --git a/tox.ini b/tox.ini
index 1055b234..2e227c47 100644
--- a/tox.ini
+++ b/tox.ini
@@ -155,11 +155,12 @@ commands =
[testenv:py2-sphinx-doctest]
changedir = docs
setenv = TORNADO_EXTENSION=0
+# No -W for doctests because that disallows tests with empty output.
commands =
- sphinx-build -q -E -n -W -b doctest . {envtmpdir}/doctest
+ sphinx-build -q -E -n -b doctest . {envtmpdir}/doctest
[testenv:py3-sphinx-doctest]
changedir = docs
setenv = TORNADO_EXTENSION=0
commands =
- sphinx-build -q -E -n -W -b doctest . {envtmpdir}/doctest
+ sphinx-build -q -E -n -b doctest . {envtmpdir}/doctest