-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcheckargs.py
More file actions
152 lines (117 loc) · 4.58 KB
/
Copy pathcheckargs.py
File metadata and controls
152 lines (117 loc) · 4.58 KB
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import types
from pprint import pprint
class BadArgument(Exception):
def __init__(self, value):
self.parameter = value
def __str__(self):
return repr(self.parameter)
class check_args(object):
"""
check_args allows you to simply type check arguments passed
into a function, without writing a lot of error prone
type checking code.
>>> @check_args(str,int)
... def dostuff(name, age):
... print "name = %s age = %d" % (name,age)
>>> dostuff("Dave",5)
name = Dave age = 5
"""
def __init__(self, *args):
self.types = args
def __call__(self, function):
def check_arguments(*args):
for arg, curtype in zip(args,self.types):
if type(arg) != curtype:
raise BadArgument(str(arg) + " is not of type " + str(curtype))
function(*args)
return check_arguments
class check_args_ex(object):
"""
Extended version of check_args, you can allow multiple types
for each argument (both int and float for instance), and
also specify conditions for each argument.
conditional checking can check to see if an integer is
within an xrange, or in a list/tuple/dictionary.
each argument for the decorated function is specified
as a list or tuple, the first item is either a type, or
list of types, the second is a conditional or a
list of conditionals.
WARNING: If you want to pass in a single list or tuple,
it must be enclosed in another list or tuple
>>> @check_args_ex(((str, unicode), None),
... (int, (xrange(10), (5,9))),
... ((str, unicode), {'Jan':1, 'Feb':1, 'Mar':1, 'Apr':1, 'May':1}))
... def dostuff2(name, age, month):
... print "name = %s age = %d month = %s" % (name,age,month)
>>> dostuff2("Dave",5,'May')
name = Dave age = 5 month = May
>>> dostuff2("Dave",12,'May')
Traceback (most recent call last):
...
BadArgument: '12 is not in xrange(10)'
>>> dostuff2("Dave",9,'Mayx')
Traceback (most recent call last):
...
BadArgument: "Mayx is not in {'Jan': 1, 'Apr': 1, 'Mar': 1, 'Feb': 1, 'May': 1}"
You can also use a function:
>>> def isvalid(arg):
... if arg in (1,2,5,"hello"):
... return True
... else:
... return False
>>> @check_args_ex(([],[isvalid]))
... def dostuff3(greeting):
... print greeting
>>> dostuff3('hello')
hello
>>> dostuff3('goodbye')
Traceback (most recent call last):
...
BadArgument: 'goodbye fails function isvalid'
"""
def __init__(self, *args):
self.types, self.conditions = zip(*args)
# the decorator depends on these being a list of lists (or tuples)...
self.types = [(i,) if type(i) not in (list, tuple) else i
for i in self.types]
self.conditions = [(i,) if type(i) not in (list, tuple) else i
for i in self.conditions]
def bail(self, error):
raise BadArgument(error)
condition_functions = {
types.FunctionType: lambda arg, condition, bail: \
(bail("%s fails function %s" % (str(arg),condition.func_name)) \
if not condition(arg) else 1),
types.NoneType: lambda arg, conditions, bail: \
True,
xrange: lambda arg, condition, bail: \
(bail("%s is not in %s" % (str(arg),str(condition)))
if arg not in condition else 1),
list: lambda arg, condition, bail: \
(bail("%s is not in %s" % (str(arg),str(condition)))
if arg not in condition else 1),
tuple: lambda arg, condition, bail: \
(bail("%s is not in %s" % (str(arg),str(condition)))
if arg not in condition else 1),
dict: lambda arg, condition, bail: \
(bail("%s is not in %s" % (str(arg),str(condition)))
if arg not in condition else 1)
}
def docondition(self, arg, condition):
self.condition_functions[type(condition)](arg,condition,self.bail)
def doconditionals(self, arg, conditionals):
[self.docondition(arg,conditional) for conditional in conditionals]
def dotypes(self, arg, types):
if len(types) and type(arg) not in types:
self.bail("%s is illegal type %s, legal types are: %s" % \
(str(arg), type(arg).__name__,
str([type(i).__name__ for i in types])))
def __call__(self, function):
def check_arguments(*args):
[self.dotypes(arg,types) for arg, types in zip(args,self.types)]
[self.doconditionals(arg,cond) for arg, cond in zip(args,self.conditions)]
function(*args)
return check_arguments
if __name__ == "__main__":
import doctest
doctest.testmod()