4.1. python-common

4.1.2. gmCfg.py

GNUmed configuration handling.

Two sources of configuration information are supported:

 - INI-style configuration files
 - database tables

Just import this module to have access to a default config file.

Theory of operation:

Upon importing this module a basic config file will be parsed. This
file is registered at the default source for configuration information.

The module will look for the config file in the following standard
places:

1) programmer supplied arguments
2) user supplied command line (getopt style):	--conf-file=<a file name>
4) ~/.<aDir>/<aName>.conf
5) ~/.<aName>.conf
6) /etc/<aDir>/<aName>.conf
7) /etc/<aName>.conf
8) ./<aName>.conf		- last resort for DOS/Win

<aDir> and <aName> will be derived automatically from the name of
the main script.

It is helpful to have a solid log target set up before importing this
module in your code. This way you will be able to see even those log
messages generated during module import.

Once your software has established database connectivity it can call
 activateDatabase()
to switch on database access for configuration options.

The default config data source is then switched to database access.

At any time can you force file or database access for a particular
configuration call via a parameter except before database access is
activated in which case the module will always use file access.

NOTE: DATABASE CONFIG DOES NOT WORK YET !

class cCfgBase:
	def __init__(self):
		pass

	def get(machine = None, user = None, cookie = None, option = None):
		pass

	def set(machine = None, user = None, cookie = None, option = None, value = None):
		pass

