In Twisted there is a great thing known as `ContextTracker`:

> provides a way to pass arbitrary key/value data up and down a call
> stack without passing them as parameters to the functions on that call
> stack.

In my twisted web app in method `render_GET` I set a `uuid` parameter:

    call = context.call({"uuid": str(uuid.uuid4())}, self._render, request)

and then I call the `_render` method to do the actual work (work with db, 
render html, etc).

I create the `scoped_session` like this: 

    scopefunc = functools.partial(context.get, "uuid")
    Session = scoped_session(session_factory, scopefunc=scopefunc)

Now within any function calls of `_render` I can get session with:

    Session()

and at the end of `_render` I have to do `Session.remove()` to remove the 
session.

It works with my webapp and I think can work for other tasks.

This is completely standalone example, show how all it work together.

    from twisted.internet import reactor, threads
    from twisted.web.resource import Resource
    from twisted.web.server import Site, NOT_DONE_YET
    from twisted.python import context
    from sqlalchemy import create_engine, Column, Integer, String
    from sqlalchemy.orm import sessionmaker, scoped_session
    from sqlalchemy.ext.declarative import declarative_base
    import uuid
    import functools
    
    engine = create_engine(
        'sqlite:///test.sql',
        connect_args={'check_same_thread': False},
        echo=False)
    
    session_factory = sessionmaker(bind=engine)
    scopefunc = functools.partial(context.get, "uuid")
    Session = scoped_session(session_factory, scopefunc=scopefunc)
    Base = declarative_base()
    
    
    class User(Base):
        __tablename__ = 'users'
        id = Column(Integer, primary_key=True)
        name = Column(String)
    
    Base.metadata.create_all(bind=engine)
    
    
    class TestPage(Resource):
        isLeaf = True
    
        def render_GET(self, request):
            context.call({"uuid": str(uuid.uuid4())}, self._render, request)
            return NOT_DONE_YET
    
        def render_POST(self, request):
            return self.render_GET(request)
    
        def work_with_db(self):
            user = User(name="TestUser")
            Session.add(user)
            Session.commit()
            return user
    
        def _render(self, request):
            print "session: ", id(Session())
            d = threads.deferToThread(self.work_with_db)
    
            def success(result):
                html = "added user with name - %s" % result.name
                request.write(html.encode('UTF-8'))
                request.finish()
                Session.remove()
            call = functools.partial(context.call, {"uuid": scopefunc()}, 
success)
            d.addBoth(call)
            return d
    
    if __name__ == "__main__":
        reactor.listenTCP(8888, Site(TestPage()))
        reactor.run()


Still I dont know how to make it work with `defer.inLineCallback`, that I 
use everywhere in my code.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to