[Checkins] SVN: z3c.saconfig/trunk/src/z3c/saconfig/ Named session support; session directive; setup hook for engine factory (i.e. for mapper registration)

Laurence Rowe l at lrowe.co.uk
Tue Aug 12 07:15:47 EDT 2008


Log message for revision 89707:
  Named session support; session directive; setup hook for engine factory (i.e. for mapper registration)

Changed:
  U   z3c.saconfig/trunk/src/z3c/saconfig/README.txt
  U   z3c.saconfig/trunk/src/z3c/saconfig/__init__.py
  U   z3c.saconfig/trunk/src/z3c/saconfig/meta.zcml
  U   z3c.saconfig/trunk/src/z3c/saconfig/scopedsession.py
  U   z3c.saconfig/trunk/src/z3c/saconfig/tests.py
  U   z3c.saconfig/trunk/src/z3c/saconfig/utility.py
  U   z3c.saconfig/trunk/src/z3c/saconfig/zcml.py

-=-
Modified: z3c.saconfig/trunk/src/z3c/saconfig/README.txt
===================================================================
--- z3c.saconfig/trunk/src/z3c/saconfig/README.txt	2008-08-12 10:45:24 UTC (rev 89706)
+++ z3c.saconfig/trunk/src/z3c/saconfig/README.txt	2008-08-12 11:15:46 UTC (rev 89707)
@@ -324,3 +324,27 @@
   >>> component.getUtility(IEngineFactory, name="dummy")
   <z3c.saconfig.utility.EngineFactory object at ...>
 
