Time for action updating and deleting information

Updating the record for a Task is all about constructing the correct update query. update will alter any records that match the conditions in the where clause. It will change only those columns mentioned in its set clause so we start by constructing this set clause (highlighted).

Joining a list of parameters and interpolating it into an SQL query might be a bit overdone but if we later want to add an extra attribute, this would be very simple (and our SQL query string now fits on a single line, making it a lot easier to read and typeset).

Once we have executed the insert, we check the number of rows affected. This value is available as the rowcount attribute of the cursor object and should be 1 as we used the unique task_id to select the records. If it isn't 1, something strange has happened and we roll back the insert and raise an exception. If it went well, we commit our changes.

Chapter4/tasklistdb.py

def update(self,user):
	params= []
	params.append('description = ?')
	params.append('duedate = ?')
	params.append('completed = ?')
	sql = '''update task set %s where task_id = ? and user_id = ?'''
	sql = sql%(",".join(params))
	conn = self.taskdb.conn
	cursor = conn.cursor()
	cursor.execute(sql, (self.description,self.duedate,self.
completed,self.id,user))
	if cursor.rowcount != 1 :
		debug('updated',cursor.rowcount)
		debug(sql)
		conn.rollback()
		raise DatabaseError('update failed')
	conn.commit()

To delete a task with a given task ID, all we have to do is execute a delete query on the task table with an expression in the where clause that matches our task_id, just like we did for an update. We do check that our delete query affects a single record only (highlighted) and roll back otherwise. This shouldn't happen, but it is better to be safe than sorry.

def delete(self,user):
	sql = '''delete from task where task_id = ? and user_id = ?'''
	conn = self.taskdb.conn
	cursor = conn.cursor()
	cursor.execute(sql,(self.id,user))
	if cursor.rowcount != 1:
		conn.rollback()
		raise DatabaseError('no such task')
	conn.commit()

Testing

Developing software without testing it is a little bit like driving a car with your eyes closed: if the road is straight you might get surprisingly far, but chances are you will crash within a few seconds. Testing, in other words, is good.

It does take time, however, to test an application thoroughly, so it makes sense to automate the testing process as much as possible. If tests can be executed easily, it encourages developers to run these tests often. This is desirable when the implementation changes. It can also act as a sanity check just before a new release. So although writing serious tests may sometimes take about as long as writing the code itself, this is a solid investment, as it might prevent many unwelcome surprises if the code is changed or the environment in which the code is deployed is altered.

There are many aspects of an application that you might like to test, but not all lend themselves to automatic testing, like user interaction (although tools like Selenium can get you quite far. More information on this tool is available at http://seleniumhq.org/). However, other parts are quite simple to automate.

Python comes with a unittest module that simplifies the task of repeatedly testing small functional units of code. The idea of unit testing is to isolate small chunks of code and define its expected behavior by asserting any number of expectations. If one of those assertions fails, the test fails. (There is much more to unit testing than can be fully covered in this book. Here we cover just the bare minimum to get a taste of the possibilities and we cover a few examples that are intended to give you enough information to understand the test suites supplied with the example code for this book. If you would like to read more on unit testing in Python, a good starting point would be Python Testing by Daniel Arbuckle, Packt Publishing, 978-1-847198-84-6).

Python's unittest module contains a number of classes and functions that enable us to write and run groups of tests and their associated assertions. For example, say we have a module called factorial that defines a function fac() to calculate a factorial.

A factorial of a number n is the product of all numbers from 1 to n inclusive. For example, fac(4) = 4 * 3 * 2 * 1 = 24. Zero is an exceptional case as the factorial of 0 = 1. Factorials are only defined for integers >= 0, so we design our code to raise ValueError exceptions if the argument n is not an int or is negative (highlighted). The factorial itself is calculated recursively. If n is either zero or one, we return one, otherwise we return the factorial of n minus one times n:

Chapter4/factorial.py

def fac(n):
	if n < 0 : raise ValueError("argument is negative")
	if type(n) != int : raise ValueError("argument is not an integer")
	if n == 0 : return 1
	if n == 1 : return 1
	return n*fac(n-1)

The code is available as factorial.py.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.116.51