The Flask-Script extension provides support for writing external scripts in Flask. This includes running a development server, a customized Python shell, scripts to set up your database, cronjobs, and other command-line tasks that belong outside the web application itself.
Flask-Script works in a similar way to Flask itself. You define and add commands that can be called from the command line to a Manager instance:
# manage.py
from flaskext.script import Manager
from myapp import app
manager = Manager(app)
@manager.command
def hello():
print "hello"
if __name__ == "__main__":
manager.run()
Once you define your script commands, you can then run them on the command line:
python manage.py hello
> hello
Source code and issue tracking at Bitbucket.
Install with pip and easy_install:
pip install Flask-Script
or download the latest version from Bitbucket:
hg clone http://bitbucket.org/danjac/flask-script
cd flask-script
python setup.py develop
If you are using virtualenv, it is assumed that you are installing Flask-Script in the same virtualenv as your Flask application(s).
The first step is to create a Python module to run your script commands in. You can call it anything you like, for our examples we’ll call it manage.py.
You don’t have to place all your commands in the same file; for example, in a larger project with lots of commands you might want to split them into a number of files with related commands.
In your manage.py file you have to create a Manager instance. The Manager class keeps track of all the commands and handles how they are called from the command line:
from flaskext.script import Manager
app = Flask(__name__)
# configure your app
manager = Manager(app)
if __name__ == "__main__":
manager.run()
Calling manager.run() prepares your Manager instance to receive input from the command line.
The Manager requires a single argument, a Flask instance. This may also be a function or other callable that returns a Flask instance instead, if you want to use a factory pattern.
The next step is to create and add your commands. There are three methods for creating commands:
- subclassing the Command class
- using the @command decorator
- using the @option decorator
To take a very simple example, we want to create a Hello command that just prints out “hello world”. It doesn’t take any arguments so is very straightforward:
from flaskext.script import Command
class Hello(Command):
"prints hello world"
def run(self):
print "hello world"
Now the command needs to be added to our Manager instance, like the one created above:
manager.add_command('hello', Hello())
This of course needs to be called before manager.run. Now in our command line:
python manage.py hello
> hello world
You can also pass the Command instance in a dict to manager.run():
manager.run({'hello' : Hello()})
The Command class must define a run method. The positional and optional arguments depend on the command-line arguments you pass to the Command (see below).
To get a list of available commands and their descriptions, just run with no command:
python manage.py
To get help text for a particular command:
python manage.py runserver -h
This will print usage plus the docstring of the Command.
This first method is probably the most flexible, but it’s also the most verbose. For simpler commands you can use the @command decorator, which belongs to the Manager instance:
@manager.command
def hello():
"Just say hello"
print "hello"
Commands created this way are run in exactly the same way as those created with the Command class:
python manage.py hello
> hello
As with the Command class, the docstring you use for the function will appear when you run with the -h option:
python manage.py -h
> Just say hello
Finally, the @option decorator, again belonging to Manager can be used when you want more sophisticated control over your commands:
@manager.option('-n', '--name', help='Your name')
def hello(app, name):
print "hello", name
The @option decorator is explained in more detail below.
Most commands take a number of named or positional arguments that you pass in the command line.
Taking the above examples, rather than just print “hello world” we would like to be able to print some arbitrary name, like this:
python manage.py hello --name=Joe
hello Joe
or alternatively:
python manage.py hello -n Joe
To facilitate this you use the option_list attribute of the Command class:
from flaskext.script import Command, Manager, Option
class Hello(Command):
option_list = (
Option('--name', '-n', dest='name'),
)
def run(self, name):
print "hello %s" % name
Positional and optional arguments are stored as Option instances - see the API below for details.
Alternatively, you can define a get_options method for your Command class. This is useful if you want to be able to return options at runtime based on for example per-instance attributes:
class Hello(Command):
def __init__(self, default_name='Joe'):
self.default_name=default_name
def get_options(self):
return [
Option('-n', '--name', dest='name', default=self.default_name),
]
def run(self, name):
print "hello", name
If you are using the @command decorator, it’s much easier - the options are extracted automatically from your function arguments. This is an example of a positional argument:
@manager.command
def hello(name):
print "hello", name
You then invoke this on the command line like so:
> python manage.py hello Joe
hello joe
Or you can do optional arguments:
@manager.command
def hello(name="Fred")
print hello, name
These can be called like so:
> python manage.py hello --name=Joe
hello Joe
alternatively:
> python manage.py hello -n Joe
hello Joe
There are a couple of important points to note here.
The short-form -n is formed from the first letter of the argument, so “name” > “-n”. Therefore it’s a good idea that your optional argument variable names begin with different letters.
The second issue is that the -h switch always runs the help text for that command, so avoid arguments starting with the letter “h”.
Note also that if your optional argument is a boolean, for example:
@manage.command
def verify(verified=False):
"""
Checks if verified
"""
print "VERIFIED?", "YES" if verified else "NO"
You can just call it like this:
> python manage.py verify
VERIFIED? NO
> python manage.py verify -v
VERIFIED? YES
> python manage.py verify --verified
VERIFIED? YES
The @command decorator is fine for simple operations, but often you need the flexibility. For more sophisticated options it’s better to use the @option decorator:
@manager.option('-n', '--name', dest='name', default='joe')
def hello(name):
print "hello", name
You can add as many options as you want:
@manager.option('-n', '--name', dest='name', default='joe')
@manager.option('-u', '--url', dest='url', default=None)
def hello(name, url):
if url is None:
print "hello", name
else:
print "hello", name, "from", url
This can be called like so:
> python manage.py hello -n Joe -u reddit.com
hello Joe from reddit.com
or alternatively:
> python manage.py hello --name=Joe --url=reddit.com
hello Joe from reddit.com
Options can also be passed to the Manager instance. This is allows you to set up options that are passed to the application rather than a single command. For example, you might want to have a flag to set the configuration file for your application. Suppose you create your application with a factory function:
def create_app(config=None):
app = Flask(__name__)
if config is not None:
app.config.from_pyfile(config)
# configure your app...
return app
You want to be able to define the config argument on the command line - for example, if you have a command to set up your database, you most certainly want to use different configuration files for production and development.
In order to pass that config argument, use the add_option() method of your Manager instance. It takes the same arguments as Option:
manager.add_option('-c', '--config', dest='config', required=False)
As with any other Flask-Script configuration you can call this anywhere in your script module, but it must be called before your manager.run() call.
Suppose you have this command:
@manager.command
def hello(name):
uppercase = app.config.get('USE_UPPERCASE', False)
if uppercase:
name = name.upper()
print hello, name
You can now run the following:
> python manage.py hello joe -c dev.cfg
hello JOE
Assuming the USE_UPPERCASE setting is True in your dev.cfg file.
Notice also that the “config” option is not passed to the command. As the app is always the first argument to your command, you can access any application-specific configuration from that.
In order for manager options to work you must pass a factory function, rather than a Flask instance, to your Manager constructor.
Flask-Script comes with a set of helper functions for grabbing user input from the command line. For example:
from flaskext.script import Manager, prompt_bool
from myapp import app
from myapp.models import db
manager = Manager(app)
@manager.command
def dropdb():
if prompt_bool(
"Are you sure you want to lose all your data"):
db.drop_all()
It then runs like this:
python manage.py dropdb
> Are you sure you want to lose all your data ? [N]
See the API below for details on the various prompt functions.
Flask-Script has a couple of ready commands you can add and customize: Server and Shell.
The Server command runs the Flask development server. It takes an optional port argument (default 5000):
from flaskext.script import Server, Manager
from myapp import create_app
manager = Manager(create_app)
manager.add_command("runserver", Server())
if __name__ == "__main__":
manager.run()
and then run the command:
python manage.py runserver
The Server command has a number of command-line arguments - run python manage.py runserver -h for details on these. You can redfine the defaults in the constructor:
server = Server(host="0.0.0.0", port=9000)
Needless to say the development server is not intended for production use.
The Shell command starts a Python shell. You can pass in a make_context argument, which must be a callable returning a dict. By default, this is just a dict returning the your Flask application instance:
from flask import app
from flaskext.script import Shell, Manager
from myapp import app
from myapp import models
from myapp.models import db
def _make_context():
return dict(app=app, app, db=db, models=models)
manager = Manager(create_app)
manager.add_command("shell", Shell(make_context=_make_context))
This is handy if you want to include a bunch of defaults in your shell to save typing lots of import statements.
The Shell command will use IPython if it is installed, otherwise it defaults to the standard Python shell. You can disable this behaviour in two ways: by passing the use_ipython argument to the Shell constructor, or passing the flag --no-ipython in the command line:
shell = Shell(use_ipython=False)
There is also a shell decorator which you can use with a context function:
@manager.shell
def make_shell_context():
return dict(app=app, db=db, models=models)
This enables a shell command with the defaults enabled:
> python manage.py shell
The default commands shell and runserver are included by default, with the default options for these commands. If you wish to replace them with different commands simply override with add_command() or the decorators. If you pass with_default_commands=False to the Manager constructor these commands will not be loaded:
manager = Manager(app, with_default_commands=False)
The Manager runs the command inside a Flask test context. This means thathat you can access request-local proxies where appropriate, such as current_app, which may be used by extensions.
Controller class for handling a set of commands.
Typical usage:
class Print(Command):
def run(self, app):
print "hello"
app = Flask(__name__)
manager = Manager(app)
manager.add_command("print", Print())
if __name__ == "__main__":
manager.run()
On command line:
python manage.py print
> hello
Parameters: |
|
---|
Prepares manager to receive command line input. Usually run inside “if __name__ == “__main__” block in a Python script.
Parameters: |
|
---|
Adds an application-wide option. This is useful if you want to set variables applying to the application setup, rather than individual commands.
For this to work, the manager must be initialized with a factory function rather than an instance. Otherwise any options you set will be ignored.
The arguments are then passed to your function, e.g.:
def create_app(config=None):
app = Flask(__name__)
if config:
app.config.from_pyfile(config)
return app
manager = Manager(create_app)
manager.add_option("-c", "--config", dest="config", required=False)
> python manage.py -c dev.cfg mycommand
Any manager options passed in the command line will not be passed to the command.
Arguments for this function are the same as for the Option class.
Adds command to registry.
Parameters: |
|
---|
Adds a command function to the registry.
Parameters: |
|
---|
Decorator to add an option to a function. Automatically registers the function - do not use together with @command. You can add as many @option calls as you like, for example:
@option('-n', '--name', dest='name')
@option('-u', '--url', dest='url')
def hello(app, name, url):
print "hello", name, url
Takes the same arguments as the Option constructor.
Decorator that wraps function in shell command. This is equivalent to:
def _make_context(app):
return dict(app=app)
manager.add_command("shell", Shell(make_context=_make_context))
The decorated function should take a single “app” argument, and return a dict.
For more sophisticated usage use the Shell class.
Returns string consisting of all commands and their descriptions.
Prints result of get_usage()
Decorator to add an option to a function. Automatically registers the function - do not use together with @command. You can add as many @option calls as you like, for example:
@option('-n', '--name', dest='name')
@option('-u', '--url', dest='url')
def hello(app, name, url):
print "hello", name, url
Takes the same arguments as the Option constructor.
Base class for creating commands.
Runs a command. This must be implemented by the subclass. The first argument is always the app (Flask instance) followed by arguments as configured by the Command options.
By default, returns self.option_list.Override if you need to do instance-specific configuration.
Runs a Python shell inside Flask application context.
Parameters: |
|
---|
Runs the Flask development server i.e. app.run()
Parameters: |
|
---|
Stores positional and optional arguments for ArgumentParser.add_argument.
Parameters: |
|
---|
Grab user input from command line.
Parameters: |
|
---|
Grabs user input from command line and converts to boolean value.
Parameters: |
|
---|
Grabs hidden (password) input from command line.
Parameters: |
|
---|
Grabs user input from command line from set of provided choices.
Parameters: |
|
---|