# -*- coding: iso-8859-1 -*-
#-----------------------------------------------------------------------------
# Modeling Framework: an Object-Relational Bridge for python
#
# Copyright (c) 2001-2004 Sbastien Bigaret <sbigaret@users.sourceforge.net>
# All rights reserved.
#
# This file is part of the Modeling Framework.
#
# This code is distributed under a "3-clause BSD"-style license;
# see the LICENSE file for details.
#-----------------------------------------------------------------------------
"""
AbstractDBAPI2Adaptor
This module contains the AbstractDBAPI2Adaptor class to be inherited from
when designing an concrete Adaptor based on a python database-adaptor
complying to the python DB-API v2.0.
CVS information
$Id: AbstractDBAPI2Adaptor.py 933 2004-08-02 19:58:54Z sbigaret $
"""
__version__='$Revision: 933 $'[11:-2]
#
from Modeling.logging import db_info
# Framework
from Modeling.Adaptor import Adaptor
from Modeling.SQLExpression import SQLExpression
from Modeling.utils import staticmethod
#from Modeling.SQLExpressionFactory import SQLExpressionFactory
# Interfaces
from Modeling.interfaces.Adaptor import IAdaptor
## Low-levels func.
## Just for use by create/Drop DB
class AbstractDBAPI2Adaptor(Adaptor):
"""
Your inheriting concrete Adaptor class **must** override:
- underlying_py_adaptor_module(), which additionally must be declared as a
static method (please use Modeling.utils.staticmethod instead of
python2.2's, since the former works for python2.1 as well.
- createAdaptorContext(): see detail in the method's docstring.
- schemaGenerationFactory(): id.
Plus the two following methods, for use by the inherited methods:
- dbAPI_connectionDictionaryForConnect()
- dbAPI_gimmeCnxAndCursorForDBAdmin()
"""
__implements__ = (IAdaptor,)
def underlying_py_adaptor_module():
"""
Returns the underlying python DB-API v2.0-compliant db-adaptor module
Subclasses should override this method without calling the superclass'
implementation.
"""
__abstract__()
underlying_py_adaptor_module=staticmethod(underlying_py_adaptor_module)
def assertConnectionDictionaryIsValid(self):
"See Modeling.interfaces.Adaptor for details"
def assignExternalInfoForAttribute(self, anAttribute):
"See Modeling.interfaces.Adaptor for details"
def assignExternalInfoForEntity(self, anEntity):
"See Modeling.interfaces.Adaptor for details"
def createAdaptorContext(self):
"""
Creates and return an instance of the concrete AdaptorContext in relation
to your concrete Adaptor.
Implementation hint: say your adaptor's name is 'Dummy', then you'll
probably use the following code::
from DummyAdaptorContext import DummyAdaptorContext
concreteAdaptorContext=DummyAdaptorContext(self)
self._contexts.append(concreteAdaptorContext)
return concreteAdaptorContext
--> It is very important that you do not forget to append the adaptor
context to the list of 'self._contexts'
Subclasses should override this method without calling the superclass'
implementation.
"""
__abstract__()
#from AbstractDBAPI2AdaptorContext import AbstractDBAPI2AdaptorContext
#concreteAdaptorContext=AbstractDBAPI2AdaptorContext(self)
#self._contexts.append(concreteAdaptorContext)
#return concreteAdaptorContext
def createDatabaseWithAdministrativeConnectionDictionary(self, administrativeConnectionDictionary, createUserFlag=0):
"""
TBD
See also:
SchemaGeneration.createDatabaseStatementsForConnectionDictionary()
"""
sg=self.schemaGenerationFactory()
sqlExprs=sg.createDatabaseStatementsForConnectionDictionary(self.connectionDictionary(), administrativeConnectionDictionary, createUserFlag)
cnx, cur=self.dbAPI_gimmeCnxAndCursorForDBAdmin(administrativeConnectionDictionary)
try:
for sqlExpr in sqlExprs:
cur.execute(sqlExpr.statement())
finally:
# Note: it can be that, when drop/createDBWithAdminConnDict() are called
# just one after the other (such as in mdl_generate_DB_schema.py)
# it is not sufficient to close the cnx, or, e.g. postgresql
# raises the following error:
# ERROR: CREATE DATABASE: source database "template1" is being
# accessed by other users
# (this happens particularly often when creating the DB after dropping
# the database initially failed --because the database does not exist
# yet, e.g.)
# Since I remember having seen possibly-related strange things on
# drop/createDB w/ mysql I've changed the code here: explicit closing
# followed by explicit destruction. As far as I can tell it solves the
# problem, I suspect a delayed destruction of the cnx in dropDB()
# causing the connection to persist when createDB begins.
cur.close()
cnx.close()
del cur, cnx
def defaultExpressionClass(self):
"See Modeling.interfaces.Adaptor for details"
return SQLExpression
def dropDatabaseWithAdministrativeConnectionDictionary(self, administrativeConnectionDictionary, dropUserFlag=0):
"""
TBD
See also:
SchemaGeneration.dropDatabaseStatementsForConnectionDictionary()
"""
sg=self.schemaGenerationFactory()
sqlExprs=sg.dropDatabaseStatementsForConnectionDictionary(self.connectionDictionary(), administrativeConnectionDictionary, dropUserFlag)
cnx, cur=self.dbAPI_gimmeCnxAndCursorForDBAdmin(administrativeConnectionDictionary)
try:
for sqlExpr in sqlExprs:
cur.execute(sqlExpr.statement())
finally:
# See comments in createDatabaseWithAdministrativeConnectionDictionary()
# --> explicit closing and destruction of cnx and cur are intended here
cur.close()
cnx.close()
del cur; del cnx
def expressionFactory(self):
"See Modeling.interfaces.Adaptor for details"
return SQLExpressionFactory
def externalTypesWithModel(self, aModel):
"See Modeling.interfaces.Adaptor for details"
def fetchedValueForDataValue(self, value, anAttribute):
"See Modeling.interfaces.Adaptor for details"
def fetchedValueForDateValue(self, value, anAttribute):
"See Modeling.interfaces.Adaptor for details"
def fetchedValueForNumberValue(self, value, anAttribute):
"See Modeling.interfaces.Adaptor for details"
def fetchedValueForStringValue(self, value, anAttribute):
"See Modeling.interfaces.Adaptor for details"
def fetchedValueForValue(self, value, anAttribute):
"See Modeling.interfaces.Adaptor for details"
def internalTypeForExternalType(self, extType, aModel):
"See Modeling.interfaces.Adaptor for details"
def isValidQualifierType(self, typeName, aModel):
"See Modeling.interfaces.Adaptor for details"
def schemaGenerationFactory(self):
"""
Returns an instance of the concrete SchemaGeneration class.
Subclasses should override this method without calling the superclass'
implementation.
"""
__abstract__()
##def setConnectionDictionary(self, connectionDictionary):
## "See Modeling.interfaces.Adaptor for details"
## Adaptor.setConnectionDictionary.im_func(self, connectionDictionary)
##def setDelegate(self, aDelegate):
## "See Modeling.interfaces.Adaptor for details"
## Adaptor.setDelegate.im_func(self, aDelegate)
#def setExpressionClassName(sqlExpressionClassName, adaptorClassName):
#setExpressionClassName=StaticMethod(setExpressionClassName)
def dbAPI_connectionDictionaryForConnect(self, aModelConnectionDictionary):
"""
Returns the connection dictionary to be used with the underlying python
DB-API v2.0-compliant db-adaptor's connect(). The returned dictionary will
be passed as keyword to the connect() method (e.g.: 'apply(connect, (),
returnedDict)').
Subclasses should override this method without calling the superclass'
implementation.
Parameter:
aModelConnectionDictionary -- a dictionary made of the following keys:
'host', 'database', 'user' and 'password' (see also:
Modeling.Model.connectionDictionary())
"""
self.__abstract__()
def dbAPI_gimmeCnxAndCursorForDBAdmin(self, administrativeConnectionDictionary):
"""
Returns a connection object (opened using the
administrativeConnectionDictionary) and a cursor adequate to perform
adminstrative tasks on the database (i.e., mainly, adequate to create or
drop databases).
Note that depending on the underlying adaptor and the corresponding
database, this can be more or less easy to provide. For example,
Postgresql db does not allow any SQL statement like 'CREATE DATABASE' to
be executed while a transaction is opened. Since the python DB-API
implicitly requires that a transaction is automatically opened, a simple
connect is not sufficient. To continue with postgresql, the python module
'psycopg' offers an 'autocommit()' method on connection to toggle the
automatic opening of a transaction, while the 'pgdb' module requires some
additional work with its underlying '_pg' module.
Subclasses should override this method without calling the superclass'
implementation.
Parameter:
administrativeConnectionDictionary -- a dictionary made of the following
keys: 'host', 'database', 'user' and 'password' (see also:
Modeling.Model.connectionDictionary()).
"""
__abstract__()
def __abstract__():
raise 'Unimplemented', 'abstract method, should be implemented in subclasses'
|