Source code for iro.validate

# Copyright (c) 2012 netzguerilla.net <iro@netzguerilla.net>
# 
# This file is part of Iro.
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
# #Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from twisted.internet import defer

import re
from decorator import decorator
try:
    from inspect import getcallargs
except ImportError:
    from .inspect_getcallargs import getcallargs
import types

from .error import ValidateException, InvalidTel, InvalidMail
from .telnumber import Telnumber

[docs]def vBool(value, field): '''Validate function for boolean values :return: **value** :raises: :exc:`iro.error.ValidateException` ''' t=[True, 1, "true", "True", "TRUE"] f=[False, 0, "false", "False", "FALSE"] if value in t: return True elif value in f: return False else: raise ValidateException(field=field, msg='%s is not boolean' % field)
[docs]def vNumber(value,field, nval, minv=None, maxv=None, none_allowed=False): """validate function for integer values. :param integer minv: minimum value :param integer maxv: maximum value :param func nval: function that give back a number :param boolean none_allowed: is None or empty string allowed :return: **value** :raises: :exc:`iro.error.ValidateException` """ if none_allowed and value in [None,'']: return None try: ret = nval(value) except ValueError: raise ValidateException(field=field) except TypeError: raise ValidateException(field=field) if minv is not None and ret < minv: raise ValidateException(field=field) if maxv is not None and ret > maxv: raise ValidateException(field=field) return ret
[docs]def vInteger(value, field, minv=None, maxv=None, none_allowed=False): """validate function for integer values. :param integer minv: minimum value :param integer maxv: maximum value :param boolean none_allowed: is None or empty string allowed :return: **value** :raises: :exc:`iro.error.ValidateException` see also :func:vNumber """ return vNumber(value, field, int, minv, maxv, none_allowed)
[docs]def vFloat(value, field, minv=None, maxv=None, none_allowed=False): """validate function for float values. :param integer minv: minimum value :param integer maxv: maximum value :param boolean none_allowed: is None or empty string allowed :return: **value** :raises: :exc:`iro.error.ValidateException` see also :func:vNumber """ return vNumber(value, field, float, minv, maxv, none_allowed)
[docs]def vHash(value,field,minlength=None,maxlength=None): '''Validate function for hash values :param integer minlength: minimum length of value string :param integer maxlength: maximum length of value string :return: **value** :raises: :exc:`iro.error.ValidateException` ''' if not re.match(r'^[a-f0-9]*$', value.lower()): raise ValidateException(field=field) if minlength and len(value)<minlength: raise ValidateException(field=field) if maxlength and len(value)>maxlength: raise ValidateException(field=field) return value.lower()
[docs]def vTel(value,field): '''Validator for telefon numbers :return: **value** :raises: :exc:`iro.error.InvalidTel` ''' ret = [] for v in value: try: tel=Telnumber(v) if tel not in ret: ret.append(tel) except InvalidTel, e: e.field=field raise e return ret
[docs]def vEmail(value, field, allowString=True, allowList=True): '''validator for emailadresses (see wikipeda for strange mailadresses and RFC3696) valid: - "very.(),:;<>[]\\".VERY.\\"very@\\\ \\"very\\".unusual"@strange.example.com - ""@example.org - "very.unusual.@.unusual.com"@example.com' not valid: - Abc.@example.com - Abc..123@example.com - thisis."notallowed@example.com - this\\ still\\"not\\allowed@example.com :param boolean allowString: value can be a string -> a string is returned :param boolean allowList: value is a a list -> a list is returned :return: **value** :raises: :exc:`iro.error.ValidateException`, :exc:`iro.error.InvalidMail` ''' ret = [] str_=False if type(value) is types.StringType: if not allowString: raise ValidateException('%s must be a list of email addresses.'%field) str_=True value=[value] elif not allowList: raise ValidateException('%s must be a email address - No list of email addresses.'%field) for v in value: parts= re.match(r'^(.*)@(.+?)$',v) if not parts: raise InvalidMail(v,field) local=parts.group(1) domain=parts.group(2) if not re.match(r'^(\[[0-9\.]{7,16}\]|\[[0-9a-f:]{3,}\]|([a-z0-9+\-%_]+\.)+[a-z]{2,6})$',domain.lower()): raise InvalidMail(v,field) if local == "": ret.append(v) continue if local.startswith(".") or local.endswith("."): raise InvalidMail(v,field) unquote = True parts = local.split('"') c=0 i=0 for part in parts: if unquote and part != "": #unquoted is not allowd so much if not re.match(r'^[^\\,\[\];\(\)@<>: ]+$',part) or ".." in part: raise InvalidMail(v,field) if i == 0: if unquote and part != "" and len(parts) > 1 and part[-1] != '.': #quoted parts must be seperated by a dot raise InvalidMail(v,field) unquote = not unquote c+=1 elif part == '' or part[-1] != "\\": if unquote and part != "": #quoted parts must be seperated by a dot if part[0] != ".": raise InvalidMail(v,field) if i < len(parts)-1 and part[-1] != '.': raise InvalidMail(v,field) unquote = not unquote c += 1 i += 1 if c%2 == 0 and c > 1: #no single quote allowed raise InvalidMail(v,field) if v not in ret: ret.append(v) if str_: ret=ret[0] return ret
[docs]def validate(kwd,func, need=True,*args,**kargs): '''validate decorator. :param string kwd: keyword to validate :param func func: validate function :param boolean need: ``False`` -- ``None`` is a valid value for kwd :params args: arguments for validate function :params kargs: keyword arguments for validate function .. note:: this decorator can handle function that returns a defer object. use it like this:: @validate(kwd=userhash, func=vuserhash) f(userhash) that will validate ``userhash`` with the function **vuserhash**. Every validate function should raise an Exception, if the the value is not valid. All **args** and **kargs** are used to call the validate function. if **need** is True, the kwd can't be `None`. ''' @decorator def v(f,*a,**k): kp=getcallargs(f,*a,**k) def dfunc(*x,**y): return None try: if kp[kwd] is not None: dfunc=func elif need: raise ValidateException(field=kwd,msg="%s is nessasary"%kwd) except KeyError: if need: raise ValidateException(field=kwd,msg="%s is nessasary"%kwd) kp[kwd] = None def _gotResult(value): kp[kwd] = value e = defer.maybeDeferred(f,**kp) return e d = defer.maybeDeferred(dfunc, kp[kwd],kwd,*args,**kargs) return d.addCallback(_gotResult) return v