Run python script in virtualenv from cron

9 April 2013

I’m using virtualenv and have some python scripts as part of a django project. The scripts need to be run by cron, but have to use the virtualenv.

There’s a few solutions around, but I went with this shell script which changes to the directory it’s in, activates the virtualenv and runs python for the given script with args.

The script looks like:

#!/bin/bash

# Runs python script within virtualenv
# used by cron

cd `dirname $0`
source env/bin/activate
python "${@:1}"

chmod it so it’s executable.

I run it from cron like:

/srv/www/myproject/runscript scripts/test.py arg1 arg2

The test.py script is at /srv/www/myproject/scripts/test.py – i.e. relative to the runscript script.

This is largely a note-to-self, but I hope it helps you, too.

Filed under: Python — Scott @ 5:46 pm

Multi-file find and replace for {% url “quoted” %} tag in Django 1.5

3 April 2013

Django 1.5 deprecates the old {% url %} tag style and uses the new one. The new one needs the url name to be quoted. So instead of {% url public_index %} it must be {% url "public_index" %}.

You’ll get an error:
‘url’ requires a non-empty first argument. The syntax changed in Django 1.5, see the docs.

Instead of adding quotes to each one in each template manually, I wanted a multi-file find and replace regex. Examples abound of using find with xargs and sed. But here’s a simple Python script and example usage to do just that.

Note that it updates the files in-place. Make sure you have a backup and/or they’re committed to version control just in case something goes wrong and messes up your templates. You’ve been warned.

Here’s a simple find and replace Python script:

import sys
import os
import re

def main(argv=None):
    if argv is None:
        argv = sys.argv

    if len(argv) < 4:
        print """
Usage:

%s find replace filename.txt [filename2.txt...]
""" % argv[0]
        exit

    find = argv[1]
    replace = argv[2]
    filepaths = argv[3:]

    for filepath in filepaths:
        text = open(filepath).read()
        #print re.sub(find, replace, text)
        new_text = re.sub(find, replace, text)
        if new_text != text:
            print filepath
            open(filepath, 'w').write(new_text)

if __name__ == '__main__':
    main()

I saved the file as replacer.py.

Here's how I called it:

find path/to/templates/ -name "*.html" | xargs python path/to/replacer.py '{% url ([\w_-]+) ' '{% url "\1" '

The find command finds all .html files in our templates directory. xargs passes the file names to our replacer script along with the find and replace patterns. We're putting quotes around the first parameter which is the url pattern name and leaving other parameters untouched.

This pattern assumes you've got a space between {% and url, which is the standard practice in django. If not, you can change the pattern.

Hope this helps.

Filed under: Django — Scott @ 1:18 pm