Skip to content

Commit 38051ac

Browse files
Brian J. Watsonnathanielmanistaatgoogle
authored andcommitted
Add media_mime_type keyword argument
Sometimes the Python mimetypes module cannot automatically detect the MIME type of a media upload file, and the user would want to explicitly specify it. An example is audio/x-raw. This commit adds a media_mime_type keyword argument to media upload methods. If the caller does not specify this argument, a warning is logged to teach the user about it in case they need to explicitly specify a MIME type.
1 parent 5f00cad commit 38051ac

File tree

3 files changed

+42
-6
lines changed

3 files changed

+42
-6
lines changed

googleapiclient/discovery.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@
108108
'type': 'string',
109109
'required': False,
110110
}
111+
MEDIA_MIME_TYPE_PARAMETER_DEFAULT_VALUE = {
112+
'description': ('The MIME type of the media request body, or an instance '
113+
'of a MediaUpload object.'),
114+
'type': 'string',
115+
'required': False,
116+
}
111117

112118
# Parameters accepted by the stack, but not visible via discovery.
113119
# TODO(dhermes): Remove 'userip' in 'v2'.
@@ -481,7 +487,7 @@ def _fix_up_parameters(method_desc, root_desc, http_method):
481487

482488

483489
def _fix_up_media_upload(method_desc, root_desc, path_url, parameters):
484-
"""Updates parameters of API by adding 'media_body' if supported by method.
490+
"""Adds 'media_body' and 'media_mime_type' parameters if supported by method.
485491
486492
SIDE EFFECTS: If the method supports media upload and has a required body,
487493
sets body to be optional (required=False) instead. Also, if there is a
@@ -518,6 +524,7 @@ def _fix_up_media_upload(method_desc, root_desc, path_url, parameters):
518524
if media_upload:
519525
media_path_url = _media_path_url_from_info(root_desc, path_url)
520526
parameters['media_body'] = MEDIA_BODY_PARAMETER_DEFAULT_VALUE.copy()
527+
parameters['media_mime_type'] = MEDIA_MIME_TYPE_PARAMETER_DEFAULT_VALUE.copy()
521528
if 'body' in parameters:
522529
parameters['body']['required'] = False
523530

@@ -751,6 +758,7 @@ def method(self, **kwargs):
751758
actual_path_params[parameters.argmap[key]] = cast_value
752759
body_value = kwargs.get('body', None)
753760
media_filename = kwargs.get('media_body', None)
761+
media_mime_type = kwargs.get('media_mime_type', None)
754762

755763
if self._developerKey:
756764
actual_query_params['key'] = self._developerKey
@@ -774,7 +782,11 @@ def method(self, **kwargs):
774782
if media_filename:
775783
# Ensure we end up with a valid MediaUpload object.
776784
if isinstance(media_filename, six.string_types):
777-
(media_mime_type, encoding) = mimetypes.guess_type(media_filename)
785+
if media_mime_type is None:
786+
logger.warning(
787+
'media_mime_type argument not specified: trying to auto-detect for %s',
788+
media_filename)
789+
media_mime_type, _ = mimetypes.guess_type(media_filename)
778790
if media_mime_type is None:
779791
raise UnknownFileType(media_filename)
780792
if not mimeparse.best_match([media_mime_type], ','.join(accept)):

tests/data/small-png

190 Bytes
Binary file not shown.

tests/test_discovery.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
from googleapiclient.discovery import DISCOVERY_URI
5151
from googleapiclient.discovery import key2param
5252
from googleapiclient.discovery import MEDIA_BODY_PARAMETER_DEFAULT_VALUE
53+
from googleapiclient.discovery import MEDIA_MIME_TYPE_PARAMETER_DEFAULT_VALUE
5354
from googleapiclient.discovery import ResourceMethodParameters
5455
from googleapiclient.discovery import STACK_QUERY_PARAMETERS
5556
from googleapiclient.discovery import STACK_QUERY_PARAMETER_DEFAULT_VALUE
@@ -61,6 +62,7 @@
6162
from googleapiclient.errors import ResumableUploadError
6263
from googleapiclient.errors import UnacceptableMimeTypeError
6364
from googleapiclient.errors import UnknownApiNameOrVersion
65+
from googleapiclient.errors import UnknownFileType
6466
from googleapiclient.http import BatchHttpRequest
6567
from googleapiclient.http import HttpMock
6668
from googleapiclient.http import HttpMockSequence
@@ -212,14 +214,16 @@ def test_fix_up_media_upload_no_initial_invalid(self):
212214

