Re: [Zope-dev] Re: SQLAlchemy (zope.sqlalchemy) integration

2008-06-06 Thread Hermann Himmelbauer
Am Donnerstag, 5. Juni 2008 19:38 schrieb Laurence Rowe:
 Hermann Himmelbauer wrote:
  Am Mittwoch, 4. Juni 2008 22:09 schrieb Laurence Rowe:
  Hermann Himmelbauer wrote:
  In my application, I then use getSASession() to retrieve my session.
 
  However, what I think is not that beautiful is the s.bind = engine
  part. Are there any suggestions how to improve this?
 
  You have two options
 
  If you ever need to mix objects from different `sites` into the same
  session, you should use an adapter on your root object like:
 
  If you don't need to mix objects from different `sites` then you can
  register a local utility for ISessionConfig.
 
  def scope():
 return getUtility(ISessionConfig).uid, thread.get_ident()
 
  def factory():
 engine = Engine(getUtility(ISessionConfig).url)
 return create_session(
   transactional=True, autoflush=True, bind=engine
   extension=ZopeTransactionExtension(),
   ))
 
  Session = scoped_session(factory, scopefunc=scope)
 
  Then you can just import Session and use:
  session = Session()
 
  Ok, great, thanks for help. The only thing I don't understand is what
  uid from the SessionConfig utility is. Below is my full database
  integration code which works for me, perhaps this is helpful to someone
  else.

 uid is some id that distinguishes your various application instances. On
 zope 2 I would probably use getPhysicalPath(). I don't know what the
 zope3 equivalent is.

Hmmm, maybe it's:

from zope.traversing.api import getPath
from zope.app.component.hooks import getSite
@property
def uid(self):
return getPath(getSite())

 Looking at your code, why did you decide to store the engine on a _v_
 attribute? I don't think you need to save it at all. You can access a
 connection through session.connection()

Ok, but in case I create the engine in the session_factor, e.g.:

def session_factory():
engine = createEngine()
return create_session(transactional = True,
  autoflush = True,
  bind = engine,
  extension = ZopeTransactionExtension())

Wouldn't the engine be created for every request, as the scope changes and the 
factory is called? In my case, the engine is created when the first session 
is fetched. After that it will be recreated only if the DSN changes.

  Btw., I'd suggest to put such code / session use cases in some Zope
  package, maybe into zope.sqlalchemy, or e.g. zope.sqlalchemy_utility as
  it's really difficult for non-insiders to set this up.

 We would need to work out what parts are useful to the various higher
 level sqlalchemy / zope packages. Once we can agree on a common core
 then we should at least make simple use cases available through
 zope.sqlalchemy directly.

In my scenario, all I need is a local utility. This is something that was 
available in z3c.zalchemy, too (and I think also in z3c.sqlalchemy).
The problem about putting this code into zope.sqlalchemy is that the 
local-utility code may be based on other zope packages and hence create 
unwanted dependencies. But I'm unsure about this.

Best Regards,
Hermann

-- 
[EMAIL PROTECTED]
GPG key ID: 299893C7 (on keyservers)
FP: 0124 2584 8809 EF2A DBF9  4902 64B4 D16B 2998 93C7
___
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 http://mail.zope.org/mailman/listinfo/zope-announce
 http://mail.zope.org/mailman/listinfo/zope )


[Zope-dev] Re: SQLAlchemy (zope.sqlalchemy) integration

2008-06-06 Thread Laurence Rowe

Hermann Himmelbauer wrote:

Am Donnerstag, 5. Juni 2008 19:38 schrieb Laurence Rowe:

Hermann Himmelbauer wrote:

Am Mittwoch, 4. Juni 2008 22:09 schrieb Laurence Rowe:

Hermann Himmelbauer wrote:

In my application, I then use getSASession() to retrieve my session.

However, what I think is not that beautiful is the s.bind = engine
part. Are there any suggestions how to improve this?

You have two options

If you ever need to mix objects from different `sites` into the same
session, you should use an adapter on your root object like:

If you don't need to mix objects from different `sites` then you can
register a local utility for ISessionConfig.

def scope():
   return getUtility(ISessionConfig).uid, thread.get_ident()

def factory():
   engine = Engine(getUtility(ISessionConfig).url)
   return create_session(
 transactional=True, autoflush=True, bind=engine
 extension=ZopeTransactionExtension(),
 ))

Session = scoped_session(factory, scopefunc=scope)

Then you can just import Session and use:
session = Session()

Ok, great, thanks for help. The only thing I don't understand is what
uid from the SessionConfig utility is. Below is my full database
integration code which works for me, perhaps this is helpful to someone
else.

uid is some id that distinguishes your various application instances. On
zope 2 I would probably use getPhysicalPath(). I don't know what the
zope3 equivalent is.


Hmmm, maybe it's:

