3 from sfa.util.py23 import StringType
6 commandline_options = []
7 help = "Add a new rule"
10 if (len(commandline_options!=2)):
11 raise Exception("Internal error: each command must supply 2 command line options")
14 def __call__(self, option, opt_str, value, parser, *args, **kwargs):
19 def help(self, indent = " "):
21 Text documentation for the method.
24 (min_args, max_args, defaults) = self.args()
26 text = "%s(%s) -> %s\n\n" % (self.name, ", ".join(max_args), xmlrpc_type(self.returns))
28 text += "Description:\n\n"
29 lines = [indent + line.strip() for line in self.__doc__.strip().split("\n")]
30 text += "\n".join(lines) + "\n\n"
32 def param_text(name, param, indent, step):
34 Format a method parameter.
39 # Print parameter name
42 text += name.ljust(param_offset - len(indent))
44 param_offset = len(indent)
46 # Print parameter type
47 param_type = python_type(param)
48 text += xmlrpc_type(param_type) + "\n"
50 # Print parameter documentation right below type
51 if isinstance(param, Parameter):
52 wrapper = textwrap.TextWrapper(width = 70,
53 initial_indent = " " * param_offset,
54 subsequent_indent = " " * param_offset)
55 text += "\n".join(wrapper.wrap(param.doc)) + "\n"
60 # Indent struct fields and mixed types
61 if isinstance(param, dict):
62 for name, subparam in param.iteritems():
63 text += param_text(name, subparam, indent + step, step)
64 elif isinstance(param, Mixed):
65 for subparam in param:
66 text += param_text(name, subparam, indent + step, step)
67 elif isinstance(param, (list, tuple, set)):
68 for subparam in param:
69 text += param_text("", subparam, indent + step, step)
73 text += "Parameters:\n\n"
74 for name, param in zip(max_args, self.accepts):
75 text += param_text(name, param, indent, indent)
77 text += "Returns:\n\n"
78 text += param_text("", self.returns, indent, indent)
86 ((arg1_name, arg2_name, ...),
87 (arg1_name, arg2_name, ..., optional1_name, optional2_name, ...),
88 (None, None, ..., optional1_default, optional2_default, ...))
90 That represents the minimum and maximum sets of arguments that
91 this function accepts and the defaults for the optional arguments.
94 # Inspect call. Remove self from the argument list.
95 max_args = self.call.func_code.co_varnames[1:self.call.func_code.co_argcount]
96 defaults = self.call.func_defaults
100 min_args = max_args[0:len(max_args) - len(defaults)]
101 defaults = tuple([None for arg in min_args]) + defaults
103 return (min_args, max_args, defaults)
105 def type_check(self, name, value, expected, args):
107 Checks the type of the named value against the expected type,
108 which may be a Python type, a typed value, a Parameter, a
109 Mixed type, or a list or dictionary of possibly mixed types,
110 values, Parameters, or Mixed types.
112 Extraneous members of lists must be of the same type as the
113 last specified type. For example, if the expected argument
114 type is [int, bool], then [1, False] and [14, True, False,
115 True] are valid, but [1], [False, 1] and [14, True, 1] are
118 Extraneous members of dictionaries are ignored.
121 # If any of a number of types is acceptable
122 if isinstance(expected, Mixed):
123 for item in expected:
125 self.type_check(name, value, item, args)
127 except SfaInvalidArgument as fault:
131 # If an authentication structure is expected, save it and
132 # authenticate after basic type checking is done.
133 #if isinstance(expected, Auth):
138 # Get actual expected type from within the Parameter structure
139 if isinstance(expected, Parameter):
142 nullok = expected.nullok
143 expected = expected.type
149 expected_type = python_type(expected)
151 # If value can be NULL
152 if value is None and nullok:
155 # Strings are a special case. Accept either unicode or str
156 # types if a string is expected.
157 if issubclass(expected_type, StringType) and isinstance(value, StringType):
160 # Integers and long integers are also special types. Accept
161 # either int or long types if an int or long is expected.
162 elif expected_type in (IntType, LongType) and isinstance(value, (IntType, LongType)):
165 elif not isinstance(value, expected_type):
166 raise SfaInvalidArgument("expected %s, got %s" % \
167 (xmlrpc_type(expected_type),
168 xmlrpc_type(type(value))),
171 # If a minimum or maximum (length, value) has been specified
172 if issubclass(expected_type, StringType):
173 if min is not None and \
174 len(value.encode(self.api.encoding)) < min:
175 raise SfaInvalidArgument("%s must be at least %d bytes long" % (name, min))
176 if max is not None and \
177 len(value.encode(self.api.encoding)) > max:
178 raise SfaInvalidArgument("%s must be at most %d bytes long" % (name, max))
179 elif expected_type in (list, tuple, set):
180 if min is not None and len(value) < min:
181 raise SfaInvalidArgument("%s must contain at least %d items" % (name, min))
182 if max is not None and len(value) > max:
183 raise SfaInvalidArgument("%s must contain at most %d items" % (name, max))
185 if min is not None and value < min:
186 raise SfaInvalidArgument("%s must be > %s" % (name, str(min)))
187 if max is not None and value > max:
188 raise SfaInvalidArgument("%s must be < %s" % (name, str(max)))
190 # If a list with particular types of items is expected
191 if isinstance(expected, (list, tuple, set)):
192 for i in range(len(value)):
193 if i >= len(expected):
194 j = len(expected) - 1
197 self.type_check(name + "[]", value[i], expected[j], args)
199 # If a struct with particular (or required) types of items is
201 elif isinstance(expected, dict):
202 for key in value.keys():
204 self.type_check(name + "['%s']" % key, value[key], expected[key], args)
205 for key, subparam in expected.iteritems():
206 if isinstance(subparam, Parameter) and \
207 subparam.optional is not None and \
208 not subparam.optional and key not in value.keys():
209 raise SfaInvalidArgument("'%s' not specified" % key, name)
211 #if auth is not None:
212 # auth.check(self, *args)