+This time with a setup call.
+
+  >>> xmlconfig.xmlconfig(StringIO("""
+  ... <configure xmlns="http://namespaces.zope.org/db">
+  ...   <engine name="dummy2" url="sqlite:///:memory:"
+  ...           setup="z3c.saconfig.tests.engine_subscriber" />
+  ... </configure>"""))
+  got: Engine(sqlite:///:memory:)
+
+The session directive is provided to register a scoped session utility:
+
+  >>> xmlconfig.xmlconfig(StringIO("""
+  ... <configure xmlns="http://namespaces.zope.org/db">
+  ...   <session name="dummy" engine="dummy2" />
+  ... </configure>"""))
+
+  >>> component.getUtility(IScopedSession, name="dummy")
+  <z3c.saconfig.utility.GloballyScopedSession object at ...>
+
+  >>> from z3c.saconfig import named_scoped_session
+  >>> factory = component.getUtility(IEngineFactory, name="dummy2")
+  >>> Session = named_scoped_session('dummy')
+  >>> Session().bind is factory()
+  True

Modified: z3c.saconfig/trunk/src/z3c/saconfig/__init__.py
===================================================================
--- z3c.saconfig/trunk/src/z3c/saconfig/__init__.py	2008-08-12 10:45:24 UTC (rev 89706)
+++ z3c.saconfig/trunk/src/z3c/saconfig/__init__.py	2008-08-12 11:15:46 UTC (rev 89707)
@@ -1,3 +1,3 @@
-from z3c.saconfig.scopedsession import Session
+from z3c.saconfig.scopedsession import Session, named_scoped_session
 from z3c.saconfig.utility import (
     GloballyScopedSession, SiteScopedSession, EngineFactory)

Modified: z3c.saconfig/trunk/src/z3c/saconfig/meta.zcml
===================================================================
--- z3c.saconfig/trunk/src/z3c/saconfig/meta.zcml	2008-08-12 10:45:24 UTC (rev 89706)
+++ z3c.saconfig/trunk/src/z3c/saconfig/meta.zcml	2008-08-12 11:15:46 UTC (rev 89707)
@@ -12,6 +12,12 @@
        handler=".zcml.engine"
        />
 
+    <meta:directive
+       name="session"
+       schema=".zcml.ISessionDirective"
+       handler=".zcml.session"
+       />
+
   </meta:directives>
 
 </configure>

Modified: z3c.saconfig/trunk/src/z3c/saconfig/scopedsession.py
===================================================================
--- z3c.saconfig/trunk/src/z3c/saconfig/scopedsession.py	2008-08-12 10:45:24 UTC (rev 89706)
+++ z3c.saconfig/trunk/src/z3c/saconfig/scopedsession.py	2008-08-12 11:15:46 UTC (rev 89707)
@@ -3,22 +3,32 @@
 from sqlalchemy.orm import scoped_session
 from zope import component
 
-def session_factory():
+def session_factory(name=u''):
     """This is used by scoped session to create a new Session object.
 
     It delegates to a IScopedSession utility.
     """
-    utility = component.getUtility(IScopedSession)
+    utility = component.getUtility(IScopedSession, name)
     return utility.sessionFactory()
 
-def scopefunc():
+def scopefunc(name=u''):
     """This is used by scoped session to distinguish between sessions.
 
     It delegates to a IScopedSession utility.
     """
-    utility = component.getUtility(IScopedSession)
+    utility = component.getUtility(IScopedSession, name)
     return utility.scopeFunc()
 
 # this is framework central configuration. Use a IScopedSession utility
 # to define behavior.
 Session = scoped_session(session_factory, scopefunc)
+
+_named_scoped_sessions = {}
+
+def named_scoped_session(name):
+    try:
+        return _named_scoped_sessions[name]
+    except KeyError:
+        return _named_scoped_sessions.setdefault(name,
+                            scoped_session(lambda:session_factory(name),
+                                           lambda:scopefunc(name)))

Modified: z3c.saconfig/trunk/src/z3c/saconfig/tests.py
===================================================================
--- z3c.saconfig/trunk/src/z3c/saconfig/tests.py	2008-08-12 10:45:24 UTC (rev 89706)
+++ z3c.saconfig/trunk/src/z3c/saconfig/tests.py	2008-08-12 11:15:46 UTC (rev 89707)
@@ -89,7 +89,10 @@
 
 # make sure hooks get cleaned up after tests are run
 addCleanUp(resetHooks)
-    
+
+def engine_subscriber(engine):
+    print "got: %s " % engine
+
 def test_suite():
     optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
     globs = {

Modified: z3c.saconfig/trunk/src/z3c/saconfig/utility.py
===================================================================
--- z3c.saconfig/trunk/src/z3c/saconfig/utility.py	2008-08-12 10:45:24 UTC (rev 89706)
+++ z3c.saconfig/trunk/src/z3c/saconfig/utility.py	2008-08-12 11:15:46 UTC (rev 89707)
@@ -39,10 +39,13 @@
     to pass the right arguments to the superclasses __init__.
     """
     implements(IScopedSession)
-
-    def __init__(self, **kw):
+    
+    def __init__(self, engine=u'', **kw):
         """Pass keywords arguments for sqlalchemy.orm.create_session.
 
+        The `engine` argument is the name of a utility implementing
+        IEngineFactory.
+        
         Note that GloballyScopedSesssion does have different defaults than
         ``create_session`` for various parameters where it makes sense
         for Zope integration, namely:
@@ -54,13 +57,14 @@
         Normally you wouldn't pass these in, but if you have the need
         to override them, you could.
         """
+        self.engine = engine
         self.kw = _zope_session_defaults(kw)
 
     def sessionFactory(self):
         kw = self.kw.copy()
         if 'bind' not in kw:
-            # look up the engine  using IEngineFactory if needed
-            engine_factory = component.getUtility(IEngineFactory)
+            engine_factory = component.getUtility(IEngineFactory,
+                                                  name=self.engine)
             kw['bind'] = engine_factory()
         return sqlalchemy.orm.create_session(**kw)
     
@@ -87,13 +91,15 @@
     a SiteScopedSession utility without passing parameters to its constructor.
     """
     implements(ISiteScopedSession)
-
-    def __init__(self, **kw):
+    
+    def __init__(self, engine=u'', **kw):
         assert 'bind' not in kw
+        self.engine = engine
         self.kw = _zope_session_defaults(kw)
         
     def sessionFactory(self):
-        engine_factory = component.getUtility(IEngineFactory)
+        engine_factory = component.getUtility(IEngineFactory,
+                                              name=self.engine)
         kw = self.kw.copy()
         kw['bind'] = engine_factory()
         return sqlalchemy.orm.create_session(**kw)

Modified: z3c.saconfig/trunk/src/z3c/saconfig/zcml.py
===================================================================
--- z3c.saconfig/trunk/src/z3c/saconfig/zcml.py	2008-08-12 10:45:24 UTC (rev 89706)
+++ z3c.saconfig/trunk/src/z3c/saconfig/zcml.py	2008-08-12 11:15:46 UTC (rev 89707)
@@ -1,6 +1,7 @@
 import zope.interface
 import zope.schema
 import zope.component.zcml
+import zope.dottedname.resolve
 
 import utility
 import interfaces
@@ -25,7 +26,42 @@
         required=False,
         default=False)
 
-def engine(_context, url, name=u"", echo=False):
+    setup = zope.schema.DottedName(
+        title=u'After engine creation hook',
+        description=u'Callback for creating mappers etc. One argument is passed, the engine',
+        required=False,
+        default=None)
+
+
+class ISessionDirective(zope.interface.Interface):
+    """Registers a database scoped session"""
+
+    name = zope.schema.Text(
+        title=u"Scoped session name",
+        description=u"Empty if this is the default session.",
+        required=False,
+        default=u"")
+
+    twophase = zope.schema.Bool(
+        title=u'Use two-phase commit',
+        description=u'Session should use two-phase commit',
+        required=False,
+        default=False)
+
+    engine = zope.schema.Text(
+        title=u"Engine name",
+        description=u"Empty if this is to use the default engine.",
+        required=False,
+        default=u"")
+
+    factory = zope.schema.DottedName(
+        title=u'Scoped Session utility factory',
+        description=u'GloballyScopedSession by default',
+        required=False,
+        default="z3c.saconfig.utility.GloballyScopedSession")
+
+
+def engine(_context, url, name=u"", echo=False, setup=None, twophase=False):
     factory = utility.EngineFactory(url, echo=echo)
     
     zope.component.zcml.utility(
@@ -34,4 +70,20 @@
         component=factory,
         permission=zope.component.zcml.PublicPermission,
         name=name)
-        
+    
+    if setup:
+        callback = zope.dottedname.resolve.resolve(setup)
+        callback(factory())
+
+def session(_context, name=u"", engine=u"", twophase=False,
+            factory="z3c.saconfig.utility.GloballyScopedSession"):
+    ScopedSession = zope.dottedname.resolve.resolve(factory)
+    scoped_session = ScopedSession(engine=engine, twophase=twophase)
+
+    zope.component.zcml.utility(
+        _context,
+        provides=interfaces.IScopedSession,
+        component=scoped_session,
+        permission=zope.component.zcml.PublicPermission,
+        name=name)
+    



More information about the Checkins mailing list