1.0 -> 1.0.1

No changes are necessary, however to take advantage of MarkupSafe’s faster HTML escaping, the default filter in environment.py that Mako is configured with should be changed from:

from webhelpers.html import escape
from markupsafe import escape

MarkupSafe utilizes a C extension where available for faster escaping which can help on larger pages with substantial variable substitutions.

0.9.7 -> 1.0

Upgrading your project is slightly different depending on which versions you’re upgrading from and to. It’s recommended that upgrades be done in minor revision steps, as deprecation warnings are added between revisions to help in the upgrade process.

For any project prior to 0.9.7, you should first follow the applicable docs to upgrade to 0.9.7 before proceeding.

To upgrade to 1.0, first upgrade your project to 0.10. This is a Pylons release that is fully backwards-compatible with 0.9.7. However under 0.10 a variety of warnings will be issued about the various things that need to be changed before upgrading to 1.0.


Since Pylons 0.10 is only out as a beta at this point, upgrade using the actual URL, for example:

$ easy_install -U http://pylonshq.com/download/0.10/Pylons-0.10.tar.gz

Beyond the warnings issued, you should also read the following list and ensure these changes have been applied.

Pylons changes from 0.9.7 to 1.0:

  • The config object created in environment.py is now passed around explicitly. There are also some other minor updates as follows.

    Update config/environment.py to initialize and return the config:

    # Add to the imports:
    from pylons.configuration import PylonsConfig
    # Add under 'def load_environment':
    config = PylonsConfig()
    # Replace the make_map / app globals line with
    config['routes.map'] = make_map(config)
    config['pylons.app_globals'] = app_globals.Globals(config)
    # Optionally, if removing the CacheMiddleware and using the
    # cache in the new 1.0 style, add under the previous lines:
    import pylons
    # Add at the end of the load_environment function:
    return config

    Update config/middleware.py to use the returned config:

    # modify the load_environment call:
    config = load_environment(global_conf, app_conf)
    # update the middleware calls
    # The Pylons WSGI app
    app = PylonsApp(config=config)
    # Routing/Session/Cache Middleware
    app = RoutesMiddleware(app, config['routes.map'])
    app = SessionMiddleware(app, config)
    # CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)
    # Add right before 'return app':
    app.config = config


    The CacheMiddleware is no longer setup by default through middleware, its now setup under app_globals inside its instantiation in lib/app_globals.py.

    Update config/routing.py to accept the config:

    # Replace the def line with
    def make_map(config):

    Update lib/app_globals.py to accept the config:

    # Replace the __init__ line with
    def __init__(self, config):
    # Optionally, if you decided to remove the CacheMiddleware
    # Add these imports
    from beaker.cache import CacheManager
    from beaker.util import parse_cache_config_options
    # and add this line in __init__:
    self.cache = CacheManager(**parse_cache_config_options(config))

    Update tests/__init__.py as needed:

    from unittest import TestCase
    from paste.deploy import loadapp
    from paste.script.appinstall import SetupCommand
    from pylons import url
    from routes.util import URLGenerator
    from webtest import TestApp
    import pylons.test
    __all__ = ['environ', 'url', 'TestController']
    # Invoke websetup with the current config file
    environ = {}
    class TestController(TestCase):
        def __init__(self, *args, **kwargs):
            wsgiapp = pylons.test.pylonsapp
            config = wsgiapp.config
            self.app = TestApp(wsgiapp)
            url._push_object(URLGenerator(config['routes.map'], environ))
            TestCase.__init__(self, *args, **kwargs)


    Change the use of url_for in your tests to use url, which is imported from tests/__init__.py in your unit tests.

    Finally, update websetup.py to avoid the duplicate app creation that previously could occur during the unit tests:

    # Add to the imports
    import pylons.test
    # Add under the 'def setup_app':
    # Don't reload the app if it was loaded under the testing environment
    if not pylons.test.pylonsapp:
        load_environment(conf.global_conf, conf.local_conf)
  • Change all instances of redirect_to(...) -> redirect(url(...))

    redirect_to processed arguments in a slightly ‘magical’ manner in that some of them went to the url_for while sometimes... not. redirect() issues a redirect and nothing more, so to generate a url, the url instance should be used (import: from pylons import url).

  • Ensure that all use of g is switched to using the new name, app_globals

  • Change all instances of url_for to url.

    Note that url does not retain the current route memory like url_for did by default. To get a route generated using the current route, call url.current.

    For example:

    # Rather than url_for() for the current route

    url can be imported from pylons.

  • Change config import statement if needed

    Previously, the config object could be imported as if it was a module:

    import pylons.config

    The config object is now an object in pylons/__init__.py so the import needs to be changed to:

    from pylons import config
  • Routes is now explicit by default

    This won’t affect those already using url as it ignores route memory. This change does mean that some routes which relied on a default controller of ‘content’ and a default action of ‘index’ will not work.

    To restore the old behavior, in config/routing.py, set the mapper to explicit:

    map.explicit = True
  • By default, the tmpl_context (a.k.a ‘c’), is no longer a AttribSafeContextObj. This means accessing attributes that don’t exist will raise an AttributeError.

    To use the attribute-safe tmpl_context, add this line to the config/environment.py:

    config['pylons.strict_tmpl_context'] = False