4 commandline_options = []
5 help = "Add a new rule"
8 if (len(commandline_options!=2)):
9 raise Exception("Internal error: each command must supply 2 command line options")
12 def __call__(self, option, opt_str, value, parser, *args, **kwargs):
17 def help(self, indent = " "):
19 Text documentation for the method.
22 (min_args, max_args, defaults) = self.args()
24 text = "%s(%s) -> %s\n\n" % (self.name, ", ".join(max_args), xmlrpc_type(self.returns))
26 text += "Description:\n\n"
27 lines = [indent + line.strip() for line in self.__doc__.strip().split("\n")]
28 text += "\n".join(lines) + "\n\n"
30 def param_text(name, param, indent, step):
32 Format a method parameter.
37 # Print parameter name
40 text += name.ljust(param_offset - len(indent))
42 param_offset = len(indent)
44 # Print parameter type
45 param_type = python_type(param)
46 text += xmlrpc_type(param_type) + "\n"
48 # Print parameter documentation right below type
49 if isinstance(param, Parameter):
50 wrapper = textwrap.TextWrapper(width = 70,
51 initial_indent = " " * param_offset,
52 subsequent_indent = " " * param_offset)
53 text += "\n".join(wrapper.wrap(param.doc)) + "\n"
58 # Indent struct fields and mixed types
59 if isinstance(param, dict):
60 for name, subparam in param.iteritems():
61 text += param_text(name, subparam, indent + step, step)
62 elif isinstance(param, Mixed):
63 for subparam in param:
64 text += param_text(name, subparam, indent + step, step)
65 elif isinstance(param, (list, tuple, set)):
66 for subparam in param:
67 text += param_text("", subparam, indent + step, step)
71 text += "Parameters:\n\n"
72 for name, param in zip(max_args, self.accepts):
73 text += param_text(name, param, indent, indent)
75 text += "Returns:\n\n"
76 text += param_text("", self.returns, indent, indent)
84 ((arg1_name, arg2_name, ...),
85 (arg1_name, arg2_name, ..., optional1_name, optional2_name, ...),
86 (None, None, ..., optional1_default, optional2_default, ...))
88 That represents the minimum and maximum sets of arguments that
89 this function accepts and the defaults for the optional arguments.
92 # Inspect call. Remove self from the argument list.
93 max_args = self.call.func_code.co_varnames[1:self.call.func_code.co_argcount]
94 defaults = self.call.func_defaults
98 min_args = max_args[0:len(max_args) - len(defaults)]
99 defaults = tuple([None for arg in min_args]) + defaults
101 return (min_args, max_args, defaults)
103 def type_check(self, name, value, expected, args):
105 Checks the type of the named value against the expected type,
106 which may be a Python type, a typed value, a Parameter, a
107 Mixed type, or a list or dictionary of possibly mixed types,
108 values, Parameters, or Mixed types.
110 Extraneous members of lists must be of the same type as the
111 last specified type. For example, if the expected argument
112 type is [int, bool], then [1, False] and [14, True, False,
113 True] are valid, but [1], [False, 1] and [14, True, 1] are
116 Extraneous members of dictionaries are ignored.
119 # If any of a number of types is acceptable
120 if isinstance(expected, Mixed):
121 for item in expected:
123 self.type_check(name, value, item, args)
125 except GeniInvalidArgument, fault:
129 # If an authentication structure is expected, save it and
130 # authenticate after basic type checking is done.
131 #if isinstance(expected, Auth):
136 # Get actual expected type from within the Parameter structure
137 if isinstance(expected, Parameter):
140 nullok = expected.nullok
141 expected = expected.type
147 expected_type = python_type(expected)
149 # If value can be NULL
150 if value is None and nullok:
153 # Strings are a special case. Accept either unicode or str
154 # types if a string is expected.
155 if expected_type in StringTypes and isinstance(value, StringTypes):
158 # Integers and long integers are also special types. Accept
159 # either int or long types if an int or long is expected.
160 elif expected_type in (IntType, LongType) and isinstance(value, (IntType, LongType)):
163 elif not isinstance(value, expected_type):
164 raise GeniInvalidArgument("expected %s, got %s" % \
165 (xmlrpc_type(expected_type),
166 xmlrpc_type(type(value))),
169 # If a minimum or maximum (length, value) has been specified
170 if expected_type in StringTypes:
171 if min is not None and \
172 len(value.encode(self.api.encoding)) < min:
173 raise GeniInvalidArgument, "%s must be at least %d bytes long" % (name, min)
174 if max is not None and \
175 len(value.encode(self.api.encoding)) > max:
176 raise GeniInvalidArgument, "%s must be at most %d bytes long" % (name, max)
177 elif expected_type in (list, tuple, set):
178 if min is not None and len(value) < min:
179 raise GeniInvalidArgument, "%s must contain at least %d items" % (name, min)
180 if max is not None and len(value) > max:
181 raise GeniInvalidArgument, "%s must contain at most %d items" % (name, max)
183 if min is not None and value < min:
184 raise GeniInvalidArgument, "%s must be > %s" % (name, str(min))
185 if max is not None and value > max:
186 raise GeniInvalidArgument, "%s must be < %s" % (name, str(max))
188 # If a list with particular types of items is expected
189 if isinstance(expected, (list, tuple, set)):
190 for i in range(len(value)):
191 if i >= len(expected):
192 j = len(expected) - 1
195 self.type_check(name + "[]", value[i], expected[j], args)
197 # If a struct with particular (or required) types of items is
199 elif isinstance(expected, dict):
200 for key in value.keys():
202 self.type_check(name + "['%s']" % key, value[key], expected[key], args)
203 for key, subparam in expected.iteritems():
204 if isinstance(subparam, Parameter) and \
205 subparam.optional is not None and \
206 not subparam.optional and key not in value.keys():
207 raise GeniInvalidArgument("'%s' not specified" % key, name)
209 #if auth is not None:
210 # auth.check(self, *args)