I'm using turboears 0.9a5 and sqlalchemy 0.1.6. Recently, I decided to
upgrade everything to latest version.

However there are some problems. Specifically, all my applications are
connecting to more than one database. Apparently, support for multiple
databases is no longer as good as it was (partially because of changes
in SA). Before there was objectstore which handled all details, but now
that it is gone, turbogears has mostly lost it's support for multiple
SA databases.

First issue is that turbogears decides if SA is active like this:

def _use_sa():
    return _engine is not None

where _engine is globaly initialized using "sqlalchemy.dburi" config
key.
I don't have "sqlalchemy.dburi". Instead, I have:

    isoz.sqlalchemy.dburi
    tool.sqlalchemy.dburi
    dialer.sqlalchemy.dburi
    sugarcrm.sqlalchemy.dburi

My proposal is to decide if SA is active like this:

    config.get("sqlalchemy.in_use", False)

and to somewhere (there is an example later) active it like this:

    config.update({"sqlalchemy.in_use" : True})

Second issue is that turbogears supports PackageHub's for SQLObject and
there is no similar facility for SA. Direct result of this is that
there is ONE global engine (via sqlalchemy.dburi) and one global
metadata. It even goes that far as to replace activemapper's metadata
with that global object.

Also there is a bind_meta_data() function which has to be called from
several locations to make all this work (startup.py, command/base.py,
visit\savisit.py). It would be easier to use autoconnecting
engine/metadata.


This is my attempt to (partially) solve turbogears support for multiple
SA databases. It should replace similar block from database.py:

try:
    import sqlalchemy
    from sqlalchemy.ext import activemapper
    from sqlalchemy.ext.proxy import AutoConnectEngine

    class TurboMetaData(object):
        def __init__(self):
            # Dictionary of all package metadata objects
            # Key is:
            #  * package name in case of package uri
(<name>.sqlalchemy.dburi)
            #  * None in case of default database (sqlalchemy.dburi)
            self.metadatas = {}

            # If there is a main sqlalchemy uri, replace default
metadata in activemapper
            if config.get("sqlalchemy.dburi", None):
                activemapper.metadata = SAPackageMetaData()

        def __getattr__(self, name):
            try:
                return self.metadatas[name]
            except KeyError:
                return getattr(self.metadatas[None], name)

    metadata = TurboMetaData() #activemapper.metadata
    session = activemapper.objectstore

    def bind_meta_data():
        pass # Everything is already bound when using SAPackageMetaData

    def create_engine(*args, **kwargs):
        """Used to create package engines when no override is
specified.
        Can be patched from user code
        """
        return SAPackageEngine(*args, **kwargs)

    class SAPackageEngine(AutoConnectEngine):
        """
        An AutoConnectEngine that looks for the dburi based on a
package name.
        You can also create AutoConnectEngine as you would and other
engine: by
        specifying dburi and dict of parameters.
        """
        def __init__(self, packagename_or_dburi, **kwargs):
            dburi = self.get_dburi(packagename_or_dburi)
            super(SAPackageEngine, self).__init__(dburi, **kwargs)
        def get_dburi(self, packagename_or_dburi):
            if packagename_or_dburi:
                return config.get("%s.sqlalchemy.dburi" %
packagename_or_dburi, packagename_or_dburi)
            else:
                return config.get("sqlalchemy.dburi", None)

    class SAPackageMetaData(sqlalchemy.BoundMetaData):
        """
        An autoconnecting metadata intended to be used on package
level.
        """
        def __init__(self, engine_or_url=None, engine_creator=None,
name=None, **kwargs):
            if isinstance(engine_or_url, basestring) or engine_or_url
is None:
                creator = engine_creator or create_engine
                engine = creator(engine_or_url, **kwargs)
                name = name or engine_or_url
            else:
                engine = engine_or_url
            super(SAPackageMetaData, self).__init__(engine, name=name,
**kwargs)
            name = self.name or engine_or_url
            metadata.metadatas[name] = self
            config.update({"sqlalchemy.in_use" : True})
            global _engine
            _engine = True # to fool _use_sa()

except ImportError:
    sqlalchemy = None


To use is you have to do something like this:

from sqlalchemy import *
from sqlalchemy.ext.activemapper import *
from turbogears.database import SAPackageMetaData

__metadata__ = SAPackageMetaData('mypkg', echo=True,
encoding='windows-1250')

class Test(ActiveMapper):
    class mapping:
        __table__ = 'test'
        id = column(Integer, primary_key=True)
        name = column(Unicode(100))
        desc = column(Unicode(255))


I would welcome any comments on how to handle multiple databases,
especially if such support is not planned in turbogears.

Regards,
Tvrtko


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"TurboGears" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/turbogears
-~----------~----~----~----~------~----~------~--~---

Reply via email to