Added support for repeating parameters
diff --git a/apiclient/discovery.py b/apiclient/discovery.py
index b202913..dbaac08 100644
--- a/apiclient/discovery.py
+++ b/apiclient/discovery.py
@@ -177,7 +177,7 @@
return resource
-def _to_string(value, schema_type):
+def _cast(value, schema_type):
"""Convert value to a string based on JSON Schema type.
See http://tools.ietf.org/html/draft-zyp-json-schema-03 for more details on
@@ -237,6 +237,7 @@
argmap = {} # Map from method parameter name to query parameter name
required_params = [] # Required parameters
+ repeated_params = [] # Repeated parameters
pattern_params = {} # Parameters that must match a regex
query_params = [] # Parameters that will be used in the query string
path_params = {} # Parameters that will be used in the base URL
@@ -255,6 +256,8 @@
enum_params[param] = desc['enum']
if desc.get('required', False):
required_params.append(param)
+ if desc.get('repeated', False):
+ repeated_params.append(param)
if desc.get('restParameterType') == 'query':
query_params.append(param)
if desc.get('restParameterType') == 'path':
@@ -294,11 +297,16 @@
actual_query_params = {}
actual_path_params = {}
for key, value in kwargs.iteritems():
- value_as_str = _to_string(value, param_type.get(key, 'string'))
+ to_type = param_type.get(key, 'string')
+ # For repeated parameters we cast each member of the list.
+ if key in repeated_params and type(value) == type([]):
+ cast_value = [_cast(x, to_type) for x in value]
+ else:
+ cast_value = _cast(value, to_type)
if key in query_params:
- actual_query_params[argmap[key]] = value_as_str
+ actual_query_params[argmap[key]] = cast_value
if key in path_params:
- actual_path_params[argmap[key]] = value_as_str
+ actual_path_params[argmap[key]] = cast_value
body_value = kwargs.get('body', None)
if self._developerKey:
@@ -330,17 +338,21 @@
docs = [methodDesc.get('description', DEFAULT_METHOD_DOC), '\n\n']
if len(argmap) > 0:
- docs.append("Args:\n")
+ docs.append('Args:\n')
for arg in argmap.iterkeys():
if arg in STACK_QUERY_PARAMETERS:
continue
- required = ""
+ repeated = ''
+ if arg in repeated_params:
+ repeated = ' (repeated)'
+ required = ''
if arg in required_params:
- required = " (required)"
+ required = ' (required)'
paramdesc = methodDesc['parameters'][argmap[arg]]
paramdoc = paramdesc.get('description', 'A parameter')
paramtype = paramdesc.get('type', 'string')
- docs.append(' %s: %s, %s%s\n' % (arg, paramtype, paramdoc, required))
+ docs.append(' %s: %s, %s%s%s\n' % (arg, paramtype, paramdoc, required,
+ repeated))
enum = paramdesc.get('enum', [])
enumDesc = paramdesc.get('enumDescriptions', [])
if enum and enumDesc:
@@ -430,7 +442,7 @@
if futureDesc and 'methods' in futureDesc:
for methodName, methodDesc in futureDesc['methods'].iteritems():
if 'next' in methodDesc and methodName in resourceDesc['methods']:
- createNextMethod(Resource, methodName + "_next",
+ createNextMethod(Resource, methodName + '_next',
resourceDesc['methods'][methodName],
methodDesc['next'])
diff --git a/apiclient/model.py b/apiclient/model.py
index 55bcc94..14ec397 100644
--- a/apiclient/model.py
+++ b/apiclient/model.py
@@ -127,9 +127,14 @@
params.update({'alt': 'json'})
astuples = []
for key, value in params.iteritems():
- if getattr(value, 'encode', False) and callable(value.encode):
- value = value.encode('utf-8')
- astuples.append((key, value))
+ if type(value) == type([]):
+ for x in value:
+ x = x.encode('utf-8')
+ astuples.append((key, x))
+ else:
+ if getattr(value, 'encode', False) and callable(value.encode):
+ value = value.encode('utf-8')
+ astuples.append((key, value))
return '?' + urllib.urlencode(astuples)
def response(self, resp, content):
diff --git a/samples/translate/main.py b/samples/translate/main.py
index 24f0648..ae39130 100644
--- a/samples/translate/main.py
+++ b/samples/translate/main.py
@@ -21,12 +21,12 @@
def main():
- p = build("translate", "v2",
- developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
+ p = build('translate', 'v2',
+ developerKey='AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0')
print p.translations().list(
- source="en",
- target="fr",
- q="flower"
+ source='en',
+ target='fr',
+ q=['flower', 'car']
).execute()
if __name__ == '__main__':
diff --git a/tests/test_json_model.py b/tests/test_json_model.py
index fa7ad05..88f2400 100644
--- a/tests/test_json_model.py
+++ b/tests/test_json_model.py
@@ -101,7 +101,9 @@
headers = {}
path_params = {}
- query_params = {'foo': 1, 'bar': u'\N{COMET}'}
+ query_params = {'foo': 1, 'bar': u'\N{COMET}',
+ 'baz': ['fe', 'fi', 'fo', 'fum'], # Repeated parameters
+ 'qux': []}
body = {}
headers, params, query, body = model.request(headers, path_params, query_params, body)
@@ -109,9 +111,11 @@
self.assertEqual(headers['accept'], 'application/json')
self.assertEqual(headers['content-type'], 'application/json')
- query_dict = parse_qs(query)
+ query_dict = parse_qs(query[1:])
self.assertEqual(query_dict['foo'], ['1'])
self.assertEqual(query_dict['bar'], [u'\N{COMET}'.encode('utf-8')])
+ self.assertEqual(query_dict['baz'], ['fe', 'fi', 'fo', 'fum'])
+ self.assertTrue('qux' not in query_dict)
self.assertEqual(body, '{}')
def test_user_agent(self):