SlideShare a Scribd company logo
AN INTRODUCTION TO
     TORNADO
               Gavin M. Roy
                   CTO
              myYearbook.com


pyCon 2011
Atlanta, GA
TORNADO AT
               MYYEARBOOK.COM
• Currency     Connect

  • Marketing Website, Portal, RESTful API

• Redirect     Engine

• Nerve

• Staplr   2

• Image    Upload Service
WHAT IS TORNADO?

•A scalable, non-blocking web server and micro-framework in
 Python 2.5 & 2.6.

  • Python          3 port underway

• Developed                at FriendFeed and open-sourced by Facebook

• Similar      to web.py in use

• Fast: ~1,500             requests/sec backend*
 * Your milage will vary
FEATURES

•   Small barrier to entry to quickly developing applications

•   Third Party Authentication via OpenID, OAuth Mixins

•   Light-weight template system

•   Auto-magical cross-site forgery protection

•   WSGI && Google App Engine Support

•   Develop using debug mode and automatically reload code and
    templates when changed on disk
class Application(object):
      """A collection of request handlers that make up a web application.

      Instances of this class are callable and can be passed directly to
      HTTPServer to serve the application:

          application = web.Application([
              (r"/", MainPageHandler),
          ])
          http_server = httpserver.HTTPServer(application)
          http_server.listen(8080)
          ioloop.IOLoop.instance().start()

      The constructor for this class takes in a list of URLSpec objects
      or (regexp, request_class) tuples. When we receive requests, we
      iterate over the list in order and instantiate an instance of the
      first request class whose regexp matches the request path.

      Each tuple can contain an optional third element, which should be a
      dictionary if it is present. That dictionary is passed as keyword
      arguments to the contructor of the handler. This pattern is used
      for the StaticFileHandler below:

          application = web.Application([
              (r"/static/(.*)", web.StaticFileHandler, {"path": "/var/www"}),
          ])




CLEAN, WELL DOCUMENTED CODE
WHAT TORNADO ISN’T

•A   full stack framework like Django

• Based   on Twisted

 • There    is an unmaintained port, Tornado on Twisted

 • Influenced    the Cyclone project

•A   replacement for a front-end web server

 • Run    behind a reverse proxy http server (nginx, Cherokee)
TORNADO VS TWISTED
•   Tornado doesn’t have to be asynchronous

•   It doesn’t have as many asynchronous drivers

    •   Can introduce blocking behaviors

•   The Tornado code is smaller and very easy to understand

•   Less mature than Twisted

•   You don’t need to buy into a development methodology

    •   Write Python not Twisted
KEY
 MODULES
Take only what you need
TORNADO.WEB

• Most   development is focused around this module

• Multiple   classes used in a web application

• Includes   decorators

  • Asynchronous     function: @tornado.web.asynchronous

  • Authentication   Required: @tornado.web.authenticated
TORNADO APPLICATION
• tornado.web.Application: Main           controller class

• Canonical Tornado      Hello World:
     import tornado.httpserver
     import tornado.ioloop
     import tornado.web

     class MainHandler(tornado.web.RequestHandler):
         def get(self):
             self.write("Hello, world")

     if __name__ == "__main__":
         application = tornado.web.Application([
             (r"/", MainHandler),
         ])

         http_server = tornado.httpserver.HTTPServer(application)
         http_server.listen(8888)
         tornado.ioloop.IOLoop.instance().start()
REQUEST HANDLERS

• tornado.web.RequestHandler

 • Extend   RequestHandler for larger web apps

   • Session   Handling

   • Database, Cache      Connections

   • Localization

• Implement    for your Application
REQUEST HANDLERS

• Classes   implementing define functions for processing

  • get, head, post, delete, put, options

• Hooks     on Initialization, Prepare, Close

• Functions    for setting HTTP Status, Headers, Cookies, Redirects
 and more
REQUEST HANDLER EXAMPLE
   import redis
   import tornado.web

   class MyRequestHandler(tornado.web.RequestHandler):

       def initialize(self):

           host = self.application.settings['Redis']['host']
           port = self.application.settings['Redis']['port']

           self.redis = redis.Redis(host, port)

   class Homepage(MyRequestHandler):

       @tornado.web.asynchronous
       def get(self):

           content = self.redis.get('homepage')
           self.write(content)
           self.finish()
TORNADO.TEMPLATE

• Not   required

• Similar    to other engines

• Limited    python exposure in template

• Fast, extensible

• Built-in   support in the RequestHandler class

• Adds   cache busting static content delivery
REQUESTHANDLER.RENDER
Code




           class Home(RequestHandler):

               def get(self):

                   self.render('home.html', username='Leeroy Jenkins');
Template




           <html>
             <body>
               Hi {{username}}, welcome to our site.
             </body>
           </html>
BASE TEMPLATE
<html>
    <head>
        <title>My Site :: {% block title %}Unextended Template{% end %}</title>
        <link rel="stylesheet" type="text/css" href="{{ static_url('css/site.css') }}" />
        <script type="text/javascript" src="{{ static_url('javascript/site.js') }}"></script>
         {% if not current_user %}
          <script type="text/javascript" src="http://api.recaptcha.net/js/recaptcha_ajax.js">
          </script>
         {% end %}
    </head>
    <body{% if current_user %} class="authenticated"{% end %}>
        {% include "header.html" %}
        {% if request.uri not in ['/', ''] and current_user %}
              {{ modules.MemberBar() }}
        {% end %}
        <div id="content">
              {% block content %}
                   No Content Specified
              {% end %}
        </div>
        <ul id="footer">
            <li><a href="/terms">{{_("Terms and Conditions")}}</a></li>
            <li class="center">{{_("Version")}}: {{ handler.application.settings['version'] }}</li>
            <li class="right">{{_("Copyright")}} &copy; {{ datetime.date.today().year }}</li>
        </ul>
    </body>
</html>
CONTENT TEMPLATE


{% extends "base.html" %}
{% block title %}{{_("Error Title")}}{% end %}
{% block content %}
<h1>{{_("Error Title")}}</h1>
<img src="/static/images/sad_robot.png" class="error_robot" />
<p class="error_message">{{_("Error Message")}}</p>
<h2 class="error">{{status_code}} - {{exception}}</h2>
{% end %}
TEMPLATE XSRF EXAMPLE


 <form action="/login" method="post">
   {{ xsrf_form_html() }}
   <div>Username: <input type="text" name="username"/></div>
   <div>Password: <input type="password" name="password"/></div>
   <div><input type="submit" value="Sign in"/></div>
 </form>




          No additional work required.
UI MODULES

• Extend templates with
 reusable widgets across the
 site

• One import assigned when
 Application is created

• Similar
        to RequestHandler in
 behavior
UIMODULE EXAMPLE
Embed
                  UIMODULE EXAMPLE
                  <div>{{ modules.HTTPSCheck() }}</div>




                 class HTTPSCheck(tornado.web.UIModule):

                     def render(self):
UIModule Class




                         if 'X-Forwarded-Ssl' not in self.request.headers or 
                             self.request.headers['X-Forwarded-Ssl'] != 'on':

                             return self.render_string("modules/ssl.html")

                         return ''



                 <div class="information">
Template




                     <a href="https://{{request.host}}{{request.uri}}">
                          {{_("Click here to use a secure connection")}}
                     </a>
                 </div>
TORNADO.LOCALE

•   Locale files in one directory

    •   In a csv format

    •   Named as locale.csv, e.g.
        en_US.csv

•   tornado.locale.load_translations
    (path)

    •   Pass path where files are located

•   Invoked as _ method in templates
ADDING LOCALIZATION
 import tornado.locale as locale
 import tornado.web

 class RequestHandler(tornado.web.RequestHandler):

     def get_user_locale(self):

         # Fake user object has a get_locale() function
         user_locale = self.user.get_locale()

         # If our locale is supported return it
         if user_locale in locale.get_supported_locales(None):
             return user_locale

         # Defaults to Accept-Language header if supported
         return None
USING LOCALIZATION

<html>
  <body>
    {{_("Welcome to our site.")}}
  </body>
</html>
LOCALE FILE EXAMPLE: DE_DE
   "New","Neu"
   "Donate","Spenden"
   "New Paste","Neuer Paste"
   "Secure, Private Pasting","Sicheres Pasten"
   "Unclaimed Hostname","Sie benutzen einen offenen Hostnamen.
   Klicken Sie heir für weitere Informationen."
   "Paste Options","Paste Optionen"
   "Formatting","Formatierung"
   "No Formatting","Keine Formatierung"
   "Line Numbers","Zeilennummern"
   "On","An"
   "Off","Aus"
   "Minutes","Minuten"
   "Hour","Stunde"
   "Day","Tag"
   "Week","Woche"
   "Year","Jahr"
   "Expire Paste","Wann soll der Paste gelöscht werden?"
   "Encryption","Verschlüsselung"
   "Encryption Key","Passwort-Verschlüsselung"
   "Encryption Algorithm","Algorithm-Verschlüsselung"
   "Save Paste","Paste speichern"
   "All Rights Reserved","Alle Rechte vorbehalten"
TEMPLATE EXAMPLE AGAIN
<html>
    <head>
        <title>My Site :: {% block title %}Unextended Template{% end %}</title>
        <link rel="stylesheet" type="text/css" href="{{ static_url('css/site.css') }}" />
        <script type="text/javascript" src="{{ static_url('javascript/site.js') }}"></script>
         {% if not current_user %}
          <script type="text/javascript" src="http://api.recaptcha.net/js/recaptcha_ajax.js">
          </script>
         {% end %}
    </head>
    <body{% if current_user %} class="authenticated"{% end %}>
        {% include "header.html" %}
        {% if request.uri not in ['/', ''] and current_user %}
              {{ modules.MemberBar() }}
        {% end %}
        <div id="content">
              {% block content %}
                   No Content Specified
              {% end %}
        </div>
        <ul id="footer">
            <li><a href="/terms">{{_("Terms and Conditions")}}</a></li>
            <li class="center">{{_("Version")}}: {{ handler.application.settings['version'] }}</li>
            <li class="right">{{_("Copyright")}} &copy; {{ datetime.date.today().year }}</li>
        </ul>
    </body>
</html>
TORNADO.AUTH

• Built   in Mixins for OpenID, OAuth, OAuth2

  •    Google, Twitter, Facebook, Facebook Graph, Friendfeed

• Use RequestHandler to extend your own login functions with
  the mixins if wanted

• Is   asynchronous

  • Not    supported in WSGI and Google App Engine
USING TORNADO.AUTH
- [/login/form, site.auth_reg.LoginForm]
- [/login/friendfeed, site.auth_reg.LoginFriendFeed]




class LoginFriendFeed(RequestHandler, tornado.auth.FriendFeedMixin):

    @tornado.web.asynchronous
    def get(self):
        if self.get_argument("oauth_token", None):
            self.get_authenticated_user(self.async_callback(self._on_auth))
            return
        self.authorize_redirect()

    def _on_auth(self, ffuser):
        if not ffuser:
            raise tornado.web.HTTPError(500, "FriendFeed auth failed")
            return

        username = ffuser['username']
TORNADO.IOLOOP
• Protocol    independent

• tornado.httpserver.HTTPServer     uses ioloop.IOLoop

• RabbitMQ      driver Pika uses ioloop.IOLoop

• Built   in timer functionality

  • tornado.ioloop.add_timeout

  • tornado.ioloop.PeriodicCallback
TORNADO.IOLOOP EXAMPLE
  class MyClient(object):

      def connect(self, host, port):

          # Create our socket
          self.sock = socket.socket(socket.AF_INET,
                                    socket.SOCK_STREAM, 0)
          self.sock.connect((host, port))
          self.sock.setblocking(0)
          self.io_loop = tornado.ioloop.IOLoop.instance()

          # Append our handler to tornado's ioloop for our socket
          events = tornado.ioloop.IOLoop.READ | 
                   tornado.ioloop.IOLoop.ERROR

          self.io_loop.add_handler(self.sock.fileno(),
                                   self._handle_events, events)



        https://github.com/pika/pika/blob/master/pika/adapters/tornado_connection.py
OTHER MODULES OF NOTE
•   tornado.database                    •   tornado.options

    •   MySQL wrapper                       •   Similar to optparse

•   tornado.escape                      •   tornado.testing

    •   Misc escape functions               •   Test support classes

•   tornado.httpclient                  •   tornado.websocket

    •   Async HTTP client                   •   Websocket Support

•   tornado.iostream

    •   Non-blocking TCP helper class
ASYNC DRIVERS

• Memcache

• MongoDB

• PostgreSQL

• RabbitMQ

• Redis
FIN

• Follow   me on Twitter @crad

• Blog: http://gavinroy.com

• Pika: http://github.com/pika

  • Async   RabbitMQ/AMQP Support for Tornado

• We’re    hiring at myYearbook.com

  • Drop    me an email: gmr@myyearbook.com
IMAGE CREDITS


• Lego by Craig A. Rodway
 http://www.flickr.com/photos/m0php/530526644/

• Delta   Clipper X courtesy of NASA

• United Nations San Francisco Conference by Yould
 http://www.flickr.com/photos/un_photo/3450033473/

More Related Content

PPTX
Introduction to Angularjs
PPTX
Restful api
PPTX
ppt of web development for diploma student
PPTX
Experience and Content Fragment
PPTX
Laravel ppt
PPTX
Json Web Token - JWT
PDF
Lets make a better react form
Introduction to Angularjs
Restful api
ppt of web development for diploma student
Experience and Content Fragment
Laravel ppt
Json Web Token - JWT
Lets make a better react form

What's hot (20)

PPTX
An Introduction To REST API
PPTX
Understanding REST APIs in 5 Simple Steps
PPT
Introduction to the Web API
PPT
Introduction to JavaScript (1).ppt
PDF
Postman: An Introduction for Testers
PDF
Observables in Angular
PDF
Learn REST in 18 Slides
PPT
Mvc architecture
PDF
Laravel Introduction
PDF
Basics of JavaScript
PPTX
Vagrant
PDF
API for Beginners
PDF
Introduction to django framework
PDF
Web Development with Python and Django
PPT
PHP - Web Development
PPTX
ReactJS presentation.pptx
PDF
CSS Grid Layout for Topconf, Linz
PPTX
An Introduction To REST API
Understanding REST APIs in 5 Simple Steps
Introduction to the Web API
Introduction to JavaScript (1).ppt
Postman: An Introduction for Testers
Observables in Angular
Learn REST in 18 Slides
Mvc architecture
Laravel Introduction
Basics of JavaScript
Vagrant
API for Beginners
Introduction to django framework
Web Development with Python and Django
PHP - Web Development
ReactJS presentation.pptx
CSS Grid Layout for Topconf, Linz
Ad

Viewers also liked (20)

PDF
Tornado Web Server Internals
PDF
Rapid web development using tornado web and mongodb
PPTX
Tornado - different Web programming
PDF
Tornadoweb
ZIP
Nginx + Tornado = 17k req/s
PPTX
Web backends development using Python
PDF
Programmation web asynchrone avec Tornado
PDF
Sinatra Ruby Framework
PDF
Crystal is a Rubyists friend (quick anecdote)
PDF
Tornado
PPTX
KEY
Tornado
ODP
Introduction to Tornado - TienNA
PPT
Real time server
PDF
Asynchronous web-development with Python
PDF
Aplikasi Penyelidikan Web 2,0
PPTX
Tornado web
PPTX
What is a tornado?
PPTX
Tornado
PDF
Contoh Lembar Catatan Fakta Guru
Tornado Web Server Internals
Rapid web development using tornado web and mongodb
Tornado - different Web programming
Tornadoweb
Nginx + Tornado = 17k req/s
Web backends development using Python
Programmation web asynchrone avec Tornado
Sinatra Ruby Framework
Crystal is a Rubyists friend (quick anecdote)
Tornado
Tornado
Introduction to Tornado - TienNA
Real time server
Asynchronous web-development with Python
Aplikasi Penyelidikan Web 2,0
Tornado web
What is a tornado?
Tornado
Contoh Lembar Catatan Fakta Guru
Ad

Similar to An Introduction to Tornado (20)

PDF
GDG Addis - An Introduction to Django and App Engine
KEY
Using and scaling Rack and Rack-based middleware
PPTX
Plugins on OnDemand with Remote Apps - Atlassian Summit 2012
PDF
Django Rest Framework and React and Redux, Oh My!
PDF
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
PDF
Web Components v1
PPTX
PPTX
Rest with Java EE 6 , Security , Backbone.js
PDF
Staying Sane with Drupal NEPHP
PDF
CouchDB for Web Applications - Erlang Factory London 2009
PDF
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
PPTX
Html5 and web technology update
PPTX
Webservices
PDF
Django at the Disco
PPT
nodejs_at_a_glance, understanding java script
ZIP
Django at the Disco
ZIP
Django at the Disco
ZIP
Django at the Disco
ZIP
Django at the Disco
PPT
nodejs_at_a_glance.ppt
GDG Addis - An Introduction to Django and App Engine
Using and scaling Rack and Rack-based middleware
Plugins on OnDemand with Remote Apps - Atlassian Summit 2012
Django Rest Framework and React and Redux, Oh My!
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
Web Components v1
Rest with Java EE 6 , Security , Backbone.js
Staying Sane with Drupal NEPHP
CouchDB for Web Applications - Erlang Factory London 2009
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
Html5 and web technology update
Webservices
Django at the Disco
nodejs_at_a_glance, understanding java script
Django at the Disco
Django at the Disco
Django at the Disco
Django at the Disco
nodejs_at_a_glance.ppt

Recently uploaded (20)

PDF
Empathic Computing: Creating Shared Understanding
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Spectral efficient network and resource selection model in 5G networks
PPT
Teaching material agriculture food technology
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
MYSQL Presentation for SQL database connectivity
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Modernizing your data center with Dell and AMD
PDF
cuic standard and advanced reporting.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
Big Data Technologies - Introduction.pptx
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
Empathic Computing: Creating Shared Understanding
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Advanced methodologies resolving dimensionality complications for autism neur...
Digital-Transformation-Roadmap-for-Companies.pptx
Encapsulation_ Review paper, used for researhc scholars
Per capita expenditure prediction using model stacking based on satellite ima...
Spectral efficient network and resource selection model in 5G networks
Teaching material agriculture food technology
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
MYSQL Presentation for SQL database connectivity
The AUB Centre for AI in Media Proposal.docx
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Modernizing your data center with Dell and AMD
cuic standard and advanced reporting.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Big Data Technologies - Introduction.pptx
The Rise and Fall of 3GPP – Time for a Sabbatical?

An Introduction to Tornado

  • 1. AN INTRODUCTION TO TORNADO Gavin M. Roy CTO myYearbook.com pyCon 2011 Atlanta, GA
  • 2. TORNADO AT MYYEARBOOK.COM • Currency Connect • Marketing Website, Portal, RESTful API • Redirect Engine • Nerve • Staplr 2 • Image Upload Service
  • 3. WHAT IS TORNADO? •A scalable, non-blocking web server and micro-framework in Python 2.5 & 2.6. • Python 3 port underway • Developed at FriendFeed and open-sourced by Facebook • Similar to web.py in use • Fast: ~1,500 requests/sec backend* * Your milage will vary
  • 4. FEATURES • Small barrier to entry to quickly developing applications • Third Party Authentication via OpenID, OAuth Mixins • Light-weight template system • Auto-magical cross-site forgery protection • WSGI && Google App Engine Support • Develop using debug mode and automatically reload code and templates when changed on disk
  • 5. class Application(object):     """A collection of request handlers that make up a web application. Instances of this class are callable and can be passed directly to HTTPServer to serve the application: application = web.Application([ (r"/", MainPageHandler), ]) http_server = httpserver.HTTPServer(application) http_server.listen(8080) ioloop.IOLoop.instance().start() The constructor for this class takes in a list of URLSpec objects or (regexp, request_class) tuples. When we receive requests, we iterate over the list in order and instantiate an instance of the first request class whose regexp matches the request path. Each tuple can contain an optional third element, which should be a dictionary if it is present. That dictionary is passed as keyword arguments to the contructor of the handler. This pattern is used for the StaticFileHandler below: application = web.Application([ (r"/static/(.*)", web.StaticFileHandler, {"path": "/var/www"}), ]) CLEAN, WELL DOCUMENTED CODE
  • 6. WHAT TORNADO ISN’T •A full stack framework like Django • Based on Twisted • There is an unmaintained port, Tornado on Twisted • Influenced the Cyclone project •A replacement for a front-end web server • Run behind a reverse proxy http server (nginx, Cherokee)
  • 7. TORNADO VS TWISTED • Tornado doesn’t have to be asynchronous • It doesn’t have as many asynchronous drivers • Can introduce blocking behaviors • The Tornado code is smaller and very easy to understand • Less mature than Twisted • You don’t need to buy into a development methodology • Write Python not Twisted
  • 8. KEY MODULES Take only what you need
  • 9. TORNADO.WEB • Most development is focused around this module • Multiple classes used in a web application • Includes decorators • Asynchronous function: @tornado.web.asynchronous • Authentication Required: @tornado.web.authenticated
  • 10. TORNADO APPLICATION • tornado.web.Application: Main controller class • Canonical Tornado Hello World: import tornado.httpserver import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") if __name__ == "__main__": application = tornado.web.Application([ (r"/", MainHandler), ]) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(8888) tornado.ioloop.IOLoop.instance().start()
  • 11. REQUEST HANDLERS • tornado.web.RequestHandler • Extend RequestHandler for larger web apps • Session Handling • Database, Cache Connections • Localization • Implement for your Application
  • 12. REQUEST HANDLERS • Classes implementing define functions for processing • get, head, post, delete, put, options • Hooks on Initialization, Prepare, Close • Functions for setting HTTP Status, Headers, Cookies, Redirects and more
  • 13. REQUEST HANDLER EXAMPLE import redis import tornado.web class MyRequestHandler(tornado.web.RequestHandler): def initialize(self): host = self.application.settings['Redis']['host'] port = self.application.settings['Redis']['port'] self.redis = redis.Redis(host, port) class Homepage(MyRequestHandler): @tornado.web.asynchronous def get(self): content = self.redis.get('homepage') self.write(content) self.finish()
  • 14. TORNADO.TEMPLATE • Not required • Similar to other engines • Limited python exposure in template • Fast, extensible • Built-in support in the RequestHandler class • Adds cache busting static content delivery
  • 15. REQUESTHANDLER.RENDER Code class Home(RequestHandler): def get(self): self.render('home.html', username='Leeroy Jenkins'); Template <html> <body> Hi {{username}}, welcome to our site. </body> </html>
  • 16. BASE TEMPLATE <html> <head> <title>My Site :: {% block title %}Unextended Template{% end %}</title> <link rel="stylesheet" type="text/css" href="{{ static_url('css/site.css') }}" /> <script type="text/javascript" src="{{ static_url('javascript/site.js') }}"></script> {% if not current_user %} <script type="text/javascript" src="http://api.recaptcha.net/js/recaptcha_ajax.js"> </script> {% end %} </head> <body{% if current_user %} class="authenticated"{% end %}> {% include "header.html" %} {% if request.uri not in ['/', ''] and current_user %} {{ modules.MemberBar() }} {% end %} <div id="content"> {% block content %} No Content Specified {% end %} </div> <ul id="footer"> <li><a href="/terms">{{_("Terms and Conditions")}}</a></li> <li class="center">{{_("Version")}}: {{ handler.application.settings['version'] }}</li> <li class="right">{{_("Copyright")}} &copy; {{ datetime.date.today().year }}</li> </ul> </body> </html>
  • 17. CONTENT TEMPLATE {% extends "base.html" %} {% block title %}{{_("Error Title")}}{% end %} {% block content %} <h1>{{_("Error Title")}}</h1> <img src="/static/images/sad_robot.png" class="error_robot" /> <p class="error_message">{{_("Error Message")}}</p> <h2 class="error">{{status_code}} - {{exception}}</h2> {% end %}
  • 18. TEMPLATE XSRF EXAMPLE <form action="/login" method="post"> {{ xsrf_form_html() }} <div>Username: <input type="text" name="username"/></div> <div>Password: <input type="password" name="password"/></div> <div><input type="submit" value="Sign in"/></div> </form> No additional work required.
  • 19. UI MODULES • Extend templates with reusable widgets across the site • One import assigned when Application is created • Similar to RequestHandler in behavior
  • 21. Embed UIMODULE EXAMPLE  <div>{{ modules.HTTPSCheck() }}</div> class HTTPSCheck(tornado.web.UIModule): def render(self): UIModule Class if 'X-Forwarded-Ssl' not in self.request.headers or self.request.headers['X-Forwarded-Ssl'] != 'on': return self.render_string("modules/ssl.html") return '' <div class="information"> Template <a href="https://{{request.host}}{{request.uri}}"> {{_("Click here to use a secure connection")}} </a> </div>
  • 22. TORNADO.LOCALE • Locale files in one directory • In a csv format • Named as locale.csv, e.g. en_US.csv • tornado.locale.load_translations (path) • Pass path where files are located • Invoked as _ method in templates
  • 23. ADDING LOCALIZATION import tornado.locale as locale import tornado.web class RequestHandler(tornado.web.RequestHandler): def get_user_locale(self): # Fake user object has a get_locale() function user_locale = self.user.get_locale() # If our locale is supported return it if user_locale in locale.get_supported_locales(None): return user_locale # Defaults to Accept-Language header if supported return None
  • 24. USING LOCALIZATION <html> <body> {{_("Welcome to our site.")}} </body> </html>
  • 25. LOCALE FILE EXAMPLE: DE_DE "New","Neu" "Donate","Spenden" "New Paste","Neuer Paste" "Secure, Private Pasting","Sicheres Pasten" "Unclaimed Hostname","Sie benutzen einen offenen Hostnamen. Klicken Sie heir für weitere Informationen." "Paste Options","Paste Optionen" "Formatting","Formatierung" "No Formatting","Keine Formatierung" "Line Numbers","Zeilennummern" "On","An" "Off","Aus" "Minutes","Minuten" "Hour","Stunde" "Day","Tag" "Week","Woche" "Year","Jahr" "Expire Paste","Wann soll der Paste gelöscht werden?" "Encryption","Verschlüsselung" "Encryption Key","Passwort-Verschlüsselung" "Encryption Algorithm","Algorithm-Verschlüsselung" "Save Paste","Paste speichern" "All Rights Reserved","Alle Rechte vorbehalten"
  • 26. TEMPLATE EXAMPLE AGAIN <html> <head> <title>My Site :: {% block title %}Unextended Template{% end %}</title> <link rel="stylesheet" type="text/css" href="{{ static_url('css/site.css') }}" /> <script type="text/javascript" src="{{ static_url('javascript/site.js') }}"></script> {% if not current_user %} <script type="text/javascript" src="http://api.recaptcha.net/js/recaptcha_ajax.js"> </script> {% end %} </head> <body{% if current_user %} class="authenticated"{% end %}> {% include "header.html" %} {% if request.uri not in ['/', ''] and current_user %} {{ modules.MemberBar() }} {% end %} <div id="content"> {% block content %} No Content Specified {% end %} </div> <ul id="footer"> <li><a href="/terms">{{_("Terms and Conditions")}}</a></li> <li class="center">{{_("Version")}}: {{ handler.application.settings['version'] }}</li> <li class="right">{{_("Copyright")}} &copy; {{ datetime.date.today().year }}</li> </ul> </body> </html>
  • 27. TORNADO.AUTH • Built in Mixins for OpenID, OAuth, OAuth2 • Google, Twitter, Facebook, Facebook Graph, Friendfeed • Use RequestHandler to extend your own login functions with the mixins if wanted • Is asynchronous • Not supported in WSGI and Google App Engine
  • 28. USING TORNADO.AUTH - [/login/form, site.auth_reg.LoginForm] - [/login/friendfeed, site.auth_reg.LoginFriendFeed] class LoginFriendFeed(RequestHandler, tornado.auth.FriendFeedMixin): @tornado.web.asynchronous def get(self): if self.get_argument("oauth_token", None): self.get_authenticated_user(self.async_callback(self._on_auth)) return self.authorize_redirect() def _on_auth(self, ffuser): if not ffuser: raise tornado.web.HTTPError(500, "FriendFeed auth failed") return username = ffuser['username']
  • 29. TORNADO.IOLOOP • Protocol independent • tornado.httpserver.HTTPServer uses ioloop.IOLoop • RabbitMQ driver Pika uses ioloop.IOLoop • Built in timer functionality • tornado.ioloop.add_timeout • tornado.ioloop.PeriodicCallback
  • 30. TORNADO.IOLOOP EXAMPLE class MyClient(object): def connect(self, host, port): # Create our socket self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) self.sock.connect((host, port)) self.sock.setblocking(0) self.io_loop = tornado.ioloop.IOLoop.instance() # Append our handler to tornado's ioloop for our socket events = tornado.ioloop.IOLoop.READ | tornado.ioloop.IOLoop.ERROR self.io_loop.add_handler(self.sock.fileno(), self._handle_events, events) https://github.com/pika/pika/blob/master/pika/adapters/tornado_connection.py
  • 31. OTHER MODULES OF NOTE • tornado.database • tornado.options • MySQL wrapper • Similar to optparse • tornado.escape • tornado.testing • Misc escape functions • Test support classes • tornado.httpclient • tornado.websocket • Async HTTP client • Websocket Support • tornado.iostream • Non-blocking TCP helper class
  • 32. ASYNC DRIVERS • Memcache • MongoDB • PostgreSQL • RabbitMQ • Redis
  • 33. FIN • Follow me on Twitter @crad • Blog: http://gavinroy.com • Pika: http://github.com/pika • Async RabbitMQ/AMQP Support for Tornado • We’re hiring at myYearbook.com • Drop me an email: gmr@myyearbook.com
  • 34. IMAGE CREDITS • Lego by Craig A. Rodway http://www.flickr.com/photos/m0php/530526644/ • Delta Clipper X courtesy of NASA • United Nations San Francisco Conference by Yould http://www.flickr.com/photos/un_photo/3450033473/