Unit testing with PyUnit
For much greater detail, check out the Python UnitTest Documentation
Python's unittest module provides a framework for automated unit testing (based on the Java unit test framework).
In essence, you create a class for each of a collection of test sets, following the naming and inheritance conventions described in the code example below, and you can then automatically run all test cases from each of the test sets.
Here is a simple example:
#! /usr/bin/env python # ========================================================== # Set up paths and import all necessary components # # import the system module and python's unit testing module import sys, unittest # import the module to be tested from MyPythonDotpyFileToBeTested import * # set up a simple test class class TestSetOne(unittest.TestCase): def setUp(self): """Automatically called to set up each test case below""" # do whatever you want to set things up before these test cases print "setting up a test from set one" def tearDown(self): """Automatically called to clean up after each test case below""" # do whatever you want to clean things up print "cleaning up a test from set one" def testA(self): """Test case names MUST begin with the word test""" print "test A" def testB(self): """Test case ordering is alphabetic by method name""" print "test B" class TestSetTwo(unittest.TestCase): def setUp(self): """Automatically called to set up each test case below""" # do whatever you want to set things up before these test cases print "setting up a test from set two" def tearDown(self): """Automatically called to clean up after each test case below""" # do whatever you want to clean things up print "cleaning up a test from set two" def test2(self): """Test case names MUST begin with the word test""" print "test2" def test1(self): """Test case ordering is alphabetic by method name""" print "test1" # run all tests from all sets if __name__ == "__main__": unittest.main()
Python and MySQL
Method 1 (Hack)
If one doesn't have access to a Python interface for the database you want to use, you can use python's getoutput command to run a Unix/Linux command and capture the resulting output as a string.
For instance, we can use the popen command in the os module to run a linux/unix command, and store the results in a variable. We can then use the readline() command to step through these stored results one line of output at a time, e.g.:
import os results = os.popen("some command", "r", 100) nextline = results.readline() print nextline |
If we are interested in running a MySQL query, then our command might be built and executed something like
#! /usr/bin/env python import os executable = "/usr/local/mysql/bin/mysql" user = "wesselsd" password = "something clever" hostname = "localhost" sqlcommand = "\"show databases;\"" cmd = executable + " -u" + user + " -p" + password + " -e" + sqlcommand; result = os.popen(cmd, "r") for nextline in result.readlines(): print nextline |
Method 2 (Cleaner)
The standard method to access a MySQL database in a python script uses the MySQLdb module to establish a connection to the database, and then creates a cursor through which to access the database.
With that set up (see the example below) one can runn selects, inserts, etc using the cursor execute method.
When doing selects, we usually retrieve multiple rows, each with multiple columns
of data.
The collection of rows can be retrieved using the fetchall()
method,
and then accessed one at a time using a for-in loop, as illustrated below. Note that
each row will be an array of multiple strings (one per column).
When doing inserts, it is probably easiest to use the triple-double quoted strings approach to prevent our insertion string from being parsed by Python before it gets to the database. Again, see the example below.
import MySQLdb # connect to the db and obtain a cursor db = MySQLdb.connect(host="localhost", user="joe", passwd="secret", db="databasename") cursor = db.cursor() # example of running a select statement and parsing the results cursor.execute("SELECT * FROM *") result = cursor.fetchall() for record in result: # print the fields of the record print record[0],record[1], etc # example of running an insert statement cursor.execute("""INSERT INTO tablename (colname, colname) VALUES ("BLAH", "BLAH")""") |
Tkinter is a Python interface to the Tk GUI toolkit, and is a quick and effective way to put together user interfaces. Unfortunately, the current Python configurations on csciun1 don't support it, but if you want to experiment with it in the windows labs or at home then the following are good introductory tutorials:
For now simply import the whole thing, e.g.The basic process in creating GUI elements with this module is
A simple example is shown first:
# import the necessary modules from Tkinter import * # display a message in the python control console print "This is the control console, please watch the GUI instead!" # set up the root, or outermost window root = Tk() root.title("Hello World Window") # create the components (widgets) within the root # and set the placement of each within the loop # a clickable button firstbutton = Button(root, text = "Click me") firstbutton.grid() # a labelled data entry field firstlabel = Label(root, text="Userid:") firstlabel.grid() username = Entry(root, width=20) username.grid() # start the root window running root.mainloop() |
To do so, we have to revise our approach somewhat, and will derive our GUI classes from Tkinter's Frame class.
A simple class-based GUI is shown below:
# make sure we import the necessary GUI components from Tkinter import * # ========================================================== # win_Example class: The Central Example Window # # note this is inheriting from Tkinter's Frame class # class WinExample(Frame): # constructor for the main window def __init__(self, master=None): # call the Frame class constructor Frame.__init__(self, master) # call the createWidgets method # to add all the other parts of this window self.createWidgets() # method to add widgets to the main window def createWidgets(self): self.add_HelpButton() # method to add a help button def add_HelpButton(self): # create the button self.HelpButton = Button(self) # set the button's options self.HelpButton["text"] = "Help", # place the button within the window self.HelpButton.grid() # ========================================================== # Main Routine # app = WinExample() app.master.title("Example master title") app.mainloop() |
A more extensive class-based GUI is shown below, and will be discussed next week:
# ========================================================== # Set up paths and import all necessary components # # make sure we import the necessary GUI components from Tkinter import * # ========================================================== # win_Example class: The Central Example Window # # note this is inheriting from Tkinter's Frame class # class WinExample(Frame): # --------------------------------------- # Constructors # # constructor for the main window def __init__(self, master=None): # call the Frame class constructor Frame.__init__(self, master) # place the current window within its parent # and make it resizable self.grid(sticky=N+S+E+W) # call the createWidgets method # to add all the other parts of this window self.createWidgets() # --------------------------------------- # Widgets # # method to add widgets to the main example window def createWidgets(self): self.add_HelpButton() self.addTitles() self.add_ReportButton() self.add_LoadButton() self.add_SaveButton() # now make all the rows and columns resizable top = self.winfo_toplevel() top.rowconfigure(0,weight=1) top.columnconfigure(0,weight=1) self.columnconfigure(0,weight=1) self.columnconfigure(1,weight=1) self.columnconfigure(2,weight=1) self.rowconfigure(0,weight=1) self.rowconfigure(1,weight=1) self.rowconfigure(2,weight=1) self.rowconfigure(3,weight=1) self.rowconfigure(4,weight=1) # method to add a help button def add_HelpButton(self): # create the button self.HelpButton = Button(self) # set the button's options self.HelpButton["text"] = "Help", self.HelpButton["bg"] = "LightBlue", # bind pressing the button to the write_to_console method self.HelpButton["command"] = self.spawn_help_window # place the button within the window self.HelpButton.grid(row=1,column=0,sticky=N+S+E+W,padx=2,pady=2) # method to add a title label and a description label def addTitles(self): # create the title button self.TitleSection = Label(self) # set the label's options self.TitleSection["text"] = "Example", self.TitleSection["bg"] = "black", self.TitleSection["fg"] = "white", # bind keyclicks over the title to the about window self.TitleSection.bind(' |