summaryrefslogtreecommitdiffstats
path: root/nova/validate.py
blob: 21f4ed286bd50a596b4ee040d79f00c44fa4643d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

"""
  Decorators for argument validation, courtesy of 
  http://rmi.net/~lutz/rangetest.html
"""

def rangetest(**argchecks):                 # validate ranges for both+defaults
    def onDecorator(func):                  # onCall remembers func and argchecks
        import sys
        code = func.__code__ if sys.version_info[0] == 3 else func.func_code
        allargs  = code.co_varnames[:code.co_argcount]
        funcname = func.__name__
        
        def onCall(*pargs, **kargs):
            # all pargs match first N args by position
            # the rest must be in kargs or omitted defaults
            positionals = list(allargs)
            positionals = positionals[:len(pargs)]

            for (argname, (low, high)) in argchecks.items():
                # for all args to be checked
                if argname in kargs:
                    # was passed by name
                    if float(kargs[argname]) < low or float(kargs[argname]) > high:
                        errmsg = '{0} argument "{1}" not in {2}..{3}'
                        errmsg = errmsg.format(funcname, argname, low, high)
                        raise TypeError(errmsg)

                elif argname in positionals:
                    # was passed by position
                    position = positionals.index(argname)
                    if float(pargs[position]) < low or float(pargs[position]) > high:
                        errmsg = '{0} argument "{1}" with value of {4} not in {2}..{3}'
                        errmsg = errmsg.format(funcname, argname, low, high, pargs[position])
                        raise TypeError(errmsg)
                else:
                    pass

            return func(*pargs, **kargs)    # okay: run original call
        return onCall
    return onDecorator


def typetest(**argchecks):
    def onDecorator(func):
        import sys
        code = func.__code__ if sys.version_info[0] == 3 else func.func_code
        allargs  = code.co_varnames[:code.co_argcount]
        funcname = func.__name__
    
        def onCall(*pargs, **kargs):
            positionals = list(allargs)[:len(pargs)]
            for (argname, typeof) in argchecks.items():
                if argname in kargs:
                    if not isinstance(kargs[argname], typeof):
                        errmsg = '{0} argument "{1}" not of type {2}'
                        errmsg = errmsg.format(funcname, argname, typeof)
                        raise TypeError(errmsg)
                elif argname in positionals:
                    position = positionals.index(argname)
                    if not isinstance(pargs[position], typeof):
                        errmsg = '{0} argument "{1}" with value of {2} not of type {3}'
                        errmsg = errmsg.format(funcname, argname, pargs[position], typeof)
                        raise TypeError(errmsg)
                else:
                    pass
            return func(*pargs, **kargs)
        return onCall
    return onDecorator