213215
def test_fix_up_media_upload_no_initial_valid_minimal(self):
214216
valid_method_desc = {'mediaUpload': {'accept': []}}
215-
final_parameters = {'media_body': MEDIA_BODY_PARAMETER_DEFAULT_VALUE}
217+
final_parameters = {'media_body': MEDIA_BODY_PARAMETER_DEFAULT_VALUE,
218+
'media_mime_type': MEDIA_MIME_TYPE_PARAMETER_DEFAULT_VALUE}
216219
self._base_fix_up_method_description_test(
217220
valid_method_desc, {}, final_parameters, [], 0,
218221
'http://root/upload/fake/fake-path/')
219222

220223
def test_fix_up_media_upload_no_initial_valid_full(self):
221224
valid_method_desc = {'mediaUpload': {'accept': ['*/*'], 'maxSize': '10GB'}}
222-
final_parameters = {'media_body': MEDIA_BODY_PARAMETER_DEFAULT_VALUE}
225+
final_parameters = {'media_body': MEDIA_BODY_PARAMETER_DEFAULT_VALUE,
226+
'media_mime_type': MEDIA_MIME_TYPE_PARAMETER_DEFAULT_VALUE}
223227
ten_gb = 10 * 2**30
224228
self._base_fix_up_method_description_test(
225229
valid_method_desc, {}, final_parameters, ['*/*'],
@@ -236,7 +240,8 @@ def test_fix_up_media_upload_with_initial_valid_minimal(self):
236240
valid_method_desc = {'mediaUpload': {'accept': []}}
237241
initial_parameters = {'body': {}}
238242
final_parameters = {'body': {'required': False},
239-
'media_body': MEDIA_BODY_PARAMETER_DEFAULT_VALUE}
243+
'media_body': MEDIA_BODY_PARAMETER_DEFAULT_VALUE,
244+
'media_mime_type': MEDIA_MIME_TYPE_PARAMETER_DEFAULT_VALUE}
240245
self._base_fix_up_method_description_test(
241246
valid_method_desc, initial_parameters, final_parameters, [], 0,
242247
'http://root/upload/fake/fake-path/')
@@ -245,7 +250,8 @@ def test_fix_up_media_upload_with_initial_valid_full(self):
245250
valid_method_desc = {'mediaUpload': {'accept': ['*/*'], 'maxSize': '10GB'}}
246251
initial_parameters = {'body': {}}
247252
final_parameters = {'body': {'required': False},
248-
'media_body': MEDIA_BODY_PARAMETER_DEFAULT_VALUE}
253+
'media_body': MEDIA_BODY_PARAMETER_DEFAULT_VALUE,
254+
'media_mime_type': MEDIA_MIME_TYPE_PARAMETER_DEFAULT_VALUE}
249255
ten_gb = 10 * 2**30
250256
self._base_fix_up_method_description_test(
251257
valid_method_desc, initial_parameters, final_parameters, ['*/*'],
@@ -775,6 +781,24 @@ def test_simple_media_good_upload(self):
775781
'https://www.googleapis.com/upload/zoo/v1/animals?uploadType=media&alt=json',
776782
request.uri)
777783

784+
def test_simple_media_unknown_mimetype(self):
785+
self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
786+
zoo = build('zoo', 'v1', http=self.http)
787+
788+
try:
789+
zoo.animals().insert(media_body=datafile('small-png'))
790+
self.fail("should throw exception if mimetype is unknown.")
791+
except UnknownFileType:
792+
pass
793+
794+
request = zoo.animals().insert(media_body=datafile('small-png'),
795+
media_mime_type='image/png')
796+
self.assertEquals('image/png', request.headers['content-type'])
797+
self.assertEquals(b'PNG', request.body[1:4])
798+
assertUrisEqual(self,
799+
'https://www.googleapis.com/upload/zoo/v1/animals?uploadType=media&alt=json',
800+
request.uri)
801+
778802
def test_multipart_media_raise_correct_exceptions(self):
779803
self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
780804
zoo = build('zoo', 'v1', http=self.http)

0 commit comments

Comments
 (0)