memento

WSGI middleware for per request code reloading.

About

This distribution provides code reloading middleware for use with your WSGI applications. Two implementations are included. One is inspired by the RollBackImporter used by Steve Purcell in PyUnit. The other reloads a list of packages you supply (minus a list of exceptions).

Download

Download the latest release from memento's Cheese Shop Page.

Blessed are the cheesemakers!

Example

A complete script to run your app via wsgiref with code reloading might look like this:


from wsgiref.simple_server import make_server
import memento

# Mori doesn't always play well with others
# so we will use Assassin
#app = memento.Mori("mypackage.mymodule:my_app")
app = memento.Assassin("mypackage.mymodule:my_app", ["mypackage"])

try:
    server = make_server('localhost', 9999, app)
    server.serve_forever()
except KeyboardInterrupt, ki:
    print "See ya!"

Use this in combination with setuptools' development mode and you will not have to restart your server between edits to see your changes take effect.

memento.Assassin

You may notice that instantiating the Assassin class is a little different than many other WSGI middlewares. Instead of passing it a WSGI app directly, we pass it a resolver statement. (A description of resolver statements can be found in the resolver documentation.) This tells your instance how to import your app.

When instantiating Assassin two arguments are required: the resolver statement mentioned above, and a list of absolute package or module names to be reloaded. An optional keyword arg called exceptions lists the names within those packages to not reload. A final optional keyword argument, turn_on sets the reloading mode to on or off (defaults to turn_on=True).

Assassin was created as a simpler and safer replacement for Mori. Assassin only makes the interpreter forget previous imports based on a given list of names while Mori is much more brutal.

memento.Mori

Mori does not play well with others and will be deprecated in the next version if I cannot correct this.

Mori's __init__ method takes a resolver statement (as mentioned above) optional boolean keyword argument called turn_on which specifies whether to start watching imports right away. Once it is on, the instance keeps track of everything that is imported. Anything that was not imported before this point is forgotten each time the _reload() method is called, which happens each time a request is processed. These forgotten imports will then be reloaded by the interpreter as a matter of course. There are also turn_on() and turn_off() methods to turn code reloading on and off.

Order of Operations

Since only modules that had not already been imported will be reloaded, it is important to pay attention to when you turn reloading on. If things are not being reloaded the way you expect, try logging what is in Mori.previous_modules, Mori.new_modules and sys.modules.keys() to see what is going on.

Why Resolver Statements?

Resolving a resolver statement triggers an import that results in the reloading of relevant packages or modules for which caching has been circumvented.

Questions, comments, suggestions, bugs... :