SQLAlchemy-Continuum and Pyramid: UnboundExecutionError

608 views Asked by At

I have a Pyramid application that does CRUD with SQLAlchemy via pyramid_basemodel. All seems to work nicely.

I then pip installed SQLAlchemy-Continuum, to provide history for certain objects. All I did to configure it was make the following alterations to my models.py file:

import sqlalchemy as sa
from sqlalchemy import (event, Column, Index, Integer, Text, String, Date, DateTime, \
    Float, ForeignKey, Table, Boolean,)
from sqlalchemy.orm import (relationship, backref, mapper, scoped_session, sessionmaker,)

from pyramid_basemodel import Base, BaseMixin, Session, save
from pyramid_fullauth.models import User
from sqlalchemy_continuum import make_versioned

from colanderalchemy import setup_schema
from zope.sqlalchemy import ZopeTransactionExtension

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
event.listen(mapper, 'mapper_configured', setup_schema)

# Continuum setup
make_versioned()

# FOR EACH VERSIONED MODEL I ADD __versioned__ = {} at the start of each model def. Eg:
class Thing(Base):
    __versioned__ = {}
    __tablename__ = 'thing'
    id = sa.Column(Integer, primary_key=True)
    related_id = sa.Column(Integer, ForeignKey('OtherThing.id'))
    other_thing = sa.orm.relationship("OtherThing", backref="thing")
    description = sa.Column(String(length=100))
    a_date = sa.Column(Date)
    some_hours = sa.Column(Integer)
    b_date = sa.Column(Date)
    more_hours = sa.Column(Integer)


sa.orm.configure_mappers()

(Sorry for the slightly redundant imports; I decided to totally follow the Continuum example and import sqlalchemy as sa, and switch to using that notation in the models that I versioned. I may also be doing stupid, monkey-see monkey-do stuff based on a half-understanding of different tutorials.)

This setup allowed me to run alembic revision --autogenerate and produce ModelHistory tables in the database, but when I go to some of the pages that read the now-versioned models, they give the error

sqlalchemy.exc.UnboundExecutionError: This session is not bound to a single Engine or Connection, and no context was provided to locate a binding.

For some reason it reads one model added in the same way, but then trying to update it fails with the same error.

My guess is that I need to configure whatever Continuum uses for a SQLAlchemy session to point to the existing one configured in Pyramid, but I'm not sure. Am I getting warm?

2

There are 2 answers

0
user3113357 On BEST ANSWER

You're generating a session when you call:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))

but not binding it to an engine. Your pyramid template, pyramid_basemodel, is already generating a session for you and binding it to the engine.

Try removing the DBSession and using Session imported from pyramid_basemodel.

0
zupo On

FWIW, if anyone these days is looking how to make SQLAlchemy-Continuum work with Pyramid, here's how you do it:

Assuming you have followed the official Pyramid tutorial is the following:

  • install SQLAlchemy-Continuum
  • add make_versioned(user_cls=None) to the top of models/__init__.py
  • add __versioned__ = {} to MyModel class in models/mymodel.py

And that's it!

I've created a repo that has all the needed bits in place: https://github.com/zupo/tutorial/tree/exploration/sqlalchemy-continuum