# HG changeset patch # User Sandro Knauß # Date 1327672919 -3600 # Node ID 1ed072cc6793597de16936c98f2c539ccb2c04b4 # Parent abdece5f6be6e645b39884ac8936ce1ddc4ab924 reconstructing validate decorator diff -r abdece5f6be6 -r 1ed072cc6793 iro/controller/viewinterface.py --- a/iro/controller/viewinterface.py Thu Jan 26 01:23:04 2012 +0100 +++ b/iro/controller/viewinterface.py Fri Jan 27 15:01:59 2012 +0100 @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- from ..model.user import with_user - +from ..validate import validate, boolean, validateHash class Interface(object): '''class for a xmlrpc user ''' + @validate(kwd="detailed", func=boolean, need=False) + @validate(kwd="id", func=validateHash, need=False) @with_user def status(self, user, id=None, detailed=False): '''Gibt den aktuellen Status eines Auftrages oder Mehreren zurück. @@ -21,7 +23,10 @@ ''' - return str(user) + if id or detailed: + return str(user),id,detailed + else: + return str(user) #return user.status(id,detailed) return "" diff -r abdece5f6be6 -r 1ed072cc6793 iro/model/user.py --- a/iro/model/user.py Thu Jan 26 01:23:04 2012 +0100 +++ b/iro/model/user.py Fri Jan 27 15:01:59 2012 +0100 @@ -1,9 +1,11 @@ from inspect import getcallargs +from functools import wraps from .schema import User from .utils import DBDefer from ..validate import vuserhash, validate from ..error import UserNotFound, InterfaceException + dbdefer=DBDefer(None) def setEngine(engine,autocommit=False): @@ -11,7 +13,7 @@ dbdefer.autocommit = autocommit @dbdefer -@validate(apikey=vuserhash) +@validate(kwd="apikey", func=vuserhash) def getuser(apikey, session): user = session.query(User).filter_by(apikey=apikey).first() if user is None: @@ -20,8 +22,9 @@ return user def with_user(f): - def new_f(*args,**kargs): - kp=getcallargs(f,*args,**kargs) + @wraps(f) + def wrapper(*args,**kargs): + kp=getcallargs(wrapper.original,*args,**kargs) try: apikey = kp["user"] except KeyError: @@ -33,8 +36,10 @@ d=getuser(apikey=apikey) return d.addCallback(_gotResult) - - new_f.__name__ = f.__name__ - return new_f + try: + wrapper.original=f.original + except AttributeError: + wrapper.original=f + return wrapper diff -r abdece5f6be6 -r 1ed072cc6793 iro/model/utils.py --- a/iro/model/utils.py Thu Jan 26 01:23:04 2012 +0100 +++ b/iro/model/utils.py Fri Jan 27 15:01:59 2012 +0100 @@ -3,6 +3,8 @@ from twisted.internet import threads from twisted.python.threadpool import ThreadPool +from functools import wraps + POOL_SIZE=5 #how many threads should the db connector pool should have class Data: @@ -19,6 +21,7 @@ def run_in_db_thread(f): """Decorator to run DB queries in Twisted's thread pool""" + @wraps(f) def wrapper(*args, **kwargs): return threads.deferToThreadPool(d.reactor, d.pool, f, *args, **kwargs) return wrapper @@ -50,6 +53,7 @@ def __call__(self, func): @run_in_db_thread + @wraps(func) def wrapper(*args, **kwargs): with WithSession(self.engine, self.autocommit) as session: return func(*args, session=session, **kwargs) diff -r abdece5f6be6 -r 1ed072cc6793 iro/validate.py --- a/iro/validate.py Thu Jan 26 01:23:04 2012 +0100 +++ b/iro/validate.py Fri Jan 27 15:01:59 2012 +0100 @@ -1,27 +1,57 @@ import re +from functools import wraps + from inspect import getcallargs from .error import ValidateException -def vuserhash(hash,field): - '''vailidate function for userhash''' - if not re.match(r'^[a-f0-9]{15,}$', hash.lower()): +def boolean(value, field): + t=[True,"true",1] + f=[False,"false",0] + if value in t: + return True + elif value in f: + return False + else: + raise ValidateException(field=field, msg='%s is not boolean' % field) + + +def validateHash(value,field,minlength=None,maxlength=None): + if not re.match(r'^[a-f0-9]*$', value.lower()): raise ValidateException(field=field) - return True + if minlength and len(value)maxlength: + raise ValidateException(field=field) + return value -def validate(**kargs): +def vuserhash(value,field): + '''vailidate function for userhash''' + return validateHash(value,field,minlength=15,maxlength=15) + +def validate(kwd,func, need=True,*args,**kargs): '''validate decorator use it like this: - @validate(userhash=vuserhash) + @validate(kwd=userhash, func=vuserhash) f(userhash) - that will validate usrhah with the function vuserhash. + that will validate usrhash with the function vuserhash. Every validate function should raise an Exception, if the the value is not valid''' def v(f): + @wraps(f) def new_f(*a,**k): - kp=getcallargs(f,*a,**k) - for i in kargs: - kargs[i](kp[i],i) - return f(*a,**k) - new_f.__name__ = f.__name__ + kp=getcallargs(new_f.original,*a,**k) + try: + if need or kp[kwd] is not None: + kp[kwd] = func(kp[kwd],kwd,*args,**kargs) + else: + kp[kwd] = None + except KeyError: + if need: + raise ValidateException(field=kwd,msg="%s is nessasary"%kwd) + return f(**kp) + try: + new_f.original=f.original + except AttributeError: + new_f.original=f return new_f return v diff -r abdece5f6be6 -r 1ed072cc6793 tests/xmlrpc.py --- a/tests/xmlrpc.py Thu Jan 26 01:23:04 2012 +0100 +++ b/tests/xmlrpc.py Fri Jan 27 15:01:59 2012 +0100 @@ -52,7 +52,7 @@ def __rpc2(self): return ServerProxy('http://localhost:7080/RPC2') - + def testDebugHello(self): '''simple test for the connection to xmlrpc server''' ret=self.__debug().hello() @@ -66,6 +66,13 @@ def testStatus(self): ret = self.__rpc2().status('abcdef123456789') self.failUnlessEqual(ret, "") + self.failUnlessEqual(self.__rpc2().status('abcdef123456789','abcde'), ["",'abcde',False]) + self.failUnlessEqual(self.__rpc2().status('abcdef123456789','abcde', True), ["",'abcde', True]) + self.failUnlessEqual(self.__rpc2().status('abcdef123456789', '', 'true'), ["", '', True]) + self.failUnlessEqual(self.__rpc2().status('abcdef123456789', '', 'false'), "") + self.failUnlessEqual(self.__rpc2().status('abcdef123456789', '', 0), "") + self.failUnlessEqual(self.__rpc2().status('abcdef123456789', '', 1), ["", '', True]) + def testNoSuchUser(self): '''a unknown user should raise a UserNotNound Exception @@ -85,7 +92,7 @@ self.failUnlessEqual(exc.faultCode, 8001) self.failUnlessEqual(exc.faultString, "procedure nosuchmethod not found") - def testValidation(self): + def testValidationFault(self): '''a validate Exception should be translated to a xmlrpclib.Fault.''' with self.assertRaises(Fault) as fault: self.__rpc2().status('xxx') @@ -93,8 +100,6 @@ self.failUnlessEqual(exc.faultCode, 700) self.failUnlessEqual(exc.faultString, "Validation of 'apikey' failed.") - - def startReactor(engine): """starts the Rector with a special debug Clild, so that the reactor can be stopped remotly. """ from twisted.internet import reactor