class cCfgFile:
    	Handle common INI-style config files.

	The INI file structure follows the common rules. Option values
	can be strings or lists of strings. Lists are handled transparently.
	The list format is as follows:

	listname = $listname$ # comment
	item 1
	item 2
	item 3
	$listname$

	Config data is cached in the following layout:

	self._cfg_data	= {dict}
	|
	|-> 'comment'	= [list of strings]
	`-> 'groups'	= {dict}
	 |
	 |-> group 1	= {dict}
	 | ...
	 `-> group n
	  |
	  |-> 'comment' = [list of strings]
	  `-> 'options'	= {dict}
	   |
	   |-> option 1	= {dict}
	   | ...
	   `-> option n
	    |
		|-> 'comment' [list of strings]
		`-> 'value'

	def __init__(self, aPath = None, aFile = None):

	def getCfg(self):
		Return handle to entire config dict.

	def get(self, aGroup = None, anOption = None):

	def getComment(self, aGroup = None, anOption = None):

	def set(self, aGroup = None, anOption = None, aValue = None, aComment = None):
		Set an option to an arbitrary type.
		This does not write the changed configuration to a file !

	def store(self):
		Store changed configuration in config file.
		# FIXME: actually we need to reread the config file here before writing

4.1.3. gmCachedAddress.py


 gmCachedAddress - data broker for a person's address
 @TODO: Almost everything

 class AddressCache(gmDBCache.DBcache)
 class CachedAddress(gmDBCache.CachedDBObject)
	def get(self, id=None, by_reference=0, refresh_only=0):
	def create_address_link( self, addressMap, db):
	def update_address_link(self, addressMap, db):
	def dictresult(self, id=None):

4.1.4. gmCachedDBObject.py

# gmCachedDBObject : abstraction and performance improvement for simple
#                     database query result objects
#
#
# CachedDBObject is a base class which should not
# be used directly.
# In order to derive a functional class from CachedDBObject, do as follows:
#
# class Derived(CachedDBObject):
#
#       #first, create the "shared buffer" variable
#	dbcache = DBcache()
#       #this static variable MUST have the name "dbcache"
#       #it must create an instance of DBcache or a subclass thereof
#
#       #then, create the appropriate constructor
#	def __init__(...)
#		#now create a reference to the static variable
#		self.cache = Derived.dbcache
#		#and pass it to the constructor
#		cachedDBObject.__init__( cache=self.cache...)
#               #__init__ MUST call the base class constructor
#
# When creating more than one instance from "Derived",
# the callback system should be used to ensure that any
# instance using the shared buffer gets notified of buffer changes:
#
# myInstance = Derived(...)
# myInstance.notify_me('identifier of myInstance', callback_function)
#
# where 'identifier of myInstance' is an arbitrary string and
# 'callback function' is a function of the prototype:
#
# function('identifier of callback triggering class', 'id')
#
# where 'id' typically would be the foreign key causing the
# current data set in the buffer
#

class DBcache:
	"prototype for a database object cache 'static' (singleton) information"

class CachedDBObject

	def reset(self)
		"force a re-query of buffer on next data access attempt"

	def setQueryStr(self, querystr)

	def getQueryStr(self)

	def setId(self, id, lazy=0)

	def getId(self)
		"get the ID of the current object"

	def get(self, id=None, by_reference=0, refresh_only=0):
		returns the buffer. If id is not None and not in cache,
		the backend will be queried.
		If by_reference is not zero, a copy of the buffer instead 
		of a reference to it will be returned.
		When using multiple threads to access the data,
		always use copies of the buffer!

	def notify_me(self, who, callback=None):
    		Register function 'callback' for caller 'who'

		If callback is None, the callback for caller 'who'
		will be removed (if exists)
		'callback' is a function that accepts two parameters:
		The first parameter is the identity of the registered
		caller ('who'), the second parameter is the buffer id.
		'callback' must not return anything

	def queue_notification(self, queue=1):
		simple helper mechanism to ensure only the most recent thread
		updates widgets on data change
		
	def notify(self):
		forces execution of all registered callback functions
		This function will be called whenever the buffer changes
		
	def attributes(self):
		returns row attributes ('field names')

	def pprint(self):
		"format buffer content in printable form"

	def dictresult(self):

4.1.5. gmDispatcher.py


     Provides global signal dispatching services.

class DispatcherError(exceptions.Exception)

class _Any:
    	# Helper class
	
Methods provided by gmDispatcher:

     def connect(receiver, signal=Any, sender=Any, weak=1)
	Connect receiver to sender for signal

	If sender is Any, receiver will receive signal from any sender.
	If signal is Any, receiver will receive any signal from sender.
	If sender is None, receiver will receive signal from anonymous.
	If signal is Any and sender is None, receiver will receive any 
	    signal from anonymous.
	If signal is Any and sender is Any, receiver will receive any 
	    signal from any sender.
	If weak is true, weak references will be used.

     def disconnect(receiver, signal=Any, sender=Any, weak=1)
	Disconnect receiver from sender for signal.

	Disconnecting is not required. The use of disconnect is the same as for
	connect, only in reverse. Think of it as undoing a previous connection.

     def disconnect(receiver, signal=Any, sender=Any, weak=1)
	Disconnect receiver from sender for signal.

	Disconnecting is not required. The use of disconnect is the same as for
	connect, only in reverse. Think of it as undoing a previous connection.

     def send(signal, sender=None, **kwds)
	Send signal from sender to all connected receivers.

	Return a list of tuple pairs [(receiver, response), ... ].
	If sender is None, signal is sent anonymously.

     def _call(receiver, **kwds)
	Call receiver with only arguments it can accept.

     def safeRef(object)
	Return a *safe* weak reference to a callable object.

class BoundMethodWeakref

    def __init__(self, boundMethod):
        Return a weak-reference-like instance for a bound method.

    def __repr__(self)
        Return the closest representation.

    def __call__(self)
        Return a strong reference to the bound method.

    def _removeReceiver(receiver)
    	Remove receiver from connections.

    def _cleanupConnections(senderkey, signal)
        Delete any empty signals for senderkey. Delete senderkey if empty.

    def _removeSender(senderkey)
    	Remove senderkey from connections.

4.1.6. gmExceptions.py

class ConnectionError(Exception)
	#raised whenever the database backend connection fails

class ConfigError(Exception)
	#raised whenever a configuration error occurs

class NoGuiError(Exception):
	#raised whenever the database backend connection fails

class PureVirtualFunction(Exception):
	#raised whenever the database

4.1.7. gmGuiBroker.py

GNUMed GUI element brokerage

This module provides wrappers for the equivalent of global
variables needed for a gnumed GUI client interface

class GuiBroker:
	Wrapper for global objects needed by GNUMmed GUI clients

	#This class wraps all global gui objects (variables)for a gnumed
	#application. The static (at application level)dictionary
	#__objects can be accessed through the method addobject
	#and getobject.
	#So, if you need to access the main window frame, you would
	#query an instance of GuiBroker for it.

	def addobject(self, widget, key=None):
		Add an object to the gnumed gui object dictionary"

		An object can be anything (class, variable, widget)
		The "key" is a key expression (number, text) that
		allows you to retrieve the object.
		Convention for keys is the widget or variable name
		as a text string
		If key is not passed as parameter, a unique serial
		number is allocated as key and returned

	def getobject(self, key):
		allows to retrieve a gnumed gui element; see addobject()
		regarding the key parameter

	def keylist(self):
		returns a list of all keys; see documentation for the
		dictionary data type

	def valuelist(self):
		returns a list of all values; see documentation for the
		dictionary data type

	def itemlist(self):
		returns a list of all key:value pairs;
		see documentation for the dictionary data type

	def __getitem__(self, key):
		Allows retrieving the value via value = instance[key]

	def __setitem__(self, key, object):
		Allows access in the style of instance[key]=value

4.1.8. gmI18N.py

GNUmed client internationalization/localization.

All i18n/l10n issues should be handled through this modules.

Theory of operation:

By importing this module a textdomain providing translations is
automatically installed. The translating method gettext.gettext()
is installed into the global (!) namespace as _(). Your own modules thus
need not do _anything_ (not even import gmI18N) to have _() available
to them for translating strings. You need to make sure, however, that
gmI18N is imported in your main module before any of the modules using
it. In order to resolve circular references involving modules that
absolutely _have_ to be imported before this module you can explicitely
import gmI18N into them at the very beginning.

The text domain (i.e. the name of the message catalog file) is derived
from the name of the main executing script unless explicitely given on
the command line like this:
 --text-domain=< your text domain >
This module searches for message catalog files in 3 main locations:
 - in standard POSIX places (/usr/share/locale/ ...)
 - below (one level above binary directory)/locale/

For DOS/Windows I don't know of standard places so only the last
option will work unless you have CygWin installed. I don't know a
thing about classic Mac behaviour. New Mac's are POSIX, of course.

The language you want to see is derived from the following locale
related environment variables (in this order):
 - LANGUAGE
 - LC_ALL
 - LC_MESSAGES
 - LANG

4.1.9. gmLog.py


GNUMed client log handling.

All error logging, user notification and otherwise unhandled 
exception handling should go through classes or functions of 
this module

Theory of operation:

A logger object is a unifying wrapper for an arbitrary number
of log targets. A log target may be a file, syslog, the console,
or an email address, or, in fact, any object derived from the
class cLogTarget. Log targets will only log messages with at least
their own message priority level (log level). Each log target
may have it's own log level.

There's also a dummy log target that just drops messages to the floor.

By importing gmLog into your code you'll immediately have
access to a default logger: gmDefLog. Initially, the logger has
a log file as it's default target. The name of the file is
automatically derived from the name of the main application.
The log file will be found in one of the following standard
locations:

1) given on the command line as "--log-file=< log file >"
2) ~/.< base_name >/< base_name > .log
3) /var/log/< base_name >/< base_name > .log
4) /var/log/< base_name > .log
5) /dir/of/binary/< base_name > .log	- mainly for DOS/Windows

where < base_name > is derived from the name
of the main application.

By importing gmLog and logging to the default log your modules
never need to worry about the real message destination or whether
at any given time there's a valid logger available. Your MAIN
module simply adds real log targets to the default logger and
all other modules will merrily and automagically start logging
there.

You can of course instantiate any number of additional loggers
that log to different targets alltogether if you want to keep
some messages separate from others.

Usage:
1.) if desired create an instance of cLogger
2.) create appropriate log targets and add them to the default logger or your 
    own (from step 1)
3.) call the cLogger.LogXXX() functions

# log levels:
# lPanic - try to log this before we die
# lErr   - some error occured, may be recoverable
# lWarn  - something should be done about this though it's not fatal
# lInfo  - user info like program flow
# lData  - raw data processed by program

# injudicious use of lData may lead to copious amounts of log output
# and has inherent security risks (may dump raw data including passwords,
# sensitive records, etc)


class cLogger:
	def __init__(self, aTarget=None):
		Open an instance of cLogger and initialize a target.
		in case there's no target given open a dummy target

	def close(self):
		Close this logger and cleanly shutdown any open targets.

	def AddTarget (self, aTarget):
		Add another log target.

		- targets must be objects derived from cLogTarget
		- ignores identical targets
		- the number of concurrent targets is potentially unlimited

	def RemoveTarget (self, anID):
		Remove a log target by it's ID.
		- clients have to track target ID's themselves if they want to
		  remove targets

	def Log(self, aLogLevel, aMsg, aRawnessFlag = lUncooked):
		Log a message.

		- for a list of log levels see top of file
		- messages above the currently active level of logging/verbosity
		  are dropped silently
		- if Rawness == lCooked non-printables < 32 (space) will be mapped to
		  their name in ASCII
		- FIXME: this should be a Unicode mapping

	def LogDelimiter (self):
		Write a horizontal delimiter to the log target.

	def LogException(self, aMsg, exception, fatal=1):
		Log an exception.
		'exception' is a tuple as returned by sys.exc_info()

	def SetAllLogLevels (self, aLogLevel = None):
		Set a certain log level on all targets.

private classes / methods:
class cLogTarget:
	Base class for actual log target implementations.
	- derive your targets from this class
	- offers lots of generic functionality

	def __init__(self, aLogLevel = lErr)
	def close(self)
	def getID (self)
	def SetLogLevel(self, aLogLevel)
	def writeMsg (self, aLogLevel, aMsg)
	def hasLogged (self)
	def writeDelimiter (self)
	def flush (self)

4.1.10. gmLoginInfo.py

# gmLoginInfo - a class to encapsulate Postgres login information

class LoginInfo:
	"a class to encapsulate Postgres login information"

	def __init__(self, user, passwd, host='localhost', port=5432, database='gnumed', options='', tty='', profile='default'):


	def SetInfo(self, user, passwd, host='localhost', port=5432, dbname='gnumed', opt='', tty='', profile='default'):


	def GetInfo(self):


	def GetInfoStr(self):

	    # doesn't hand out passwords 

	def GetPGDB_DSN(self):

    	    return dsn in colon delimited form as one string and host
	    
	def GetDBAPI_DSN(self):

    	    return dsn in colon delimited form as one string
	  
    	def SetUser(self, user):

	def GetUser(self):

	def SetPassword(self, passwd):

	def SetPassword(self, passwd):

	def GetPasswordHash(self):

	def SetDatabase(self, dbname):

	def GetDatabase(self):

	def SetHost(self, host):

	def SetHost(self, host):

	def SetPort(self, port):

	def GetPort(self):

	def SetOptions(self, opt):

	def GetOptions(self):

	def SetTTY(self, tty):

	def GetTTY(self):

	def GetTTY(self):

	def GetTTY(self):


	def Clear(self):

		"clears all connection information regarding user, password etc."


4.1.11. gmPG.py

# gmConnectionPool - Broker for Postgres distributed backend connections


as of 09.08.2002 tries to handle psycopg (Zope), PyPGSql and pgdb

class ConnectionPool:

	"maintains a static dictionary of available database connections

	def __init__(self, login=None):
		parameter login is of type gmLoginInfo.LoginInfo

	def GetConnection(self, service):

		"if a distributed service exists, return it - otherwise return the default server"


	def ReleaseConnection(self, service):

		"decrease reference counter of active connection"


	def GetAvailableServices(self):

		list all distributed services available on this system

		(according to configuration database)


	def Connected(self):


	def LogError(self, msg):

		"This function must be overridden by GUI applications"


#---------------------------------------------------
# database helper functions
#---------------------------------------------------
def cursorIndex(cursor):

	returns a dictionary of row atribute names and their row indices


def descriptionIndex(cursordescription):

	returns a dictionary of row atribute names and their row indices


def dictResult(cursor, fetched=None):

	"returns the all rows fetchable by the cursor as dictionary (attribute:value)"


def fieldNames(cursor):

	"returns the attribute names of the fetched rows in natural sequence as a list"

	
def listDatabases(service='default'):

	"list all accessible databases on the database backend of the specified service"


def listUserTables(service='default'):

	"list the tables except all system tables of the specified service"


def listSystemTables(service='default'):

	"list the system tables of the specified service"


def listSystemTables(service='default'):

	"list the system tables of the specified service"


def quickROQuery(query, service='default'):

	a quick read-only query that fetches all possible results at once

	returns the tuple containing the fetched rows and the cursor 'description' object


def getBackendName():


def prompted_input(prompt, default=None):


def inputTMLoginParams():

	text mode input request of database login parameters


def inputWXLoginParams():

	GUI (wx) mode input request of database login parameters.

	Returns gmLoginInfo.LoginInfo object


def inputLoginParams():

	"input request for database backend login parameters. Try GUI dialog if available"


4.1.12. gmPlugin.py


# gmPlugin - base classes for GNUMed's plugin architecture
class gmPlugin:
	base class for all gnumed plugins

	def provides ():
		Returns a list of services that the plugin provides

	def requires ():
		Requires a list of services that must be registered
		before this plugin is registered. The configuration
		tool must check these and make sure the load order
		satisfies the plugins' requirements

	def description ():
		Returns a brief description of the plugin.

	def name (self):

	def register(self):

	def unregister(self):

class wxBasePlugin (gmPlugin):
	
	
	base class for all plugins providing wxPython widgets.
	Plugins must have a class descending of this class in their file, which MUST HAVE THE SAME NAME AS THE FILE.
	The file must be in a directory which is loaded by LoadPluginSet (gui/ for the moment, others may be added for different plugin types)

	# NOTE: I anticipate that all plugins will in fact be derived
	# from this class. Without the brokers a plugin is useless (IH)

	def __init__(self, guibroker=None, callbackbroker=None, dbbroker=None, params=None):

	def GetIcon (self):
		Return icon representing page on the toolbar.
		This is the default behaviour. GetIconData should return
		pickled, compressed and escaped string with the icon data.

		If you want to change the behaviour (because you want to load
		plugin icons from overseas via a satellite link or something
		you need to override this function in your plugin (class).

		Using this standard code also allows us to only import cPickle
		and zlib here and not in each and every plugin module which
		should speed up plugin load time :-)

		# FIXME: load from config which plugin we want
		# which_icon is a cookie stored on the backend by a config manager,
		# it tells the plugin which icon to return data for,

	def GetIconData(self, anIconID = None):
		# FIXME: in overriding methods need to be very careful about the
		# type of the icon ID since if we read it back from the database we
		# may not know what type it was

	def GetWidget (self, parent):
		Return the widget to display

	def MenuInfo (self):
		Return tuple of (menuname, menuitem).
		menuname can be "tools", "view", "help", "file"

	def Raise (self):
		Raises this plugin to the top level if not visible.

	def Shown (self):
		Called whenever this module is shown onscreen.

class wxNotebookPlugin (wxBasePlugin):
	
	Base plugin for plugins which provide a 'big page'
	Either whole screen, or notebook if it exists
		
	def register (self):
		Register ourselves with the main notebook widget.

	def unregister (self):
		Remove ourselves.

	def Raise (self):
	def OnMenu (self, event):
	def GetNotebookNumber (self):
	def DoToolbar (self, tb, widget):
		
		sets up the toolbar for this widget.
		tb is the toolbar
		widget is the widget returned by GetWidget () for connecting events


class wxPatientPlugin (wxBasePlugin):
	
	A 'small page', sits inside the patient view, with the side visible

	def register (self)
	def OnTool (self, event):
	def Raise (self):
	def unregister (self):


def LoadPlugin (aPackage, plugin_name, guibroker = None, dbbroker = None):
	Loads a plugin from a package directory.

	- "set" specifies the subdirectory in which to find the plugin
	- this knows nothing of databases, all it does is load a named plugin

	There will be a general 'gui' directory for large GUI
	components: prescritions, etc., then several others for more
	specific types: export/import filters, crypto algorithms
	guibroker, dbbroker are broker objects provided
	defaults are the default set of plugins to be loaded

	FIXME: we should inform the user about failing plugins

def GetAllPlugins (set):
	
	Searches the directory for all plugins

def UnloadPlugin (set, name):
	
	Unloads the named plugin

4.1.13. gmdbf.py


This is a module for reading dbf files.

It has been modified thanks to suggestions and patches from Jeff Bauer
and Kevin Dahlhausen. Unfortunately I lost patches which fix
endianness problems, which were sent to me by someone, so that will
have to wait. I do not use this module much these days, but since it
seems to be in use "out there" I thought I would finally make an
update available. This version should be more portable. Also, rather
than printing an error message an exception is now raised when the dbf
file appears to be corrupt.

Usage: the following

import dbf
db = dbf.dbf('mydata.dbf')

creates a dbf object db associated with an existing dbf file
'mydata.dbf'.  The dbf file is opened by the constructor. If the file
is not there IOError is raised. If the file appears not to be a dbf
format file, TypeError is raised.

If you prefer to create a dbf object, but open the actual file later,
you can use the following:

import dbf
db = dbf.dbf('mydata.dbf', openit=0)

and then you can call

db.open()

to actually open the file. Note that the constructor, if called this
way, does not verify that the file is there, so the IOError exception
is raised by the call to open.

Once the dbf object is created and opened (implicitly or not), the
following are available:

-- db.fields  : returns a a list of tuples describing the fields
-- db.nrecs   : returns the number of records
-- db[n]      : returns a tuple containing record number n (0 <= n < nrecs)
-- db.status(): prints some essential data about the dbf file

So to list the first two fields of mydata.dbf, assuming they are string
fields, one might write:

import dbf
from string import strip
db=dbf.dbf('mydata.dbf')
for k in db:
    print "%s, %s" % (strip(k[1]), strip(k[2]))


Good luck!

class dbf:
	def __init__(self, fname, openit=1):
	def open(self):
	def _get(self, recno):
	def __getitem__(self, recno):
	def dictresult(self, recno):
	def status(self):
	def close(self):


4.1.14. gmSignals.py

# gmSignals.py

gmSignals - factory functions returning GnuMed internal signal strings. 
This helps to avoid that  simple typographic mistakes result in messages
not being dispatched. It would allow to do messenging house keeping as well.

def popup_notice():
	a notice of general interest has been received

def popup_alert():
	an important notice of general ineterest has been received
	
def patient_selected():
	the current active patient displayed by the client has been selected
	
def patient_modified():
	the current patients demographic data has been modified
	
def medication_modified():
	the current patient's medication has been modified
	
def waitingroom_added():
	a patient has been added to the waiting room
	
def waitingroom_incons():
	a patient has started his consultation with the doctor
	
def waitingroom_left():
	a aptient has left the waiting room, finished his consultation

4.1.15. gmDbObject.py

 gmDbObject : base class for generic database objects
              this base class should provide a higher level database API      
              to the client programmers, since it takes care of
              some error handling and handles the differences
              between read-only and read/write connections

class DBObject:
    High level DB-API based base class for all gnumed database objects

    def __init__(self, dbbroker, service='default', select_query=None):
	    dbbroker: database broker as in gmPG.py
	    service: name of the gnumed database service the data is based on
	    select_query: query that selects the rows associated with class instance

    def SetSelectQuery(self, query):
	    Definition of the query string used to select the row(s)
	    associated with this database object. Parameters (for example for
	    a 'where' clause are allowed in
	     'dictionary parameter style', that is as '%(dictionary key)s'
	    All parameters have to be passed as strings, but no quoting!!!


    def SetInsertQuery(self, query):
	    Definition of the query that would insert a row into this
	    database object. All parameters must
	    be set in 'dictionary parameter style', that is as '%(dictionary key)s'
	    All parameters have to be passed as strings, but no quoting!!!


    def SetUpdateQuery(self, query):
	    Definition of the query neccessary to update the associated row.
	    The string must have a '%(primarykey)s' parameter which is representing the 
	    primary key attribute of the row to update. All other parameters must
	    be set in 'dictionary parameter style', that is as '%(dictionary key)s'
	    All parameters have to be passed as strings, but no quoting!!!


    def SetDeleteQuery(self, query):
	    Definition of the query neccessary to delete the associated row.
	    The string must have a '%(primarykey)s' parameter which is representing the 
	    primary key attribute of the row to delete


    def LogError(self, msg, map):
	    Please replace with gnumed logging functins s.a.p.


    def Select(self, map=None, maxfetch=0, listonly=0):
	    Executes the select query and returns a list of
	    PgResultSets (see pyPgSQL documentation)
	    dictionary 'map' can be used for query parameters, for
	    example for a 'WHERE' clause.
	    'maxfetch' limits the number of rows returned
	    'listonly' can speed things up if a large number
	    of rows is expected as result by returning a simple list
	    of lists instead of a list of PgResultSets

    def Insert(self, map):
	    insert a row with attributes as listed in the dictionary 'map'.
	    Returns the OID is succesful, otherwise returns 'None'


    def Update(self, map):
	    update a row with attributes as listed in the dictionary "map".
	    'map' dictionary  MUST contain the key 'primarykey' with the
	    value set to the primay key of the row to be updated
	    Returns 'None' if failed, the primary key if success 


    def Delete(self, map):
	    deletes a row as determined by the delete query string.
	    'map' dictionary  MUST contain the key 'primarykey' with the
	    value set to the primay key of the row to be deleted
	    Returns 'None' if failed, the primary key if success