5 commandline_options = []
6 help = "Add a new rule"
9 if (len(commandline_options!=2)):
10 raise Exception("Internal error: each command must supply 2 command line options")
13 def __call__(self, option, opt_str, value, parser, *args, **kwargs):
18 def help(self, indent = " "):
20 Text documentation for the method.
23 (min_args, max_args, defaults) = self.args()
25 text = "%s(%s) -> %s\n\n" % (self.name, ", ".join(max_args), xmlrpc_type(self.returns))
27 text += "Description:\n\n"
28 lines = [indent + line.strip() for line in self.__doc__.strip().split("\n")]
29 text += "\n".join(lines) + "\n\n"
31 def param_text(name, param, indent, step):
33 Format a method parameter.
38 # Print parameter name
41 text += name.ljust(param_offset - len(indent))
43 param_offset = len(indent)
45 # Print parameter type
46 param_type = python_type(param)
47 text += xmlrpc_type(param_type) + "\n"
49 # Print parameter documentation right below type
50 if isinstance(param, Parameter):
51 wrapper = textwrap.TextWrapper(width = 70,
52 initial_indent = " " * param_offset,
53 subsequent_indent = " " * param_offset)
54 text += "\n".join(wrapper.wrap(param.doc)) + "\n"
59 # Indent struct fields and mixed types
60 if isinstance(param, dict):
61 for name, subparam in param.items():
62 text += param_text(name, subparam, indent + step, step)
63 elif isinstance(param, Mixed):
64 for subparam in param:
65 text += param_text(name, subparam, indent + step, step)
66 elif isinstance(param, (list, tuple, set)):
67 for subparam in param:
68 text += param_text("", subparam, indent + step, step)
72 text += "Parameters:\n\n"
73 for name, param in zip(max_args, self.accepts):
74 text += param_text(name, param, indent, indent)
76 text += "Returns:\n\n"
77 text += param_text("", self.returns, indent, indent)
85 ((arg1_name, arg2_name, ...),
86 (arg1_name, arg2_name, ..., optional1_name, optional2_name, ...),
87 (None, None, ..., optional1_default, optional2_default, ...))
89 That represents the minimum and maximum sets of arguments that
90 this function accepts and the defaults for the optional arguments.
93 # Inspect call. Remove self from the argument list.
94 max_args = self.call.__code__.co_varnames[1:self.call.__code__.co_argcount]
95 defaults = self.call.__defaults__
99 min_args = max_args[0:len(max_args) - len(defaults)]
100 defaults = tuple([None for arg in min_args]) + defaults
102 return (min_args, max_args, defaults)
104 def type_check(self, name, value, expected, args):
106 Checks the type of the named value against the expected type,
107 which may be a Python type, a typed value, a Parameter, a
108 Mixed type, or a list or dictionary of possibly mixed types,
109 values, Parameters, or Mixed types.
111 Extraneous members of lists must be of the same type as the
112 last specified type. For example, if the expected argument
113 type is [int, bool], then [1, False] and [14, True, False,
114 True] are valid, but [1], [False, 1] and [14, True, 1] are
117 Extraneous members of dictionaries are ignored.
120 # If any of a number of types is acceptable
121 if isinstance(expected, Mixed):
122 for item in expected:
124 self.type_check(name, value, item, args)
126 except SfaInvalidArgument as fault:
130 # If an authentication structure is expected, save it and
131 # authenticate after basic type checking is done.
132 #if isinstance(expected, Auth):
137 # Get actual expected type from within the Parameter structure
138 if isinstance(expected, Parameter):
141 nullok = expected.nullok
142 expected = expected.type
148 expected_type = python_type(expected)
150 # If value can be NULL
151 if value is None and nullok:
154 # Strings are a special case. Accept either unicode or str
155 # types if a string is expected.
156 if issubclass(expected_type, str) and isinstance(value, str):
159 # Integers and long integers are also special types. Accept
160 # either int or long types if an int or long is expected.
161 elif expected_type in (IntType, LongType) and isinstance(value, (IntType, LongType)):
164 elif not isinstance(value, expected_type):
165 raise SfaInvalidArgument("expected %s, got %s" % \
166 (xmlrpc_type(expected_type),
167 xmlrpc_type(type(value))),
170 # If a minimum or maximum (length, value) has been specified
171 if issubclass(expected_type, str):
172 if min is not None and \
173 len(value.encode(self.api.encoding)) < min:
174 raise SfaInvalidArgument("%s must be at least %d bytes long" % (name, min))
175 if max is not None and \
176 len(value.encode(self.api.encoding)) > max:
177 raise SfaInvalidArgument("%s must be at most %d bytes long" % (name, max))
178 elif expected_type in (list, tuple, set):
179 if min is not None and len(value) < min:
180 raise SfaInvalidArgument("%s must contain at least %d items" % (name, min))
181 if max is not None and len(value) > max:
182 raise SfaInvalidArgument("%s must contain at most %d items" % (name, max))
184 if min is not None and value < min:
185 raise SfaInvalidArgument("%s must be > %s" % (name, str(min)))
186 if max is not None and value > max:
187 raise SfaInvalidArgument("%s must be < %s" % (name, str(max)))
189 # If a list with particular types of items is expected
190 if isinstance(expected, (list, tuple, set)):
191 for i in range(len(value)):
192 if i >= len(expected):
193 j = len(expected) - 1
196 self.type_check(name + "[]", value[i], expected[j], args)
198 # If a struct with particular (or required) types of items is
200 elif isinstance(expected, dict):
201 for key in list(value.keys()):
203 self.type_check(name + "['%s']" % key, value[key], expected[key], args)
204 for key, subparam in expected.items():
205 if isinstance(subparam, Parameter) and \
206 subparam.optional is not None and \
207 not subparam.optional and key not in list(value.keys()):
208 raise SfaInvalidArgument("'%s' not specified" % key, name)
210 #if auth is not None:
211 # auth.check(self, *args)