Writing Scripts

There are 2 types of scripts you may need to write: Python and shell.

The reason for writing a script is usually for sake of automating some task, logic for which is either “not important enough” or perhaps is “too custom” to warrant adding it to the app proper. For instance app upgrade scripts are closely tied to the machine/environment on which the app is installed and so are kept outside of the app proper.

Which isn’t to say, by the way, that these scripts shouldn’t be tracked via source control. All scripts needed to manage the app should ideally be committed to a Git repo somewhere; see Deployment Layer for more on that.

As a rule, shell scripts are “simpler” but of course are limited to the commands defined by the app (and underlying shell). Python scripts bring maximum flexibility but can sometimes be overkill.

Python Scripts

A “complete” sample Python script is shown below. It may be more complex than you typically need, but hopefully not too bad; modify as you like.

(See also Ad Hoc Scripts for more simple examples.)

If you use Data Versioning then it is important to “postpone” most module imports, until the config has been fully created. (Even if you don’t use versioning it’s a good habit, in case you ever change your mind.) This is why, in the example below, the import from rattail.db happens within the main function, instead of at the top of the script.

This script is useful for such and such.

import argparse

from rattail.config import make_config

def do_something(config):

    # most imports should not happen until config is made
    from rattail.db.auth import administrator_role

    app = config.get_app()
    model = app.model

    # open db connection
    session = app.make_session()

    # not doing anything useful here, just an example
    admin = administrator_role(session)

    # do something else...for instance count the departments

    # must commit session to save any changes

if __name__ == '__main__':

    # here we define available command line args
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--config', metavar='PATH',
                        action='append', dest='config_paths')

    # here we determine what args caller specified
    args = parser.parse_args()

    # okay let's make that config, per command line
    config = make_config(args.config_paths)

    # if you'd rather skip command line parsing altogether,
    # you can instead do something like this:
    #config = make_config('/srv/envs/poser/app/quiet.conf')

    # and finally let's do something useful

Let’s say you name this script foo.py and put it in your app dir, so running it would look like:

cd /srv/envs/poser
bin/python3 app/foo.py --help

Shell Scripts