[Tutor] data structure question

Alexander alejck at gmail.com
Tue Jan 29 00:31:14 CET 2008


Thanks for all the responses. I'm using this both as an opportunity to
learn and to create something that does exactly what I want it to so
that's why I want to write my own program.

I decided to go with a flat list in the end. Now I have a working
implementation but it's not as nice as I think it could be. This is
what I need:

Each task has a set of attributes. Some of these attribute values have
an internal and an external value or representation (for example the
attribute deadline, which is a datetime internally and a formatted
string externally).

The list of tasks should be sortable, filterable, and searchable on
any of the attributes. This needs to be done on the internal
attributes. The list of tasks should also be easily displayed with the
attributes as formatted strings.

My attempt is pasted below. My question now is whether this is a
tenable implementation, what's wrong with it if not, and at which
point something like this is better done using a relational backend
with SQL. To me it seems like the operations that I want to be able to
do are more easily implemented in SQL (perhaps because I don't know
enough python...) but what are the drawbacks of such an approach?

The code:

#! /usr/bin/python
# vim: tabstop=4 expandtab shiftwidth=4
"""Flat implementation of tasklist."""

import cPickle as pickle
import datetime
import parsedatetime.parsedatetime

import pdb

class TaskList(object):
	defaults = ['rgtd','backend','testing 1','tomorrow',1,'open']
	def __init__(self):
		"""Create an empty instance"""
		self.tasks = []
		self.modified = False

	def addTask(self,args):
		"""Add a task."""
		args = args + self.defaults[len(args):]
		task = Task(args)
		self.tasks.append(task)
		self.modified = True
	
	def clear(self):
		"""Delete all tasks."""
		self.tasks = []
		self.modified = True
	
	def removeTask(self,index):
		try:
			task = self.tasks.pop(index)
			self.modified = True
			result = 'Removed task %i\t%s'  (index,task.__str__())
		except:
			result = 'Removing task %i failed.' % index
		return result

	def setStatus(self,index,status):
		self.tasks[int(index)].status = str(status)
		self.modified=True

	def save(self, filename='.rgtddb'):
		"""Save tasklist to file using pickle."""
		file = open(filename,'wb')
		pickle.dump(self,file)
		file.close()
		self.modified = False

	def sorted(self,field='int_deadline',ascending=False):
		"""Return tasks sorted on int_deadline.
		Adapted from Python Cookbook 2ed Recipe 5.3.
		"""
		intermed = [ (getattr(x, field), i, x) for i, x in enumerate(self.tasks) ]
		intermed.sort(reverse=ascending)
		return [x[-1] for x in intermed]
	
	def sort(self,field='int_deadline',ascending=False):
		self.tasks[:] = self.sorted(field,ascending)

	def output(self,displaymask=False):
		row = ''
		
		# Set displaymask to all fields in sortorder if no mask is supplied.
		if not displaymask:
			displaymask = ['status','deadline','cost','project','area','task']
		
		# Sort tasks
		self.sort()

		# Produce output string
		for index, task in enumerate(self.tasks):
			row = row + '%i\t%s\n' % (index, '\t'.join([getattr(task,field)for
field in displaymask]))
		return row

class Task(object):
	def __init__(self,args):
		"""Set all task attributes from an argument list in correct order."""
		self.project = args[0]
		self.area = args[1]
		self.task = args[2]
		self.deadline = args[3]
		self.cost = args[4]
		self.status = args[5]
	
	def setDeadline(self, value):
		"""Use parsedatetime.parsedatetime to parse human-readable
		deadline entry to a datetime object.
		"""
		parsedatetime.parsedatetime._debug=False
		calendar = parsedatetime.parsedatetime.Calendar()
		self.__deadline = datetime.datetime(*calendar.parse(value)[0][0:7])
		# datetime object is also stored in for internal use (sorting)
		self.int_deadline = datetime.datetime(*calendar.parse(value)[0][0:7])

	def getDeadline(self):
		"""Return deadline as a string in the format day-month."""
		return self.__deadline.strftime('%d-%m %H')

	def setCost(self,value):
		"""Set cost to a timedelta object."""
		self.__cost = datetime.timedelta(hours=int(value))
		# datetime object is also stored for internal use (sorting)
		self.int_cost = datetime.timedelta(hours=int(value))	
	
	def getCost(self):
		"""Return a cost as a formatted string.
		Adapted from http://www.nabble.com/Formatting-timedelta-objects-td14259934.html
		"""
		hours = self.__cost.seconds // 3600
		#minutes = (self.__cost.seconds % 3600) // 60
		return '%sh' % (hours)

	
 	# Task properties that use overloading for setting and getting.
	deadline = property(getDeadline,setDeadline)
	cost = property(getCost,setCost)

#############################
# Methods that have not been
# encapsulated in TaskList.
#############################

def load(filename=False):
	"""Load tasklist from disk using pickle."""
	if not filename:
		filename = '.rgtddb'
	ts = False
	try:
		ts = pickle.load(open(filename,'rb'))
		ts.modified = False
	except IOError:
		print 'The file %s does not exist.' % filename
	return ts

Best,

Alexander


On 1/18/08, Alan Gauld <alan.gauld at btinternet.com> wrote:
>
> "Tiger12506" <keridee at jayco.net> wrote in message
> news:000601c85a1e$0dbedcb0$81fde004 at jslaptop...
> >>    def recursive_print(self, level=0):
> >>        print "\t"*level + self.cargo
> >>        for x in self.children:
> >>          recursive_print(x,level+1)
> >
> > Whoops. should be
> >
> > for x in self.children:
> >    x.recursive_print(level+1)
>
> Ah, you already caught it, my gmane feed ruinning a bit slow...
>
> Alan G
>
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> http://mail.python.org/mailman/listinfo/tutor
>


More information about the Tutor mailing list