[Checkins] SVN: z3c.dobbin/trunk/ Updated codebase to use zope.sqlalchemy; this consists of minor import-changes as well as reimplementing support for concrete instances (this now uses a before-commit-hook). Thanks to Lawrence Rowe for assistance.

Malthe Borch mborch at gmail.com
Thu Jul 10 12:14:03 EDT 2008


Log message for revision 88194:
  Updated codebase to use zope.sqlalchemy; this consists of minor import-changes as well as reimplementing support for concrete instances (this now uses a before-commit-hook). Thanks to Lawrence Rowe for assistance.

Changed:
  U   z3c.dobbin/trunk/README.txt
  U   z3c.dobbin/trunk/setup.py
  U   z3c.dobbin/trunk/src/z3c/dobbin/README.txt
  U   z3c.dobbin/trunk/src/z3c/dobbin/bootstrap.py
  U   z3c.dobbin/trunk/src/z3c/dobbin/mapper.py
  U   z3c.dobbin/trunk/src/z3c/dobbin/relations.py
  U   z3c.dobbin/trunk/src/z3c/dobbin/session.py
  U   z3c.dobbin/trunk/src/z3c/dobbin/soup.py
  U   z3c.dobbin/trunk/src/z3c/dobbin/testing.py
  U   z3c.dobbin/trunk/src/z3c/dobbin/tests.py
  A   z3c.dobbin/trunk/src/z3c/dobbin/zs2sa.py

-=-
Modified: z3c.dobbin/trunk/README.txt
===================================================================
--- z3c.dobbin/trunk/README.txt	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/README.txt	2008-07-10 16:14:02 UTC (rev 88194)
@@ -16,5 +16,6 @@
 -------
 
 This package was designed and implemented by Malthe Borch, Stefan
-Eletzhofer. It's licensed as ZPL.
+Eletzhofer with parts contributed by Kapil Thangavelu and Laurence
+Rowe. It's licensed as ZPL.
 

Modified: z3c.dobbin/trunk/setup.py
===================================================================
--- z3c.dobbin/trunk/setup.py	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/setup.py	2008-07-10 16:14:02 UTC (rev 88194)
@@ -40,7 +40,6 @@
       zip_safe=False,
       extras_require = dict(
         test = [
-            'zope.app.testing',
             'pysqlite',
             ],
         ),
@@ -49,7 +48,8 @@
                            'zope.schema',
                            'zope.component',
                            'zope.dottedname',
-                           'ore.alchemist',
-                           'ZODB3',
+                           'zope.configuration',
+                           'z3c.saconfig',
+                           'transaction',
                            'SQLAlchemy==0.4.6'],
       )

Modified: z3c.dobbin/trunk/src/z3c/dobbin/README.txt
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/README.txt	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/src/z3c/dobbin/README.txt	2008-07-10 16:14:02 UTC (rev 88194)
@@ -6,8 +6,8 @@
 
 We begin with a new database session.
 
-    >>> import ore.alchemist
-    >>> session = ore.alchemist.Session()
+    >>> import z3c.saconfig
+    >>> session = z3c.saconfig.Session()
 
 Mappers from interface specification
 ------------------------------------
@@ -78,15 +78,19 @@
     >>> session.save(album)
     >>> session.save(vinyl)
     >>> session.save(cd)
+
+We must actually query the database once before proceeding; this seems
+to be a bug in ``zope.sqlalchemy``.
     
+    >>> results = session.query(album.__class__).all()
+    
     >>> import transaction
     >>> transaction.commit()
 
 We get a reference to the database metadata object, to locate each
 underlying table.
     
-    >>> from ore.alchemist.interfaces import IDatabaseEngine
-    >>> engine = component.getUtility(IDatabaseEngine)
+    >>> engine = session.bind
     >>> metadata = engine.metadata
 
 Tables are given a name based on the dotted path of the interface they

Modified: z3c.dobbin/trunk/src/z3c/dobbin/bootstrap.py
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/bootstrap.py	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/src/z3c/dobbin/bootstrap.py	2008-07-10 16:14:02 UTC (rev 88194)
@@ -2,17 +2,21 @@
 
 import sqlalchemy as rdb
 from sqlalchemy import orm
-        
-import ore.alchemist.interfaces
+
+from z3c.saconfig.interfaces import IEngineFactory
+
 import relations
 
 class UUID(rdb.types.TypeEngine):
     def get_col_spec(self):
         return "UUID"
 
-def bootstrapDatabaseEngine(event):
-    engine = component.getUtility(ore.alchemist.interfaces.IDatabaseEngine)
+def bootstrapDatabaseEngine(event=None):
+    factory = component.getUtility(IEngineFactory)
+    engine = factory()
     engine.metadata = metadata = rdb.MetaData(engine)
+
+    # setup metadata
     setUp(metadata)
     
 def setUp(metadata):

