Writing TurboGears Extensions

TurboGears provides a bunch of hook points and ways to extend the framework behavior to write extensions. Most of the needs can usually be satisfied by relying on tg.ApplicationConfigurator, Configuration Milestones and Hooks.

Creating an Extension

TurboGears extensions are identified by the tgext.* package name, since version 2.3.2 the devtools provide a command to quickly create a new TurboGears extension which can be both used by itself or plugged through tgext.pluggable.

To quickstart the extension run:

$ gearbox tgext -n myextension -a "My Name" -e "my@email.com"

This will create a tgext.myextension directory which a simple sample extension inside. To tune the author, description, license of your extension have a look at the tgext command options using gearbox help tgext.

Tuning on the Extension

If you created the tgext.myextension using the tgext command you can quickly turn it on by editing your application config/app_cfg.py and appending at the end the following lines:

import tgext.myextension
tgext.myextension.plugme(base_config)

of through the pluggable application interface if tgext.pluggable is available:

from tgext.pluggable import plug
plug(base_config, 'tgext.myextension')

By enabling the autogenerated extension and starting gearbox serve again, you will notice that it just provides a bunch of logging hooks and not much more:

17:52:30,019 INFO  [tgext.myextension] Setting up tgext.myextension extension...
17:52:30,023 INFO  [tgext.myextension] >>> Public files path is /home/USER/myapp/myapp/public
17:52:30,023 INFO  [tgext.myextension] + Application Running!
17:52:30,040 INFO  [gearbox] Starting server in PID 22484.
Starting HTTP server on http://0.0.0.0:8080
17:52:30,740 INFO  [tgext.myextension] Serving: /

The Sample Extension

The sample extension created by the tgext command provides its actual setup inside the __init__.py file. This file showcases some of the extension points provided by TurboGears.

If you actually created tgext.myextension you should get a tgext.myextension/tgext/myextension/__init__.py file with the following content:

from tg import config
from tg import hooks
from tg.configuration import milestones

import logging
log = logging.getLogger('tgext.myextension')


# This is the entry point of your extension, will be called
# both when the user plugs the extension manually or through tgext.pluggable
# What you write here has the same effect as writing it into app_cfg.py
# So it is possible to plug other extensions you depend on.
def plugme(configurator, options=None):
    if options is None:
        options = {}

    log.info('Setting up tgext.myextension extension...')
    milestones.config_ready.register(SetupExtension(configurator))

    return dict(appid='tgext.myextension')


# Most of your extension initialization should probably happen here,
# where it's granted that .ini configuration file has already been loaded
# in tg.config but you can still register hooks or other milestones.
class SetupExtension(object):
    def __init__(self, configurator):
        self.configurator = configurator

    def __call__(self):
        log.info('>>> Plugin files path is %s' % config['paths']['static_files'])
        hooks.register('startup', self.on_startup)

        def echo_wrapper_factory(handler, config):
            def echo_wrapper(controller, environ, context):
                log.info('Serving: %s' % context.request.path)
                return handler(controller, environ, context)
            return echo_wrapper

        # Application Wrappers are much like easier WSGI Middleware
        # that get a TurboGears context and return a Response object.
        self.configurator.register_application_wrapper(echo_wrapper_factory)

    def on_startup(self):
        log.info('+ Application Running!')

The core parts of the previous example are:

  • plugme function, this is the function used to turn on your extension.

    will be automatically called by tgext.pluggable when the extension is enabled using the pluggable application interface or by the user itself when manually enabling your extension. Inside this method the application configurator object is available and the options the user specified for the extension, but not application configuration as it has not been loaded yet.

  • SetupExtension.__call__, this is a callable that is registered

    by the plugme function for the config_read milestone so that it is executed when the .ini configuration has been loaded and merged with the options declared through the application configurator in config/app_cfg.py.

    Here you can register additional milestones, functions or access and modify the application configurator through the self.configurator object.

  • SetupExtension.on_startup This is a sample hook registered on

    application startup by SetupExtension.__call__ that says hello when the application has started. Have at look at Hooks for a complete list of available hooks.

Extensions with models and controllers

If your extension needs to expose models and controllers you probably want to have a look at Pluggable Applications which are meant to create reusable turbogears applications that can be plugged inside other applications to extend their features.

Pluggable Applications with TurboGears

TurboGears 2.1.4 introduced support for pluggable applications using tgext.pluggable. tgext.pluggable is now the official supported way in TurboGears to create pluggable reusable applications. Currently only SQLAlchemy based applications are supported as pluggable applications.

Official documentation for tgext.pluggable can be found at: http://pypi.python.org/pypi/tgext.pluggable

Supported Features

Pluggable applications can define their own:

  • controllers, which will be automatically mounted when the application is purged.
  • models, which will be available inside and outside of the plugged application.
  • helpers, which can be automatically exposed in h object in application template.
  • bootstrap, which will be executed when setup-app is called.
  • statics, which will be available at their own private path.

Mounting a pluggable application

In your application config/app_cfg.py import plug from tgext.pluggable and call it for each pluggable application you want to enable.

The plugged package must be installed in your environment.

from tgext.pluggable import plug
plug(base_config, 'package_name')

Creating Pluggable Applications

tgext.pluggable provides a quickstart-pluggable command to create a new pluggable applications:

$ gearbox quickstart-pluggable plugtest
...

The quickstarted application will provide an example on how to use models, helpers, bootstrap, controllers and statics.