Tornado
A Python Web Framework
- Asynchronous Networking
- Scalable
- Uses non-blocking network I/O
- Fast (faster than Django, web.py, CherryPy)
- Great for creating RESTful services
INstallation
-
Available in PyPI
-
Install with pip or easy_install
-
Source on GitHub
-
Runs on python 2.6+ and 3.2+
-
Supports Unix-Like environments
-
Not suggested for running on Mac OS X
-
(But who would host off of OS X anyways?)
INFORMATION
-
Created by FriendFeed
-
FF acquired by Facebook, tornado opensourced afterwards
- Docs/Examples available at www.tornadoweb.org
- In use here at Synacor!
The Basics
Tornado Application
Request Handlers
Arguments
Routing
Tornado Application
tornado.web.Application
-
Holds a mapping of URLs to Handlers
-
Used in conjunction with httpserver.HTTPServer
-
Can register static files as well
-
Even can handle virtual hosts!
-
Configuration also registered with Application
REQUEST HANDLERS
-
Accept a request
- Main methods are HTTP verbs
- GET
- POST
- PUT
- DELETE
- HEAD
- OPTIONS
Request Handlers
-
Able to access request parameters
-
Does the communication heavy lifting
-
self.write() to send data to client
-
self.set_header() set appropriate headers
-
self.set_status() to modify HTTP status codes
- self.redirect() to send user elsewhere
REQUEST HANDLERS
- Can also use templating engine
- Python embedded in templates
- Sounds familiar
- Localization is a breeze
- If you use their templates, at least
REQUEST HANDLERS
import tornado.ioloopimport tornado.webclass BaseHandler(tornado.web.RequestHandler):def get(self):self.write("Hello, world")application = tornado.web.Application([(r"/", BaseHandler),])if __name__ == "__main__":application.listen(8080)tornado.ioloop.IOLoop.instance.start()
Respond to GET requests with "Hello, world"
Available on the url "/"
Arguments
(I'm right, you're wrong!)
-
Easy access to request arguments (GET and POST!)
-
self.get_argument('name')
- ?name=Matt
- arg 'name' required
- only returns last defined argument
-
self.get_argument('name', default='John Doe', strip=True)
- arg 'name' defaults to 'John Doe', strips whitespace
-
self.get_arguments('name') -- return list of arguments 'name'
- returns list of argument 'name'
- ?name[]=Matt&name[]=John
ARGUMENTS
File Uploads
-
Access via self.request
-
(also where headers and request body are found)
-
self.request.files['name'][0]
-
where 'name' is the field name
-
provides 'filename', and binary data in 'body'
Note: The file sits in RAM
the use of nginx's upload module is suggested
Arguments
class ArgumentHandler(tornado.RequestHandler):def get(self):#name is requiredname = self.get_argument('name')names = self.get_arguments('names') # empty list if not presentself.write('Hello, {0}<br />'.format(name))if len(names) > 0:self.write('Your list of names are: {0}'.format(', '.join(names)))else:self.write("Provide a list of names in the 'names' argument!")
Routing
-
Registered within Application
-
Pairs a regular expression with a handler
-
Regex mapped to handler
-
Matches provided to handler as parameters
-
Can map as many Regex to a single Handler as you want
Routing
application = tornado.web.Application([ (r"/", MainHandler),(r"/hello/world/", HelloWorldHandler),(r"/hello/([^/]+)/?"), HelloAnythingHandler),])
class HelloWorldHandler(tornado.web.RequestHandler):def get(self):self.write("Hello, World")
Yes, I could drop the hello world handler and have the same functionality.class HelloAnythingHandler(tornado.web.RequestHandler):def get(self, anything):self.write("Hello, {0}".format(anything))
Some things to consider
@tornado.asynchronous decorator
means request is asynchronous
does not make code asynchronous
use a mongodb driver such as motor
motor allows for asynchronous mongo operations
if using decorator, must use self.finish
request will hang until client timesout otherwise
Demo Time
Let's see a working demo of a service!
Source code available at:
https://github.com/mattgen88/tornado-demo
Tornado
By Matthew General
Tornado
- 1,093