[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
gnue/gnue-common/gnue/common GClientApp.py GCon...
From: |
Jason Cater |
Subject: |
gnue/gnue-common/gnue/common GClientApp.py GCon... |
Date: |
Tue, 15 May 2001 08:16:38 -0700 |
CVSROOT: /home/cvs
Module name: gnue
Changes by: Jason Cater <address@hidden> 01/05/15 08:16:38
Modified files:
gnue-common/gnue/common: GClientApp.py GConnections.py
GDataObjects.py GLoginHandler.py
Log message:
Umm, I wouldn't know where to begin. -- a lot of stuff?
CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-common/gnue/common/GClientApp.py.diff?cvsroot=OldCVS&tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-common/gnue/common/GConnections.py.diff?cvsroot=OldCVS&tr1=1.2&tr2=1.3&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-common/gnue/common/GDataObjects.py.diff?cvsroot=OldCVS&tr1=1.3&tr2=1.4&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-common/gnue/common/GLoginHandler.py.diff?cvsroot=OldCVS&tr1=1.1&tr2=1.2&r1=text&r2=text
Patches:
Index: gnue/gnue-common/gnue/common/GClientApp.py
diff -u gnue/gnue-common/gnue/common/GClientApp.py:1.4
gnue/gnue-common/gnue/common/GClientApp.py:1.5
--- gnue/gnue-common/gnue/common/GClientApp.py:1.4 Fri May 11 18:42:55 2001
+++ gnue/gnue-common/gnue/common/GClientApp.py Tue May 15 08:16:38 2001
@@ -250,6 +250,14 @@
print "\nFor help, type:\n %s --help\n" % (sys.argv[0])
sys.exit()
+ #
+ # Set the login handler for this session
+ #
+ def setLoginHandler(self, loginHandler):
+ if self.connections:
+ self.connections.loginHandler = loginHandler
+
+
#
# Used when profiling
#
Index: gnue/gnue-common/gnue/common/GConnections.py
diff -u gnue/gnue-common/gnue/common/GConnections.py:1.2
gnue/gnue-common/gnue/common/GConnections.py:1.3
--- gnue/gnue-common/gnue/common/GConnections.py:1.2 Fri May 11 18:42:55 2001
+++ gnue/gnue-common/gnue/common/GConnections.py Tue May 15 08:16:38 2001
@@ -22,7 +22,8 @@
# GConnections.py
#
# DESCRIPTION:
-# Class that loads connection definition files.
+# Class that loads connection definition files and maintains
+# database connections.
#
# NOTES:
#
@@ -33,17 +34,28 @@
import os
import os.path
import urllib
+import string
import GDebug
+import GDataObjects
+import GLoginHandler
+
class NotFoundError (Error):
+ # Raised if a requested connection name does not
+ # exist in the Connections Definition File.
pass
class InvalidFormatError (Error):
+ # Raised if the Connections Definition File is
+ # in an unreadable format.
pass
+
class GConnections:
- def __init__(self, location):
+ def __init__(self, location, loginHandler=None):
+
+ self._loginHandler = loginHandler
#
# This is an ugly hack to make the Python 1.5.2 ConfigParser
@@ -52,11 +64,12 @@
#
if (not ConfigParser.__dict__.has_key('readfp') and
ConfigParser.__dict__.has_key('_ConfigParser__read')):
- GDebug.printMesg(1,'[GConnections] Subclassing ConfigParser to support
URL''s :(')
- self.parser = _ConfigParser()
+ GDebug.printMesg(1,'Subclassing ConfigParser to support URL''s')
+ self._parser = _ConfigParser()
else:
- self.parser = ConfigParser()
+ self._parser = ConfigParser()
+ GDebug.printMesg(1,'Conn File: "%s"' % location)
drive = os.path.splitdrive(location)
if len(drive[0]):
fileHandle = open(location,'r')
@@ -64,7 +77,7 @@
fileHandle = urllib.urlopen(location)
try:
- self.parser.readfp(fileHandle)
+ self._parser.readfp(fileHandle)
except DuplicateSectionError:
raise InvalidFormatError, 'The file has duplicate source definitions.'
except MissingSectionError:
@@ -72,13 +85,21 @@
except:
raise InvalidFormatError, 'The file cannot be parsed.'
- def hasConnection(self, connection_name):
- return self.parser.has_section(connection_name)
+ self._openConnections = {}
+
+
+ def setLoginHandler(self, loginHandler):
+ self._loginHandler = loginHandler
+
- def get(self, connection_name, attribute, default=None):
- if self.parser.has_section(connection_name):
+ def hasConnectionParameters(self, connection_name):
+ return self._parser.has_section(connection_name)
+
+
+ def getConnectionParameter(self, connection_name, attribute, default=None):
+ if self._parser.has_section(connection_name):
try:
- return self.parser.get(connection_name, attribute)
+ return self._parser.get(connection_name, attribute)
except:
return default
else:
@@ -88,28 +109,95 @@
# Returns an dictionary of dictionaries describing all connections:
# {connection name: {att name: value}}
#
- def getConnections(self):
+ def getAllConnectionParameters(self):
rv = {}
- for section in self.parser.sections():
+ for section in self._parser.sections():
rv[section]={}
- for att in self.parser.options(section):
- rv[section][att] = self.parser.get(section, att)
+ for att in self._parser.options(section):
+ rv[section][att] = self._parser.get(section, att)
return rv
#
# Returns a dictionary describing a connection:
# {att name: value}
#
- def getConnection(self, connection_name):
+ def getConnectionParameters(self, connection_name):
rv = {}
- if self.parser.has_section(connection_name):
- for att in self.parser.options(connection_name):
- rv[att] = self.parser.get(connection_name, att)
+ if self._parser.has_section(connection_name):
+ for att in self._parser.options(connection_name):
+ rv[att] = self._parser.get(connection_name, att)
else:
raise NotFoundError
return rv
+
+ #
+ # Return a database provider object
+ #
+ def getDataObject(self, connection_name, connection_type):
+ # This will throw a GConnections.NotFoundError if an unknown
+ # connection name is specified. The calling method should
+ # catch this exception and handle it properly (exit w/message)
+ return _load_dbdriver(self.getConnectionParameter(connection_name, \
+ 'provider'), connection_type, self)
+
+
+ #
+ # Get a data connection for a specified database
+ #
+ def setDataConnection(self, dataSource):
+ connection_name = dataSource.database
+ dataObject = dataSource.getDataObject()
+ if self._openConnections.has_key(string.lower(connection_name)):
+
+ # If a database connetion has already been established, use it
+ dataSource.getDataObject().setDataConnection(self._openConnections[ \
+ string.lower(connection_name)])
+ GDebug.printMesg(5,'Reusing data connection to %s' % connection_name)
+
+ else:
+ attempts = 4
+
+ GDebug.printMesg(5,'Getting new data connection to %s' % connection_name)
+
+ while attempts:
+
+ try:
+ # Ask the UI to prompt for our login data
+ loginData = self._loginHandler.getLogin(
+ [connection_name,
self.getConnectionParameter(connection_name,'comment',''),
+ dataSource.getDataObject().getLoginFields()])
+
+ # Add the parameters from the Connections Definition File
+ loginData.update(self.getConnectionParameters(connection_name))
+
+ # Ask the data object to connect to the database
+ dataSource.getDataObject().connect(loginData)
+
+ # Save the newly opened connection for future datasources
+ self._openConnections[string.lower(connection_name)] = \
+ dataSource.getDataObject().getDataConnection()
+
+ # We're done!
+ attempts = 0
+
+ except GDataObjects.LoginError, error:
+ # Oops, they must have entered an invalid user/password.
+ # Those silly users.
+ attempts = attempts - 1
+
+ if not attempts:
+ # Four times is plenty...
+ raise GDataObjects.LoginError, error
+
+ except GLoginHandler.UserCanceledLogin:
+ # Guess they changed their minds. Treat as a login error.
+ raise GDataObjects.LoginError, "User canceled the login request"
+
+
+
+
#
# This is an ugly hack to make the Python 1.5.2 ConfigParser
# support reading its data from a file handle. Later versions
@@ -118,4 +206,33 @@
class _ConfigParser(ConfigParser):
def readfp (self, fp):
self.__read(fp)
+
+
+
+
+#
+# Load the correct DBdriver from gnue/common/dbdrivers/*/
+#
+def _load_dbdriver(driver, type, connectionManager):
+
+ if sys.platform == 'win32':
+ os.putenv('PYTHONCASEOK','1')
+
+ dbdriver = __import__("dbdrivers/%s/DBdriver" % (driver))
+ try:
+ dbdriver = __import__("dbdrivers/%s/DBdriver" % (driver))
+ except:
+ raise GDataObjects.ProviderNotSupportedError, \
+ "No drivers found for provider '%s'" % driver
+
+ try:
+ dd = dbdriver.supportedDataObjects[type]()
+ GDebug.printMesg (1,'Attaching to %s (%s)' %
(driver,dd.__class__.__name__))
+ return dd
+ except KeyError:
+ raise GDataObjects.ObjectTypeNotAvailableError, \
+ "DB Driver '%s' does not support source type '%s'" % (driver, type)
+
+
+
Index: gnue/gnue-common/gnue/common/GDataObjects.py
diff -u gnue/gnue-common/gnue/common/GDataObjects.py:1.3
gnue/gnue-common/gnue/common/GDataObjects.py:1.4
--- gnue/gnue-common/gnue/common/GDataObjects.py:1.3 Fri May 11 14:59:04 2001
+++ gnue/gnue-common/gnue/common/GDataObjects.py Tue May 15 08:16:38 2001
@@ -31,36 +31,68 @@
import GDebug
from string import lower
-import exceptions
-class DataObjectError(StandardError):
+class LoginError(Exception):
+ # Raised when invalid login user/pass was provided
+ # Client should attempt to get better information and
+ # try again
pass
-class ReadOnlyError(DataObjectError):
+class ConnectError(Exception):
+ # Raised when connection data is invalid (e.g., host not found, etc).
+ # Client should probably not attempt to relogin. Exit gracefully
+ # with a reason.
+ pass
+
+class ProviderNotSupportedError(Exception):
+ # Raised when a datasource type is requested that the dbdriver
+ # does not support (e.g., not all dbdrivers support raw sql mode.)
+ pass
+
+class ObjectTypeNotAvailableError(Exception):
+ # Raised when a datasource type is requested that the dbdriver
+ # does not support (e.g., not all dbdrivers support raw sql mode.)
+ pass
+
+class ReadOnlyError(Exception):
+ # Raised when an attempt is made to update a read-only data object.
pass
+
+
###########################################################
#
#
#
###########################################################
-class DataSource:
+class DataObject:
def __init__(self):
- self._detailSources = []
+ self._detailObjects = []
self._dataConnection = None
self._resultSetClass = ResultSet
def createResultSet(self, conditions={}, readOnly=0):
pass
- def addDetailDataSource(self, ds):
- GDebug.printMesg (1,"DataSource: adding a master/detail relationship")
- self._detailSources.append (ds)
+ def addDetailDataObject(self, ds):
+ GDebug.printMesg (1,"DataObject: adding a master/detail relationship")
+ self._detailObjects.append (ds)
+
+ # Return a list of necessary login fields (e.g., user/pass).
+ # Each list item is another list of ["field label", isPassword?]
+ def getLoginFields(self):
+ return []
def connect(self, connectData={}):
pass
+ def setDataConnection(self, connection):
+ self._dataConnection = connection
+
+ def getDataConnection(self):
+ return self._dataConnection
+
def commit(self):
pass
@@ -83,6 +115,7 @@
self._defaultValues = defaultValues
self._masterRecordSet = masterRecordSet
self._readonly = 0
+ self._boundFields = {}
self.current = None
@@ -167,7 +200,7 @@
return 1
- # Returns 1=DataSource has uncommitted changes
+ # Returns 1=DataObject has uncommitted changes
def isPending(self):
isPending = 0
for rec in (self._cachedRecords):
@@ -190,9 +223,14 @@
#
- def notifyDetailSources(self):
+ def notifyDetailObjects(self):
pass
-
+
+
+ # Returns 1=Field is bound to a database field
+ def isFieldBound(self, fieldName):
+ return self._boundFields.has_key(lower(fieldName))
+
###
### Methods below should be overridden by Vendor Specific functions
@@ -217,7 +255,7 @@
class RecordSet:
def __init__(self, parent, initialData={}, dbIdentifier=None,
defaultData={}):
- self._detailSources = []
+ self._detailObjects = []
self._dbIdentifier = dbIdentifier
self._deleteFlag = 0
self._updateFlag = 0
@@ -283,14 +321,14 @@
def setField(self, field, value):
# If this field is bound to a datasource and the datasource is read only,
# generate an error.
- if self.isFieldBound(field) and self._parent.isReadOnly():
+ if self._parent.isFieldBound(field) and self._parent.isReadOnly():
# Provide better feedback??
raise ReadOnlyError, "Attempted to modify read only field '%s'" % field
else:
self._emptyFlag = 0
fn = lower(field)
self._fields[fn] = value
- if self.isFieldBound(field):
+ if self._parent.isFieldBound(field):
self._updateFlag = 1
if self._modifiedFlags.has_key(fn):
flag = self._modifiedFlags[fn] + 1
@@ -299,11 +337,6 @@
self._modifiedFlags[fn] = flag
- # Returns 1=Field is bound to a database field
- def isFieldBound(self, fieldName):
- return self._boundFields.has_key(lower(fieldName))
-
-
# Returns 1=Field has been modified
def isFieldModified(self, fieldName):
return self._modifiedFlags.has_key (lower(fieldName))
@@ -328,13 +361,13 @@
self._postChanges()
# Post all details in
- for child in (self._detailSources):
+ for child in (self._detailObjects):
child.post()
# Sets the ResultSet associated with this master record
def addDetailResultSet(self, ds):
- self._detailSources.append(ds)
+ self._detailObjects.append(ds)
###
Index: gnue/gnue-common/gnue/common/GLoginHandler.py
diff -u gnue/gnue-common/gnue/common/GLoginHandler.py:1.1
gnue/gnue-common/gnue/common/GLoginHandler.py:1.2
--- gnue/gnue-common/gnue/common/GLoginHandler.py:1.1 Mon May 14 14:59:59 2001
+++ gnue/gnue-common/gnue/common/GLoginHandler.py Tue May 15 08:16:38 2001
@@ -30,8 +30,16 @@
# HISTORY:
#
-class LoginHandler:
+#
+# If user stops the login process (cancel button?), raise this exception
+#
+class UserCanceledLogin(Exception):
+ pass
+
+
+
+class LoginHandler:
#
# getLogin is passed an list consisting of:
# Connection Name