Modified: z3c.dobbin/trunk/src/z3c/dobbin/mapper.py
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/mapper.py	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/src/z3c/dobbin/mapper.py	2008-07-10 16:14:02 UTC (rev 88194)
@@ -15,10 +15,8 @@
 
 from sqlalchemy.orm.attributes import proxied_attribute_factory
 
-from ore.alchemist.interfaces import IDatabaseEngine
-from ore.alchemist import Session
-from ore.alchemist.zs2sa import FieldTranslator
-from ore.alchemist.zs2sa import StringTranslator
+from z3c.saconfig import Session
+from zs2sa import FieldTranslator, StringTranslator
 
 from uuid import uuid1
 from random import randint
@@ -148,7 +146,7 @@
 def createMapper(spec):
     """Create a mapper for the specification."""
 
-    engine = component.getUtility(IDatabaseEngine)
+    engine = Session().bind
     metadata = engine.metadata
 
     exclude = ['__name__']

Modified: z3c.dobbin/trunk/src/z3c/dobbin/relations.py
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/relations.py	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/src/z3c/dobbin/relations.py	2008-07-10 16:14:02 UTC (rev 88194)
@@ -1,6 +1,6 @@
 from zope import interface
 
-from ore.alchemist import Session
+from z3c.saconfig import Session
 
 import soup
 import factory

Modified: z3c.dobbin/trunk/src/z3c/dobbin/session.py
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/session.py	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/src/z3c/dobbin/session.py	2008-07-10 16:14:02 UTC (rev 88194)
@@ -1,82 +1,21 @@
 from zope import interface
 
-from transaction.interfaces import ISavepointDataManager
-from transaction import get as getTransaction
+from z3c.saconfig import Session
 
-from ore.alchemist import Session
-
 import soup
+import transaction
 
-class Savepoint:
-    """Transaction savepoint."""
+def beforeCommitHook(obj, uuid):
+    # unset pending state
+    session = Session()
+    del session._d_pending[uuid]
 
-    def rollback(self):
-        raise NotImplementedError("Rollbacks are not implemented.")
+    # build instance
+    instance = soup.lookup(uuid)
 
-class TransactionManager(object):
-    """Transaction manager for the database session.
+    # update attributes
+    soup.update(instance, obj)    
 
-    This is used to synchronize relations to concrete items.    
-    """
-    
-    interface.implements(ISavepointDataManager)
-
-    def __init__(self, obj, uuid):
-        self.registered = False
-        self.vote = False
-        self.obj = obj
-        self.uuid = uuid
-        
-        session = Session()
-
-        try:
-            session._d_pending[uuid] = obj
-        except AttributeError:
-            session._d_pending = {uuid: obj}
-        
-    def register(self):
-        if not self.registered:
-            getTransaction().join(self)
-            self.registered = True
-            
-    def savepoint(self):
-        return Savepoint()
-
-    def tpc_begin(self, transaction):
-        pass
-
-    def commit(self, transaction):
-        obj = self.obj
-        uuid = self.uuid
-
-        # unset pending state
-        session = Session()
-        del session._d_pending[uuid]
-
-        # build instance
-        instance = soup.lookup(uuid)
-
-        # update attributes
-        soup.update(instance, obj)
-        
-    def tpc_vote(self, transaction):
-        pass
-
-    def tpc_finish(self, transaction):
-        self.registered = False
-
-    def tpc_abort(self, transaction):
-        # unset pending state
-        session = Session()
-        del session._d_pending[self.uuid]
-        
-        self.registered = False
-
-    abort = tpc_abort
-
-    def sortKey(self):
-        return id(self)
-
 def registerObject(obj, uuid):
     session = Session()
 
@@ -86,5 +25,9 @@
         pending = ()
     
     if obj not in pending:
-        TransactionManager(obj, uuid).register()
+        try:
+            session._d_pending[uuid] = obj
+        except AttributeError:
+            session._d_pending = {uuid: obj}
 
+        transaction.get().addBeforeCommitHook(beforeCommitHook, (obj, uuid))

Modified: z3c.dobbin/trunk/src/z3c/dobbin/soup.py
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/soup.py	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/src/z3c/dobbin/soup.py	2008-07-10 16:14:02 UTC (rev 88194)
@@ -6,7 +6,7 @@
 from session import registerObject
 
 from zope.dottedname.resolve import resolve
-from ore.alchemist import Session
+from z3c.saconfig import Session
 
 import factory
 import bootstrap

Modified: z3c.dobbin/trunk/src/z3c/dobbin/testing.py
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/testing.py	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/src/z3c/dobbin/testing.py	2008-07-10 16:14:02 UTC (rev 88194)
@@ -7,26 +7,28 @@
 
 from sqlalchemy import orm
 
