diff --git a/occams/__init__.py b/occams/__init__.py index e842e866..fcd3f389 100644 --- a/occams/__init__.py +++ b/occams/__init__.py @@ -69,7 +69,6 @@ def main(global_config, **settings): config.include('pyramid_chameleon') config.include('pyramid_redis') config.include('pyramid_redis_sessions') - config.include('pyramid_tm') config.include('pyramid_webassets') config.add_renderer('json', JSON( adapters=( diff --git a/occams/models.py b/occams/models.py index f81d173d..700a2c0d 100644 --- a/occams/models.py +++ b/occams/models.py @@ -1,4 +1,4 @@ -import sqlalchemy as sa +from sqlalchemy import engine_from_config from sqlalchemy.orm import sessionmaker import zope.sqlalchemy @@ -7,34 +7,69 @@ from . import log -def includeme(config): - """ - Configures database connection +def get_engine(settings, prefix='sqlalchemy.'): + engine = engine_from_config(settings, prefix) + log.info('Connected to: "%s"' % repr(engine.url)) + return engine + + +def get_session_factory(engine): + factory = sessionmaker() + factory.configure(bind=engine) + return factory + + +def get_tm_session(session_factory, transaction_manager, info=None): """ - settings = config.registry.settings + Get a ``sqlalchemy.orm.Session`` instance backed by a transaction. - maker = sessionmaker() - zope.sqlalchemy.register(maker) - occams_datastore.models.events.register(maker) + This function will hook the session to the transaction manager which + will take care of committing any changes. - engine = sa.engine_from_config(settings, 'occams.db.') - maker.configure(bind=engine) + - When using pyramid_tm it will automatically be committed or aborted + depending on whether an exception is raised. - config.registry['db_sessionmaker'] = maker - config.add_request_method(_get_db_session, 'db_session', reify=True) + - When using scripts you should wrap the session in a manager yourself. + For example:: - log.info('Connected to: "%s"' % repr(engine.url)) + import transaction + engine = get_engine(settings) + session_factory = get_session_factory(engine) + with transaction.manager: + dbsession = get_tm_session(session_factory, transaction.manager) -def _get_db_session(request): - db_session = request.registry['db_sessionmaker']() - # Keep track of the request so we can generate model URLs - db_session.info['request'] = request - db_session.info['settings'] = request.registry.settings + """ + dbsession = session_factory() + + if info: + dbsession.info.update(info) + + occams_datastore.models.events.register(dbsession) + zope.sqlalchemy.register( + dbsession, transaction_manager=transaction_manager) + return dbsession + + +def includeme(config): + """ + Initialize the model for a Pyramid app. + """ + settings = config.get_settings() - def close_session(request): - db_session.close() + # use pyramid_tm to hook the transaction lifecycle to the request + config.include('pyramid_tm') - request.add_finished_callback(close_session) + engine = get_engine(settings, prefix='occams.db.') + session_factory = get_session_factory(engine) + config.registry['dbsession_factory'] = session_factory - return db_session + # make request.dbsession available for use in Pyramid + config.add_request_method( + # r.tm is the transaction manager used by pyramid_tm + lambda r: get_tm_session( + session_factory, + r.tm, info={'request': r, 'settings': r.registry.settings}), + 'db_session', + reify=True + )