diff --git a/tornado/auth.py b/tornado/auth.py index d4f50369..91a29519 100644 --- a/tornado/auth.py +++ b/tornado/auth.py @@ -697,9 +697,9 @@ class GoogleMixin(OpenIdMixin, OAuthMixin): Some of the available resources are: - Gmail Contacts - http://www.google.com/m8/feeds/ - Calendar - http://www.google.com/calendar/feeds/ - Finance - http://finance.google.com/finance/feeds/ + * Gmail Contacts - http://www.google.com/m8/feeds/ + * Calendar - http://www.google.com/calendar/feeds/ + * Finance - http://finance.google.com/finance/feeds/ You can authorize multiple resources by separating the resource URLs with a space. @@ -740,6 +740,9 @@ class GoogleMixin(OpenIdMixin, OAuthMixin): class FacebookMixin(object): """Facebook Connect authentication. + New applications should consider using `FacebookGraphMixin` below instead + of this class. + To authenticate with Facebook, register your application with Facebook at http://www.facebook.com/developers/apps.php. Then copy your API Key and Application Secret to the application settings @@ -799,10 +802,10 @@ class FacebookMixin(object): http://wiki.developers.facebook.com/index.php/Extended_permission. The most common resource types include: - publish_stream - read_stream - email - sms + * publish_stream + * read_stream + * email + * sms extended_permissions can be a single permission name or a list of names. To get the session secret and session key, call @@ -918,13 +921,14 @@ class FacebookMixin(object): return hashlib.md5(body).hexdigest() class FacebookGraphMixin(OAuth2Mixin): + """Facebook authentication using the new Graph API and OAuth2.""" _OAUTH_ACCESS_TOKEN_URL = "https://graph.facebook.com/oauth/access_token?" _OAUTH_AUTHORIZE_URL = "https://graph.facebook.com/oauth/authorize?" _OAUTH_NO_CALLBACKS = False def get_authenticated_user(self, redirect_uri, client_id, client_secret, code, callback, extra_fields=None): - """ Handles the login for the Facebook user, returning a user object. + """Handles the login for the Facebook user, returning a user object. Example usage:: diff --git a/tornado/autoreload.py b/tornado/autoreload.py index 69738bdc..2ed0faec 100644 --- a/tornado/autoreload.py +++ b/tornado/autoreload.py @@ -16,8 +16,14 @@ """A module to automatically restart the server when a module is modified. +Most applications should not call this module directly. Instead, pass the +keyword argument ``debug=True`` to the `tornado.web.Application` constructor. +This will enable autoreload mode as well as checking for changes to templates +and static resources. + This module depends on IOLoop, so it will not work in WSGI applications -and Google AppEngine. +and Google AppEngine. It also will not work correctly when HTTPServer's +multi-process mode is used. """ import functools diff --git a/tornado/options.py b/tornado/options.py index e41e3678..2a89e51d 100644 --- a/tornado/options.py +++ b/tornado/options.py @@ -310,7 +310,10 @@ class Error(Exception): def enable_pretty_logging(): - """Turns on formatted logging output as configured.""" + """Turns on formatted logging output as configured. + + This is called automatically by `parse_command_line`. + """ root_logger = logging.getLogger() if options.log_file_prefix: channel = logging.handlers.RotatingFileHandler( diff --git a/tornado/stack_context.py b/tornado/stack_context.py index 5b012c53..53edbd27 100644 --- a/tornado/stack_context.py +++ b/tornado/stack_context.py @@ -61,19 +61,19 @@ class _State(threading.local): _state = _State() class StackContext(object): + '''Establishes the given context as a StackContext that will be transferred. + + Note that the parameter is a callable that returns a context + manager, not the context itself. That is, where for a + non-transferable context manager you would say:: + + with my_context(): + + StackContext takes the function itself rather than its result:: + + with StackContext(my_context): + ''' def __init__(self, context_factory): - '''Establishes the given context as a StackContext that will be transferred. - - Note that the parameter is a callable that returns a context - manager, not the context itself. That is, where for a - non-transferable context manager you would say:: - - with my_context(): - - StackContext takes the function itself rather than its result:: - - with StackContext(my_context): - ''' self.context_factory = context_factory # Note that some of this code is duplicated in ExceptionStackContext @@ -98,19 +98,19 @@ class StackContext(object): _state.contexts = self.old_contexts class ExceptionStackContext(object): + '''Specialization of StackContext for exception handling. + + The supplied exception_handler function will be called in the + event of an uncaught exception in this context. The semantics are + similar to a try/finally clause, and intended use cases are to log + an error, close a socket, or similar cleanup actions. The + exc_info triple (type, value, traceback) will be passed to the + exception_handler function. + + If the exception handler returns true, the exception will be + consumed and will not be propagated to other exception handlers. + ''' def __init__(self, exception_handler): - '''Specialization of StackContext for exception handling. - - The supplied exception_handler function will be called in the - event of an uncaught exception in this context. The semantics are - similar to a try/finally clause, and intended use cases are to log - an error, close a socket, or similar cleanup actions. The - exc_info triple (type, value, traceback) will be passed to the - exception_handler function. - - If the exception handler returns true, the exception will be - consumed and will not be propagated to other exception handlers. - ''' self.exception_handler = exception_handler def __enter__(self): diff --git a/tornado/testing.py b/tornado/testing.py index 9c42e8a5..e5cee162 100644 --- a/tornado/testing.py +++ b/tornado/testing.py @@ -3,13 +3,13 @@ This module contains three parts: -* AsyncTestCase/AsyncHTTPTestCase: Subclasses of unittest.TestCase +* `AsyncTestCase`/`AsyncHTTPTestCase`: Subclasses of unittest.TestCase with additional support for testing asynchronous (IOLoop-based) code. -* LogTrapTestCase: Subclass of unittest.TestCase that discards log output +* `LogTrapTestCase`: Subclass of unittest.TestCase that discards log output from tests that pass and only produces output for failing tests. -* main(): A simple test runner (wrapper around unittest.main()) with support +* `main()`: A simple test runner (wrapper around unittest.main()) with support for the tornado.autoreload module to rerun the tests when code changes. These components may be used together or independently. In particular, diff --git a/tornado/websocket.py b/tornado/websocket.py index 104349d7..ca203828 100644 --- a/tornado/websocket.py +++ b/tornado/websocket.py @@ -1,17 +1,16 @@ +"""Server-side implementation of the WebSocket protocol. + +`WebSockets `_ allow for bidirectional +communication between the browser and server. + +.. warning:: + + The WebSocket protocol is still in development. This module currently + implements the "draft76" version of the protocol, which is supported + only by Chrome and Safari. See this `browser compatibility table + `_ on Wikipedia. +""" # Author: Jacob Kristhammar, 2010 -# -# Updated version of websocket.py[1] that implements latest[2] stable version -# of the websocket protocol. -# -# NB. It's no longer possible to manually select which callback that should -# be invoked upon message reception. Instead you must override the -# on_message(message) method to handle incoming messsages. -# This also means that you don't have to explicitly invoke -# receive_message, in fact you shouldn't. -# -# [1] http://github.com/facebook/tornado/blob/ -# 2c89b89536bbfa081745336bb5ab5465c448cb8a/tornado/websocket.py -# [2] http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 import functools import hashlib diff --git a/tornado/wsgi.py b/tornado/wsgi.py index 8b6177f7..6527d30c 100644 --- a/tornado/wsgi.py +++ b/tornado/wsgi.py @@ -16,38 +16,17 @@ """WSGI support for the Tornado web framework. -We export WSGIApplication, which is very similar to web.Application, except -no asynchronous methods are supported (since WSGI does not support -non-blocking requests properly). If you call self.flush() or other -asynchronous methods in your request handlers running in a WSGIApplication, -we throw an exception. +WSGI is the Python standard for web servers, and allows for interoperability +between Tornado and other Python web frameworks and servers. This module +provides WSGI support in two ways: -Example usage:: - - import tornado.web - import tornado.wsgi - import wsgiref.simple_server - - class MainHandler(tornado.web.RequestHandler): - def get(self): - self.write("Hello, world") - - if __name__ == "__main__": - application = tornado.wsgi.WSGIApplication([ - (r"/", MainHandler), - ]) - server = wsgiref.simple_server.make_server('', 8888, application) - server.serve_forever() - -See the 'appengine' demo for an example of using this module to run -a Tornado app on Google AppEngine. - -Since no asynchronous methods are available for WSGI applications, the -httpclient and auth modules are both not available for WSGI applications. - -We also export WSGIContainer, which lets you run other WSGI-compatible -frameworks on the Tornado HTTP server and I/O loop. See WSGIContainer for -details and documentation. +* `WSGIApplication` is a version of `tornado.web.Application` that can run + inside a WSGI server. This is useful for running a Tornado app on another + HTTP server, such as Google App Engine. See the `WSGIApplication` class + documentation for limitations that apply. +* `WSGIContainer` lets you run other WSGI applications and frameworks on the + Tornado HTTP server. For example, with this class you can mix Django + and Tornado handlers in a single server. """ import cgi @@ -70,10 +49,38 @@ except ImportError: from cStringIO import StringIO as BytesIO # python 2 class WSGIApplication(web.Application): - """A WSGI-equivalent of web.Application. + """A WSGI equivalent of `tornado.web.Application`. + WSGIApplication is very similar to web.Application, except no + asynchronous methods are supported (since WSGI does not support + non-blocking requests properly). If you call self.flush() or other + asynchronous methods in your request handlers running in a + WSGIApplication, we throw an exception. + + Example usage:: + + import tornado.web + import tornado.wsgi + import wsgiref.simple_server + + class MainHandler(tornado.web.RequestHandler): + def get(self): + self.write("Hello, world") + + if __name__ == "__main__": + application = tornado.wsgi.WSGIApplication([ + (r"/", MainHandler), + ]) + server = wsgiref.simple_server.make_server('', 8888, application) + server.serve_forever() + + See the 'appengine' demo for an example of using this module to run + a Tornado app on Google AppEngine. + + Since no asynchronous methods are available for WSGI applications, the + httpclient and auth modules are both not available for WSGI applications. We support the same interface, but handlers running in a WSGIApplication - do not support flush() or asynchronous methods. + do not support flush() or asynchronous methods. """ def __init__(self, handlers=None, default_host="", **settings): web.Application.__init__(self, handlers, default_host, transforms=[], @@ -94,7 +101,7 @@ class WSGIApplication(web.Application): class HTTPRequest(object): - """Mimics httpserver.HTTPRequest for WSGI applications.""" + """Mimics `tornado.httpserver.HTTPRequest` for WSGI applications.""" def __init__(self, environ): """Parses the given WSGI environ to construct the request.""" self.method = environ["REQUEST_METHOD"] @@ -182,8 +189,11 @@ class WSGIContainer(object): tornado.ioloop.IOLoop.instance().start() This class is intended to let other frameworks (Django, web.py, etc) - run on the Tornado HTTP server and I/O loop. It has not yet been - thoroughly tested in production. + run on the Tornado HTTP server and I/O loop. + + The `tornado.web.FallbackHandler` class is often useful for mixing + Tornado and WSGI apps in the same server. See + https://github.com/bdarnell/django-tornado-demo for a complete example. """ def __init__(self, wsgi_application): self.wsgi_application = wsgi_application diff --git a/website/sphinx/auth.rst b/website/sphinx/auth.rst index 46065945..80207458 100644 --- a/website/sphinx/auth.rst +++ b/website/sphinx/auth.rst @@ -2,4 +2,42 @@ ============================================================ .. automodule:: tornado.auth - :members: + + Common protocols + ---------------- + + .. autoclass:: OpenIdMixin + :members: + + .. autoclass:: OAuthMixin + :members: + + .. autoclass:: OAuth2Mixin + :members: + + Twitter + ------- + + .. autoclass:: TwitterMixin + :members: + + FriendFeed + ---------- + + .. autoclass:: FriendFeedMixin + :members: + + Google + ------ + + .. autoclass:: GoogleMixin + :members: + + Facebook + -------- + + .. autoclass:: FacebookMixin + :members: + + .. autoclass:: FacebookGraphMixin + :members: diff --git a/website/sphinx/testing.rst b/website/sphinx/testing.rst index 9378d927..fdb1008d 100644 --- a/website/sphinx/testing.rst +++ b/website/sphinx/testing.rst @@ -2,4 +2,23 @@ ================================================================== .. automodule:: tornado.testing - :members: + + Asynchronous test cases + ----------------------- + + .. autoclass:: AsyncTestCase + :members: + + .. autoclass:: AsyncHTTPTestCase + :members: + + Controlling log output + ---------------------- + + .. autoclass:: LogTrapTestCase + :members: + + Test runner + ----------- + + .. autofunction:: main diff --git a/website/sphinx/wsgi.rst b/website/sphinx/wsgi.rst index 489e85d9..d0a72cdb 100644 --- a/website/sphinx/wsgi.rst +++ b/website/sphinx/wsgi.rst @@ -2,4 +2,18 @@ ============================================================================== .. automodule:: tornado.wsgi - :members: + + WSGIApplication + --------------- + + .. autoclass:: WSGIApplication + :members: + + .. autoclass:: HTTPRequest + :members: + + WSGIContainer + ------------- + + .. autoclass:: WSGIContainer + :members: