Beware of snakes and trailing commas…

Written by Johannes on May 31, 2013 Categories: Python, SQLAlchemy, Webdevelopment, Werkzeug

Your ads will be inserted here by

Easy AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

No here’s a nice way to shoot yourself in the foot with Python tuples. We all know Python tuples are constructed by commas, not round brackets. So

>>> 1,2,3,4
(1, 2, 3, 4)

but

>>> (1)
1

Most important

>>> 1,
(1,)

Those differences are subtle, but significant. So keep that in mind when working on something larger that just insists on breaking up and hurling insults at you and you would never suspect that you have made such a trivial mistake.

In my case I was trying to instantiate an SQLAlchemy scoped Session object in one module and trying to bind an engine to it in the initialization code of my app. The reason for this is to make it possible to easily exchange the engine object, in particular for unit tests, that should typically operate on a separate test database or in memory database. What I did was

Your ads will be inserted here by

Easy AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

# core/db_session.py
from sqlalchemy.orm import scoped_session, sessionmaker
session_factory = sessionmaker(autocommit=False, autoflush=False,)
db_session = scoped_session(session_factory)
 
# runserver.py
from core.app import settings, app
from sqlalchemy import create_engine
from core.db_session import db_session
 
db_engine = create_engine('sqlite:////tmp/cc.sqlite', convert_unicode=True),
db_session.configure(bind=db_engine)
 
from werkzeug.serving import run_simple
 
if __name__ == '__main__':
    run_simple('127.0.0.1', 5000, app, use_debugger=True, use_reloader=True)

roughly following the SQLAlchemy documentation.

Werkzeugs excellent debugging tool gave me an impressive stack trace, telling me something about tuples having no “contextual context”. Now I know I should have seen the elephant in the room, but I was so immersed in thread locals and Werkzeug Local, LocalManagers and LocalStacks that I was almost 100% positive I was experiencing some major scoping issue. So I spent half the morning trying various different approaches of rearranging my code, thinking up hacky ways to monkeypatch (yes, I was that desperate) the way the db_session was fed into my BaseModel class.

Buuuuut… the solution was so simple. Instead of

db_engine = create_engine('sqlite:////tmp/cc.sqlite', convert_unicode=True),

I simply had to write

db_engine = create_engine('sqlite:////tmp/cc.sqlite', convert_unicode=True)

I wonder how that comma wound up there in the first place…

No Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre user="" computer="" escaped="">