tags:

views:

173

answers:

3

I am working on a Python project that includes a lot of simple example scripts to help new users get used to the system. As well as the source code for each example, I include the output I get on my test machine so users know what to expect when all goes well.

It occured to me that I could use this as a crude form of unit testing. Automatically run all the example scripts and do a load of diffs against the expected output.

All of my example scripts end with extension .py so I can get their filenames easily enough with something like

pythonfiles=[filename for filename in os.listdir(source_directory) if filename[-3:]=='.py']

So, pythonfiles contains something like ['example1.py', 'cool_example.py'] and so on.

What syntax can I use to actually run the scripts referenced in this list?

+4  A: 

You want to use the subprocess module.

Shane C. Mason
+8  A: 

You could leverage doctest to help you get this done. Write a method that executes each script, and in the docstring for each method you paste the expected output:

def run_example1():
    """
    This is example number 1. Running it should give you the following output:

    >>> run_example1()
    "This is the output from example1.py"
    """

    os.system('python example1.py') # or you could use subprocess here

if __name__ == "__main__":
    import doctest
    doctest.testmod()

Note I haven't tested this.

Alternatively, as Shane mentioned, you could use subprocess. Something like this will work:

import subprocess

cmd = ('example1.py', 'any', 'more', 'arguments')

expected_out = """Your expected output of the script"""

exampleP = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = exampleP.communicate() # out and err are stdout and stderr, respectively

if out != expected_out:
    print "Output does not match"
Mike Mazur
+1 doctest is a joy!
TokenMacGuy
+2  A: 

If they are similarly structured (All are executed with a run function for example), you can import the them as python scripts, and call thier run function.

import sys
import os
import imp

pythonfiles = [filename for filename in os.listdir(source_directory) if filename[-3:]=='.py']
for py_file in pythonfiles:
    mod_name = os.path.splitext(py_file)[0]
    py_filepath = os.path.join(source_directory, py_file)
    py_mod = imp.load_source(mod_name, py_filepath)
    if hasattr(py_mod, "run"):
        py_mod.run()
    else:
         print '%s has no "run"' % (py_filepath)
monkut
Note that this is faster than subprocess (though the difference is probably insignificant unless you're using Windows, and might not matter anyway if you don't have many scripts to run). However, this won't reset global variables between calls, which the subprocess solution will. I'm upvoting both as they both have uses.
user9876