from zope.traversing.api import getPath
from zope.app.component.hooks import getSite
@property
def uid(self):
return getPath(getSite())


Looking at your code, why did you decide to store the engine on a _v_
attribute? I don't think you need to save it at all. You can access a
connection through session.connection()


Ok, but in case I create the engine in the session_factor, e.g.:

def session_factory():
engine = createEngine()
return create_session(transactional = True,
  autoflush = True,
  bind = engine,
  extension = ZopeTransactionExtension())

Wouldn't the engine be created for every request, as the scope changes and the 
factory is called? In my case, the engine is created when the first session 
is fetched. After that it will be recreated only if the DSN changes.


The engines are created the same number of times either way. 
zope.sqlalchemy uses session.close() rather than session.remove(), so 
the session/engine is only created once per thread, then recycled. This 
is the same as storing it on a _v_ attribute, which are per thread as 
active objects live in the connection cache.


Laurence

___
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
http://mail.zope.org/mailman/listinfo/zope-announce

http://mail.zope.org/mailman/listinfo/zope )


Re: [Zope-dev] Re: SQLAlchemy (zope.sqlalchemy) integration

2008-06-05 Thread Hermann Himmelbauer
Am Mittwoch, 4. Juni 2008 22:09 schrieb Laurence Rowe:
 Hermann Himmelbauer wrote:
  In my application, I then use getSASession() to retrieve my session.
 
  However, what I think is not that beautiful is the s.bind = engine
  part. Are there any suggestions how to improve this?

 You have two options

 If you ever need to mix objects from different `sites` into the same
 session, you should use an adapter on your root object like:

 If you don't need to mix objects from different `sites` then you can
 register a local utility for ISessionConfig.

 def scope():
return getUtility(ISessionConfig).uid, thread.get_ident()

 def factory():
engine = Engine(getUtility(ISessionConfig).url)
return create_session(
  transactional=True, autoflush=True, bind=engine
  extension=ZopeTransactionExtension(),
  ))

 Session = scoped_session(factory, scopefunc=scope)

 Then you can just import Session and use:
 session = Session()

Ok, great, thanks for help. The only thing I don't understand is what uid 
from the SessionConfig utility is. Below is my full database integration code 
which works for me, perhaps this is helpful to someone else.

Btw., I'd suggest to put such code / session use cases in some Zope package, 
maybe into zope.sqlalchemy, or e.g. zope.sqlalchemy_utility as it's really 
difficult for non-insiders to set this up.

-
import thread
from persistent import Persistent
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, create_session
from zope.interface import Interface, implements, alsoProvides
from zope.schema import TextLine, Bool
from zope.component import getUtility, adapter
from zope.sqlalchemy import ZopeTransactionExtension

from zmyapp.interfaces import INewMySiteEvent

from zope.i18nmessageid import MessageFactory
_ = MessageFactory('xyz')

class ISAEngineUtility(Interface):
SQLAlchemy Engine Utility

db_type = TextLine(title = _(uDatabase Type))
db_username = TextLine(title = _(uDatabase Username))
db_password = TextLine(title = _(uDatabase Password))
db_host = TextLine(title = _(uDatabase Host))
db_name = TextLine(title = _(uDatabase Name))
db_echo = Bool(title = _(uEcho Database Operations))
db_enconding = TextLine(title = _(uDatabase Encoding))
db_convert_unicode = Bool(title = _(uDatabase Unicode Conversion))

class SAEngineUtility(Persistent):
implements(ISAEngineUtility)

# FIXME FIXME!!!
uid = 12345

def reset_engine_on_attrset(dsn_part):
doc = Reset engine when setting variable (stored in %s) % dsn_part
def fget(self):
return getattr(self, dsn_part, None)
def fset(self, value):
oldvalue = getattr(self, dsn_part, None)
if oldvalue != value:
setattr(self, dsn_part, value)
if getattr(self, 'init_done', False):
self._resetEngine()
return {'fget': fget, 'fset': fset, 'doc': doc}

db_type = property(**reset_engine_on_attrset('_db_type'))
db_username = property(**reset_engine_on_attrset('_db_username'))
db_password = property(**reset_engine_on_attrset('_db_password'))
db_host = property(**reset_engine_on_attrset('_db_host'))
db_name = property(**reset_engine_on_attrset('_db_name'))
db_echo = property(**reset_engine_on_attrset('_db_echo'))
db_encoding = property(**reset_engine_on_attrset('_db_encoding'))
db_convert_unicode =property(
 **reset_engine_on_attrset('_db_convert_unicode'))

def __init__(self, db_type, db_username, db_password, db_host, db_name,
 db_echo = False,
 db_encoding = 'utf-8',
 db_convert_unicode = False):
self.db_type = db_type
self.db_username = db_username
self.db_password = db_password
self.db_host = db_host
self.db_name = db_name
self.db_echo = db_echo
self.db_encoding = db_encoding
self.db_convert_unicode = db_convert_unicode
self.init_done = True

