103
103
'type' : string_types ,
104
104
}
105
105
106
- STR_RE = re .compile (r'([a-zA-Z_]+)' )
106
+ TYPE_INFO_COMMENT_RE = re .compile (r'\s*\([^)]+\)\s*|,.+$' )
107
+ TYPE_INFO_SPLITTER_RE = re .compile (r'(\w+(?:<.+>)?)(?:\s+|$)' )
108
+ TYPE_INFO_RE = re .compile (r'(\w+)(<[^>]+>)?(?:\s+|$)' )
107
109
108
110
109
111
def map_param_type (param_type ):
@@ -112,18 +114,20 @@ def map_param_type(param_type):
112
114
This requires a bit of logic since this isn't standardized.
113
115
If a type doesn't map, assume str
114
116
"""
115
- m = STR_RE .match (param_type )
116
- main_type = m .group (0 )
117
+ main_type , sub_type = TYPE_INFO_RE .match (param_type ).groups ()
117
118
118
119
if main_type in ('list' , 'array' ):
119
- info = param_type .replace (' ' , '' ).split ('<' , 1 )
120
-
121
120
# Handle no sub-type: "required list"
122
- sub_type = info [1 ] if len (info ) > 1 else 'str'
121
+ if sub_type is not None :
122
+ sub_type = sub_type .strip ()
123
+
124
+ if not sub_type :
125
+ sub_type = 'str'
123
126
124
127
# Handle list of pairs: "optional list<pair<callsign, path>>"
125
- sub_match = STR_RE .match (sub_type )
126
- sub_type = sub_match .group (0 ).lower ()
128
+ sub_match = TYPE_INFO_RE .match (sub_type )
129
+ if sub_match :
130
+ sub_type = sub_match .group (0 ).lower ()
127
131
128
132
return [PARAM_TYPE_MAP .setdefault (sub_type , string_types )]
129
133
@@ -151,25 +155,23 @@ def parse_interfaces(interfaces):
151
155
method ['required' ] = {}
152
156
153
157
for name , type_info in iteritems (dict (d ['params' ])):
158
+ # Set the defaults
159
+ optionality = 'required'
160
+ param_type = 'string'
161
+
154
162
# Usually in the format: <optionality> <param_type>
155
- info_pieces = type_info .split (' ' , 1 )
156
-
157
- # If optionality isn't specified, assume required
158
- if info_pieces [0 ] not in ('optional' , 'required' ):
159
- optionality = 'required'
160
- param_type = info_pieces [0 ]
161
- # Just make an optional string for "ignored" params
162
- elif info_pieces [0 ] == 'ignored' :
163
- optionality = 'optional'
164
- param_type = 'string'
165
- else :
166
- optionality = info_pieces [0 ]
167
- param_type = info_pieces [1 ]
168
-
169
- # This isn't validated by the client
170
- if param_type .startswith ('nonempty' ):
171
- optionality = 'required'
172
- param_type = param_type [9 :]
163
+ type_info = TYPE_INFO_COMMENT_RE .sub ('' , type_info )
164
+ info_pieces = TYPE_INFO_SPLITTER_RE .findall (type_info )
165
+ for info_piece in info_pieces :
166
+ if info_piece in ('optional' , 'required' ):
167
+ optionality = info_piece
168
+ elif info_piece == 'ignored' :
169
+ optionality = 'optional'
170
+ param_type = 'string'
171
+ elif info_piece == 'nonempty' :
172
+ optionality = 'required'
173
+ else :
174
+ param_type = info_piece
173
175
174
176
method [optionality ][name ] = map_param_type (param_type )
175
177
@@ -238,8 +240,12 @@ def _request(self, **kwargs):
238
240
239
241
def validate_kwarg (key , target ):
240
242
# Always allow list
241
- if isinstance (key , list ):
242
- return all ([validate_kwarg (x , target [0 ]) for x in key ])
243
+ if isinstance (target , list ):
244
+ return (
245
+ isinstance (key , (list , tuple , set )) and
246
+ all (validate_kwarg (x , target [0 ]) for x in key )
247
+ )
248
+
243
249
return isinstance (key , tuple (target ) if isinstance (target , list ) else target )
244
250
245
251
for key , val in resource .get ('required' , {}).items ():
0 commit comments