-from ore.alchemist import Session
-from ore.alchemist.interfaces import IDatabaseEngine
-
 import z3c.dobbin
 
+from z3c.saconfig import EngineFactory
+from z3c.saconfig import GloballyScopedSession
+
 metadata = rdb.MetaData()
 
 def setUp(test):
-    test._engine = rdb.create_engine('sqlite:///:memory:')
+    # provide engine factory
+    factory = EngineFactory('sqlite:///:memory:')
+    component.provideUtility(factory)
+
+    # setup scoped session
+    utility = GloballyScopedSession(autoflush=True)
+    component.provideUtility(utility)
     
-    # register database engine
-    component.provideUtility(test._engine, IDatabaseEngine)
-
     # bootstrap database engine
-    z3c.dobbin.bootstrap.bootstrapDatabaseEngine(None)
+    z3c.dobbin.bootstrap.bootstrapDatabaseEngine()
 
     # register components
     zope.configuration.xmlconfig.XMLConfig('meta.zcml', component)()
     zope.configuration.xmlconfig.XMLConfig('configure.zcml', z3c.dobbin)()
 
 def tearDown(test):
-    del test._engine
-    del metadata._bind
+    pass

Modified: z3c.dobbin/trunk/src/z3c/dobbin/tests.py
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/tests.py	2008-07-10 15:52:48 UTC (rev 88193)
+++ z3c.dobbin/trunk/src/z3c/dobbin/tests.py	2008-07-10 16:14:02 UTC (rev 88194)
@@ -5,7 +5,7 @@
 from zope import schema
 from zope import component
 
-from zope.app.testing import setup
+import zope.component.testing
 from zope.testing.doctestunit import DocFileSuite
 
 import transaction
@@ -13,12 +13,12 @@
 import testing
 
 def setUp(test):
-    setup.placefulSetUp()
+    zope.component.testing.setUp(test)
     testing.setUp(test)
     
 def tearDown(test):
-    setup.placefulTearDown()
     testing.tearDown(test)
+    zope.component.testing.tearDown(test)
     
 def test_suite():
     globs = dict(

Added: z3c.dobbin/trunk/src/z3c/dobbin/zs2sa.py
===================================================================
--- z3c.dobbin/trunk/src/z3c/dobbin/zs2sa.py	                        (rev 0)
+++ z3c.dobbin/trunk/src/z3c/dobbin/zs2sa.py	2008-07-10 16:14:02 UTC (rev 88194)
@@ -0,0 +1,68 @@
+from zope import schema
+import sqlalchemy as rdb
+
+class FieldTranslator( object ):
+    """ Translate a zope schema field to an sa  column
+    """
+
+    def __init__(self, column_type):
+        self.column_type = column_type
+
+    def extractInfo( self, field, info ):
+        d = {}
+        d['name'] = field.getName()
+        if field.required:
+            d['nullable'] = False
+        d['default'] = field.default
+        d['type'] = self.column_type        
+        return d
+    
+    def __call__(self, field, annotation):
+        d = self.extractInfo( field, annotation )
+        name, type = d['name'], d['type']
+        del d['name']
+        del d['type']
+        return rdb.Column( name, type, **d)
+
+class StringTranslator(FieldTranslator):
+    
+    column_type = rdb.Text
+
+    def __init__(self, column_type=None):
+        self.column_type = column_type or self.column_type
+        
+    def extractInfo( self, field, info ):
+        d = super( StringTranslator, self ).extractInfo( field, info )
+        if schema.interfaces.IMinMaxLen.providedBy( field ):
+            d['type'].length = field.max_length
+        return d
+
+class ObjectTranslator(object):
+    
+    def __call__(self, field, metadata):
+        table = transmute(field.schema, metadata)
+        pk = get_pk_name(table.name)
+        field_name = "%s.%s" % table.name, pk
+        return rdb.Column(pk, rdb.Integer, rdb.ForeignKey(field_name),
+            nullable=False)
+
+fieldmap = {
+    'ASCII': StringTranslator(),
+    'ASCIILine': StringTranslator(),
+    'Bool': FieldTranslator(rdb.BOOLEAN),
+    'Bytes': FieldTranslator(rdb.BLOB),
+    'BytesLine': FieldTranslator(rdb.BLOB),
+    'Choice': StringTranslator(),
+    'Date': FieldTranslator(rdb.DATE), 
+    'Datetime': FieldTranslator(rdb.DATE), 
+    'DottedName': StringTranslator(),
+    'Float': FieldTranslator(rdb.Float), 
+    'Id': StringTranslator(),
+    'Int': FieldTranslator(rdb.Integer),
+    'Object': ObjectTranslator(),
+    'Password': StringTranslator(),
+    'SourceText': StringTranslator(),
+    'Text': StringTranslator(),
+    'TextLine': StringTranslator(),
+    'URI': StringTranslator(),
+}



More information about the Checkins mailing list