iro/model/dbdefer.py
author Sandro Knauß <knauss@netzguerilla.net>
Mon, 13 Feb 2012 22:16:26 +0100
branchdevel
changeset 155 ff1edf7c1329
parent 151 ff8448fb07e7
child 258 0a5eb5aac0be
permissions -rw-r--r--
dbdefer now can be used for functions with no other argument than session

from decorator import FunctionMaker
import sqlalchemy

from .pool import runInDBPool
from .utils import WithSession

import inspect

class DBDefer(object):
    '''a twisted sqlalchemy connector this Decorator adds a session parameter, with a valid session connection'''
    def __init__(self, engine, autocommit=False):
        self.autocommit=autocommit
        self.engine = engine

    def __call__(self, func):
        @runInDBPool
        def wrapper(func,*a, **kw):
            i = argspec.args.index("session")
            ab = a[:i]
            ae = a[i:-1]
            if isinstance(a[-1],sqlalchemy.orm.session.Session):
                al = ab + (a[-1],) + ae
                ret = func(*al, **kw)
                if self.autocommit:
                    a[-1].commit()
                return ret
            else:
                with WithSession(self.engine, self.autocommit) as session:
                    al = ab + (session,) + ae
                    return func(*al, **kw)

        caller=func
        argspec = inspect.getargspec(caller)
        args =[i for i in argspec.args if i != "session" ]
        sargs=", ".join(args)       
        if sargs:
            sargs+=", session"
        else:
            sargs="session"
        defaults = argspec.defaults
        if not defaults:
            defaults = (None,)
        else:
            defaults += (None,)
        evaldict = caller.func_globals.copy()
        evaldict['_call_'] = func
        evaldict['decorator'] = wrapper
        wrap = FunctionMaker.create(
              '%s(%s)' % (caller.__name__, sargs), 
              'return decorator(_call_, %s)' % sargs,
              evaldict, defaults=defaults, undecorated=caller, __wrapped__=caller,
              doc=caller.__doc__, module=caller.__module__, addsource=True)
        return wrap

dbdefer=DBDefer(None)

def setEngine(engine,autocommit=False): 
    dbdefer.engine = engine
    dbdefer.autocommit = autocommit