def mkDSN(self):
Create database DSN out of DSN elements
userpass = ''
if self.db_username:
userpass += self.db_username
if self.db_password:
userpass += ':' + self.db_password
if self.db_host == 'localhost':
db_host = ''
else:
db_host = self.db_host
if db_host and userpass:
db_host = userpass + '@' + self.db_host
elif not db_host and userpass:
db_host = userpass + '@localhost'
return '%s://%s/%s' % (self.db_type, db_host, self.db_name)

def getEngine(self):
engine = getattr(self, '_v_engine', None)
if engine:
return engine

# No engine available, create a new one
self._v_engine = create_engine(self.mkDSN(),
   echo = self.db_echo,
  

[Zope-dev] Re: SQLAlchemy (zope.sqlalchemy) integration

2008-06-05 Thread Laurence Rowe

Hermann Himmelbauer wrote:

Am Mittwoch, 4. Juni 2008 22:09 schrieb Laurence Rowe:

Hermann Himmelbauer wrote:

In my application, I then use getSASession() to retrieve my session.

However, what I think is not that beautiful is the s.bind = engine
part. Are there any suggestions how to improve this?

You have two options

If you ever need to mix objects from different `sites` into the same
session, you should use an adapter on your root object like:

If you don't need to mix objects from different `sites` then you can
register a local utility for ISessionConfig.

def scope():
   return getUtility(ISessionConfig).uid, thread.get_ident()

def factory():
   engine = Engine(getUtility(ISessionConfig).url)
   return create_session(
 transactional=True, autoflush=True, bind=engine
 extension=ZopeTransactionExtension(),
 ))

Session = scoped_session(factory, scopefunc=scope)

Then you can just import Session and use:
session = Session()


Ok, great, thanks for help. The only thing I don't understand is what uid 
from the SessionConfig utility is. Below is my full database integration code 
which works for me, perhaps this is helpful to someone else.


uid is some id that distinguishes your various application instances. On 
zope 2 I would probably use getPhysicalPath(). I don't know what the 
zope3 equivalent is.


Looking at your code, why did you decide to store the engine on a _v_ 
attribute? I don't think you need to save it at all. You can access a 
connection through session.connection()



Btw., I'd suggest to put such code / session use cases in some Zope package, 
maybe into zope.sqlalchemy, or e.g. zope.sqlalchemy_utility as it's really 
difficult for non-insiders to set this up.


We would need to work out what parts are useful to the various higher 
level sqlalchemy / zope packages. Once we can agree on a common core 
then we should at least make simple use cases available through 
zope.sqlalchemy directly.


Laurence

___
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
http://mail.zope.org/mailman/listinfo/zope-announce

http://mail.zope.org/mailman/listinfo/zope )


[Zope-dev] Re: SQLAlchemy (zope.sqlalchemy) integration

2008-06-04 Thread Laurence Rowe

Hermann Himmelbauer wrote:

Hi,
Regarding to the discussion some days ago with the SQLAlchemy Zope3 
integration, I still have problems with retrieving the session. I currently 
use a utility for the engine, which seems to work well.


However, for retrieving the session, I tried to use the following pattern 
(many thanks to Michael Bayer, btw.):


 database module ---
SASession = scoped_session(sessionmaker(
transactional = True,
autoflush = True,
extension = ZopeTransactionExtension()))

def getSASession():
SASession.remove()
engine = getUtility(ISAEngineUtility).getEngine()
s = SASession()
s.bind = engine
return s


In my application, I then use getSASession() to retrieve my session.

However, what I think is not that beautiful is the s.bind = engine part. Are 
there any suggestions how to improve this?


You have two options

If you ever need to mix objects from different `sites` into the same 
session, you should use an adapter on your root object like:


Sessions = {}

@adapter(MyRoot)
@provider(ISASession)
def getSASession(context):
  Session = Sessions.get(context.uid, None)
  if Session is None:
Session = Sessions.setdefault(
  context.uid,
  scoped_session(sessionmaker(
transactional=True, autoflush=True,
extension=ZopeTransactionExtension(),
bind=Engine(context.engine_url) # or getUtility...
  ))
)
  return Session()

And register orm.object_session also if you like to call consistently
session = ISASession(context)


If you don't need to mix objects from different `sites` then you can 
register a local utility for ISessionConfig.


def scope():
  return getUtility(ISessionConfig).uid, thread.get_ident()

def factory():
  engine = Engine(getUtility(ISessionConfig).url)
  return create_session(
transactional=True, autoflush=True, bind=engine
extension=ZopeTransactionExtension(),
))

Session = scoped_session(factory, scopefunc=scope)

Then you can just import Session and use:
   session = Session()

Laurence

___
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
http://mail.zope.org/mailman/listinfo/zope-announce

http://mail.zope.org/mailman/listinfo/zope )