Some methods don't specify a schema for their response, which means that
they are returning non-JSON such as CSV, images, etc. In that case
we return the bytes on the wire instead of trying to parse the response
as JSON.
Reviewed in http://codereview.appspot.com/5448123/
diff --git a/apiclient/discovery.py b/apiclient/discovery.py
index a3d4beb..ca26025 100644
--- a/apiclient/discovery.py
+++ b/apiclient/discovery.py
@@ -52,6 +52,7 @@
from http import MediaUpload
from http import MediaFileUpload
from model import JsonModel
+from model import RawModel
URITEMPLATE = re.compile('{[^}]*}')
VARNAME = re.compile('[a-zA-Z0-9_-]+')
@@ -437,8 +438,13 @@
if self._developerKey:
actual_query_params['key'] = self._developerKey
+ model = self._model
+ # If there is no schema for the response then presume a binary blob.
+ if 'response' not in methodDesc:
+ model = RawModel()
+
headers = {}
- headers, params, query, body = self._model.request(headers,
+ headers, params, query, body = model.request(headers,
actual_path_params, actual_query_params, body_value)
expanded_url = uritemplate.expand(pathUrl, params)
@@ -541,7 +547,7 @@
logging.info('URL being requested: %s' % url)
return self._requestBuilder(self._http,
- self._model.response,
+ model.response,
url,
method=httpMethod,
body=body,
diff --git a/apiclient/model.py b/apiclient/model.py
index b8271f9..7f40efa 100644
--- a/apiclient/model.py
+++ b/apiclient/model.py
@@ -161,7 +161,8 @@
Returns:
The query parameters properly encoded into an HTTP URI query string.
"""
- params.update({'alt': self.alt_param})
+ if self.alt_param is not None:
+ params.update({'alt': self.alt_param})
astuples = []
for key, value in params.iteritems():
if type(value) == type([]):
@@ -269,6 +270,25 @@
return {}
+class RawModel(JsonModel):
+ """Model class for requests that don't return JSON.
+
+ Serializes and de-serializes between JSON and the Python
+ object representation of HTTP request, and returns the raw bytes
+ of the response body.
+ """
+ accept = '*/*'
+ content_type = 'application/json'
+ alt_param = None
+
+ def deserialize(self, content):
+ return content
+
+ @property
+ def no_content_response(self):
+ return ''
+
+
class ProtocolBufferModel(BaseModel):
"""Model class for protocol buffers.
diff --git a/tests/data/zoo.json b/tests/data/zoo.json
index 6e42da2..0bb0a79 100644
--- a/tests/data/zoo.json
+++ b/tests/data/zoo.json
@@ -289,6 +289,33 @@
"$ref": "Animal"
}
},
+ "getmedia": {
+ "path": "animals/{name}",
+ "id": "zoo.animals.get",
+ "httpMethod": "GET",
+ "description": "Get animals",
+ "parameters": {
+ "name": {
+ "location": "path",
+ "required": true,
+ "description": "Name of the animal to load",
+ "type": "string"
+ },
+ "projection": {
+ "location": "query",
+ "type": "string",
+ "enum": [
+ "full"
+ ],
+ "enumDescriptions": [
+ "Include everything"
+ ]
+ }
+ },
+ "parameterOrder": [
+ "name"
+ ]
+ },
"insert": {
"path": "animals",
"id": "zoo.animals.insert",
diff --git a/tests/test_discovery.py b/tests/test_discovery.py
index 9e47e8f..e1ef94f 100644
--- a/tests/test_discovery.py
+++ b/tests/test_discovery.py
@@ -187,6 +187,26 @@
self.assertEqual(q['trace'], ['html'])
self.assertEqual(q['fields'], ['description'])
+ def test_model_added_query_parameters(self):
+ http = HttpMock(datafile('zoo.json'), {'status': '200'})
+ zoo = build('zoo', 'v1', http)
+ request = zoo.animals().get(name='Lion')
+
+ parsed = urlparse.urlparse(request.uri)
+ q = parse_qs(parsed[4])
+ self.assertEqual(q['alt'], ['json'])
+ self.assertEqual(request.headers['accept'], 'application/json')
+
+ def test_fallback_to_raw_model(self):
+ http = HttpMock(datafile('zoo.json'), {'status': '200'})
+ zoo = build('zoo', 'v1', http)
+ request = zoo.animals().getmedia(name='Lion')
+
+ parsed = urlparse.urlparse(request.uri)
+ q = parse_qs(parsed[4])
+ self.assertTrue('alt' not in q)
+ self.assertEqual(request.headers['accept'], '*/*')
+
def test_patch(self):
http = HttpMock(datafile('zoo.json'), {'status': '200'})
zoo = build('zoo', 'v1', http)