Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

event listener on scoped session

I am trying to add an event listener to the before_commit event of an SQLAlchemy Session inside of a Flask application. When doing the following

def before_commit(session):
    for item in session:
        if hasattr(item, 'on_save'):
            item.on_save(session)

event.listen(db.session, 'before_commit', before_commit)

I get

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "app.py", line 60, in <module>
    event.listen(db.session, 'before_commit', before_commit)
  File "C:\Python27\lib\site-packages\sqlalchemy\event\api.py", line 49, in listen
    _event_key(target, identifier, fn).listen(*args, **kw)
  File "C:\Python27\lib\site-packages\sqlalchemy\event\api.py", line 22, in _event_key
    tgt = evt_cls._accept_with(target)
  File "C:\Python27\lib\site-packages\sqlalchemy\orm\events.py", line 1142, in _accept_with
    "Session event listen on a scoped_session "
sqlalchemy.exc.ArgumentError: Session event listen on a scoped_session requires that its creation callable is associated with the Session class.

I can't find the correct way to register the event listener. The documentation actually states that event.listen() also accepts a scoped_session, but it seems like it does not?!


http://docs.sqlalchemy.org/en/latest/orm/events.html#sqlalchemy.orm.events.SessionEvents

The listen() function will accept Session objects as well as the return result of sessionmaker() and scoped_session().

Additionally, it accepts the Session class which will apply listeners to all Session instances globally.

like image 874
Niklas R Avatar asked Jan 24 '14 00:01

Niklas R


1 Answers

it means that the factory you've passed to scoped_session() must be a sessionmaker():

from sqlalchemy.orm import scoped_session, sessionmaker, sessionmaker
from sqlalchemy import event

# good

ss1 = scoped_session(sessionmaker())

@event.listens_for(ss1, "before_flush")
def evt(*arg, **kw):
    pass

# bad

ss2 = scoped_session(lambda: Session)

@event.listens_for(ss2, "before_flush")
def evt(*arg, **kw):
    pass
like image 99
zzzeek Avatar answered Sep 23 '22 18:09

zzzeek