Skip to content


Subversion checkout URL

You can clone with
Download ZIP
Tinman is a Tornado support package including an application wrapper/runner and a set of handy decorators.
Python Shell

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.


Tinman is a take what you need package designed to speed development of Tornado applications. It includes an application wrapper and a toolbox of decorators and utilities.


  • RequestHandler output caching
  • Network address whitelisting decorator
  • Method/Function debug logging decorator
  • A full featured application wrapper
  • Automated connection setup for RabbitMQ and Redis (memcached, mongodb, mysql, postgresql planned)


  • ipaddr
  • pyyaml

Optional Dependencies

  • pika >= v0.9.5

Application Runner

The tinman application runner works off a YAML configuration file format and provides a convenient interface for running tornado applications interactively or as a daemon.

Command Line Syntax:

    Usage: tinman -c <configfile> [options]

    Tornado application wrapper

      --version             show program's version number and exit
      -h, --help            show this help message and exit
      -c CONFIG, --config=CONFIG
                            Specify the configuration file for use
      -f, --foreground      Run interactively in console

Configuration File Syntax:

    %YAML 1.2
        base_path: /home/foo/mywebsite
        debug: True
        xsrf_cookies: False
        # Any other vaidate Tornado application setting item

        no_keep_alive: False
        ports: [8000,8001]
        xheaders: True

        #filename: log.txt
        format: "%(module)-10s# %(lineno)-5d %(levelname) -10s %(asctime)s  %(message)s"
        # Valid values: debug, info, warning, error, critical
        level: debug
        handler: syslog
            address: /dev/log
            facility: LOG_LOCAL6

    # Automatically connect to RabbitMQ
        host: localhost
        port: 5672
        username: guest
        password: guest
        virtual_host: /

    # Automatically connect to Redis
        host: localhost
        port: 6379
        db: 0

            - /
            - test.example.Home
            # /c1f1-7c5d9e0f.gif
            - re
            - /(c[a-f0-9]f[a-f0-9]{1,3}-[a-f0-9]{8}).gif
            - test.example.Pixel
            - .*
            - tornado.web.RedirectHandler
            - {"url": ""}

Test Application

The tinman application runner has a built in test application. To see if the module is setup correctly simply run:

tinman -f

In your console you should see output similar to:

Configuration not specified, running Tinman Test Application
utils       # 247   INFO      2011-06-11 23:25:26,164  Log level set to 10
cli         # 145   INFO      2011-06-11 23:25:26,164  Starting Tinman v0.2.1 process for port 8000
cli         # 154   DEBUG     2011-06-11 23:25:26,169  All children spawned
application # 106   DEBUG     2011-06-11 23:25:26,170  Initializing route: / with tinman.test.DefaultHandler
application # 36    INFO      2011-06-11 23:25:26,171  Appending handler: ('/', <class 'tinman.test.DefaultHandler'>)
cli         # 171   INFO      2011-06-11 23:25:26,174  Starting Tornado v1.2.1 HTTPServer on port 8000
web         # 1235  INFO      2011-06-11 23:25:32,782  200 GET / ( 1.24ms

You should now be able to access a test webpage on port 8000. CTRL-C will exit.



Vaidates the requesting IP address against a list of ip address blocks specified in Application.settings


# Define the whitelist as part of your application settings
settings['whitelist'] = ['',

application = Application(routes, **settings)

# Specify the decorator in each method of your RequestHandler class
# where you'd like to enforce the whitelist
class MyClass(tornado.web.RequestHandler):

  def get(self):
      self.write("IP was whitelisted")

In addition you may add the whitelist right into the configuration file:



A local in-memory cache decorator. RequestHandler class method calls are cached by name and arguments. Note that this monkey-patches the RequestHandler class on execution and will cache the total output created including all of the template rendering if there is anything. Local cache can be flushed with tinman.cache.flush()


class MyClass(tornado.web.RequestHandler):

   def get(self, content_id):
       self.write("Hello, World")


Send a logging.debug message with the class, method and arguments called.


class MyClass(tornado.web.RequestHandler):

    def get(self, content_id):
       self.write("Hello, World")



A collection of helpful functions for starting, daemonizing and stopping a Tornado application.

daemonize(pidfile=None, user=None, group=None)

Daemonize the application specifying the PID in the pidfile if specified, setting the application to run as the user and group if specified.

setup_logging(config, debug=False)

Setup the logging module with the parameters specified in the config dictionary. If debug is specified as True, output will be to stdout using the Tornado colored output if available and all other logging methods such as file or syslog will be disabled.

config dictionary format

directory:   Optional log file output directory
filename:    Optional filename, not needed for syslog
format:      Format for non-debug mode
level:       One of debug, error, warning, info
handler:     Optional handler
syslog:      If handler == syslog, parameters for syslog
    address:   Syslog address
    facility:  Syslog facility


Will call the stop() method of all child objects added to the tinman.utils.children list. This is useful for multi-processing apps to make sure that all children shutdown when a signal is called on the parent


Registers the shutdown function on SIGTERM and registers a rehash handler on SIGHUP. To specify the rehash handler, assign a callback to tinman.utils.rehash_handler.

Auto-Setup of Services

In order to facilitate a quick development process, the tinman application now has the concept of auto-setup and connect services. Initially, RabbitMQ is the only connectivity that is supported (via the Pika library). It is intended to add support for all major service types that have asynchronous support for the Tornado IO loop.


To setup an automatic connection to RabbitMQ simply include a RabbitMQ section in your configuration file:

    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual_host: /

When the application is constructed, it will connect to RabbitMQ and assign the connection and channel to a standard object called tinman which is an attribute of the application.

We construct a copy of a tinman specific object using the tinman.clients.rabbitmq.RabbitMQ class. Currently this is only setup to publish messages, though it is the intent to add the ability to consume messages asychronously as well. This object is accessed from a request handler as: self.application.tinman.rabbitmq

For publishing messages, only one command is required: RabbitMQ.publish_message

If you pass in a dictionary or list, the message will be auto-JSON encoded and the mimetype will be set as application/json.


  • exchange: RabbitMQ exchange to publish to
  • routing_key: RabbitMQ routing key to use in publishing message
  • message: The message itself to send
  • mimetype: The mimetype of the message (default: text/plain)
  • mandatory: AMQP Basic.Publish mandatory field
  • immediate: AMQP Basic.Publish immediate field






To setup an automatic connection to Redis siply include a Redis section in your configuration file:

    host: localhost
    port: 6379
    db: 0
    password: foo

When the application is constructed, it will connect to Redis and assign the connection and channel to a standard object called tinman which is an attribute of the application.

We construct a copy of a tinman specific object using the tinman.clients.redis.Redis class. This object is accessed from a request handler as self.application.tinman.redis

This class requires the asynchronous brukva client from


from tornado import web

class RedisTest(web.RequestHandler):

    def initialize(self):
        # Set a more handy redis handle
        self.redis = self.application.tinman.redis.client

    def get(self, key):

        # Make an asynchronous redis request
        self.redis.get(key, self.on_redis_response)

    def on_redis_response(self, response):
        """Since we're fully async here, when redis comes back with our response
        we'll process it in this function.

        # If we could not find the response code
        if not response:

        # Write the redis value out as a key/value pair in JSON
        self.write({key: response})

        # Done
Something went wrong with that request. Please try again.