Thanks for sharing this Franck! On 3 Hun, 21:25, Franck <[email protected]> wrote: > Hi, > > Actually I pretty much disagree with the pattern provided here > :http://webpy.org/cookbook/sqlalchemy > > <http://webpy.org/cookbook/sqlalchemy>Here's why : according to the > documentation, it's ok to instanciate *scoped_session* once : then, why use > a load hook to bind it at every request > ?http://www.sqlalchemy.org/docs/orm/session.html#sqlalchemy.orm.scoped... > > <http://www.sqlalchemy.org/docs/orm/session.html#sqlalchemy.orm.scoped...>The > argument you supply to scoped_session constructor, i.e. * > sessionmaker(bind=engine)*, is actually a session factory which is called in > the background every time a fresh session is needed. > Here's some sample code which demonstrates that : > > ** meta.py ** > > class SessionFactory(object): > > def __init__(self, engine_factory): > self.engine_factory = engine_factory > self.sessionmaker = sessionmaker() > > def __call__(self): > engine = self.engine_factory() > self.sessionmaker.configure(bind = engine) > session = self.sessionmaker() > web.debug("[MODEL] Sucessfully instanciated DB session %s bound to > %s" %(session, engine)) > return session > > def init_orm(engine_factory): > return scoped_session(SessionFactory(engine_factory)) > > def init_engine(dsn, echo): > engine = create_engine(dsn, echo = echo) > web.debug("[MODEL] Successfully instantiated DB engine (DSN = %s, echo = > %s)" %(dsn, echo)) > return engine > > This code allows me to : > > 1) Call init_engine once (or several times in the case when I need to switch > engine) and bind the result to some global variable (namely > web.config.engine) > 2) Call init_orm once like this : web.config.orm = meta.init_orm(lambda : > web.config.engine) > > Wrapping code : > > ** application.py ** > > class WebApplication(web.application): > """ Web application with additional features (configuration > management...) """ > > def __init__(self, mapping, fvars): > > # Parent constructor > web.application.__init__(self, mapping, fvars) > > # The ORM is bound once since it dynamically loads the engine from > the configuration > web.config.orm = meta.init_orm(lambda : web.config.engine) > > # SQL Alchemy processor > self.add_processor(_sqlalchemy_processor) > > def configure(self, config_filename): > > # Reads the configuration file > config_file = ConfigParser.ConfigParser() > config_file.read(config_filename) > > # Initializes the components > web.config.engine = meta.init_engine(config_file.get("sqlalchemy", > "dsn"), config_file.getboolean("sqlalchemy", "echo")) > > def _sqlalchemy_processor(handler): > """ Makes sure a commit appends at the end of each request """ > try: > return handler() > except web.HTTPError: > config.orm.commit() > raise > except: > config.orm.rollback() > raise > finally: > config.orm.commit() > > Of course this pattern can be simplified if the *engine* should be defined > once (very common scenario). > > Actually I'm very eager to hear feedback about my pattern since I asked > myself the same questions as Ben. > Is the use of *web.config* OK ? Other frameworks tend to recommend the use > of a global shared *scoped_session* but I dislike that. > > Thanks > Franck > > > > > > > > On Fri, Jun 3, 2011 at 3:47 AM, Ben Hearsum <[email protected]> wrote: > > I ended up finding a solution to this: setting web.ctx.orm manually in > > setUp, and removing it in tearDown. I ended up with a Mixin class for > > my tests that looks like this: > > class > > TestDBMixin(object): > > def > > setUp(self): > > > db.Base.metadata.create_all(engine) > > web.ctx.orm = > > scoped_session(sessionmaker(bind=engine)) > > > def > > tearDown(self): > > > db.Base.metadata.drop_all(engine) > > web.ctx.orm = > > None > > > And test classes that look like this: > > class TestUser(unittest.TestCase, TestDBMixin): > > def setUp(self): > > TestDBMixin.setUp(self) > > > def tearDown(self): > > TestDBMixin.tearDown(self) > > > def > > test_add(self): > > u = User('name') > > u.add('pass') > > > On 2 Hun, 00:04, Ben Hearsum <[email protected]> wrote: > > > Hi, > > > > I'm writing a web application with web.py and sqlalchemy. I've > > usedhttp://webpy.org/cookbook/sqlalchemyasa guide to get me up and > > > running. As well as code like the tutorial, I've got Models that have > > > various methods that query the database, and Controllers that consume > > > them. The methods in my models like something like this: > > > def add(self): > > > web.ctx.orm.add(User('blah')) > > > > They work perfectly fine when called by a Controller, presumably > > > because the context is flushed out at that time. However, tests always > > > fail with: > > > AttributeError: 'ThreadedDict' object has no attribute 'orm' > > > > I've tried all sorts of various hacks and tricks to try and make this > > > work, to no avail. I _could_ drop all of failing tests, and rely on > > > the associated Controller tests to catch any issues, but this seems > > > suboptimal. > > > > Is there a known solution/pattern web.py + sqlalchemy + testing? > > > -- > > You received this message because you are subscribed to the Google Groups > > "web.py" group. > > To post to this group, send email to [email protected]. > > To unsubscribe from this group, send email to > > [email protected]. > > For more options, visit this group at > >http://groups.google.com/group/webpy?hl=en.
-- You received this message because you are subscribed to the Google Groups "web.py" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/webpy?hl=en.
