def test_resumable_multipart_media_good_upload(self): self.http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=self.http) media_upload = MediaFileUpload(datafile('small.png'), resumable=True) request = zoo.animals().insert(media_body=media_upload, body={}) self.assertTrue( request.headers['content-type'].startswith('application/json')) self.assertEquals('{"data": {}}', request.body) self.assertEquals(media_upload, request.resumable) self.assertEquals('image/png', request.resumable.mimetype()) self.assertNotEquals(request.body, None) self.assertEquals(request.resumable_uri, None) http = HttpMockSequence([ ({ 'status': '200', 'location': 'http://upload.example.com' }, ''), ({ 'status': '308', 'location': 'http://upload.example.com/2', 'range': '0-12' }, ''), ({ 'status': '308', 'location': 'http://upload.example.com/3', 'range': '0-%d' % (media_upload.size() - 2) }, ''), ({ 'status': '200' }, '{"foo": "bar"}'), ]) status, body = request.next_chunk(http=http) self.assertEquals(None, body) self.assertTrue(isinstance(status, MediaUploadProgress)) self.assertEquals(13, status.resumable_progress) # Two requests should have been made and the resumable_uri should have been # updated for each one. self.assertEquals(request.resumable_uri, 'http://upload.example.com/2') self.assertEquals(media_upload, request.resumable) self.assertEquals(13, request.resumable_progress) status, body = request.next_chunk(http=http) self.assertEquals(request.resumable_uri, 'http://upload.example.com/3') self.assertEquals(media_upload.size() - 1, request.resumable_progress) self.assertEquals('{"data": {}}', request.body) # Final call to next_chunk should complete the upload. status, body = request.next_chunk(http=http) self.assertEquals(body, {"foo": "bar"}) self.assertEquals(status, None)
def put(self, filename, path='', silent=False): """Upload a local filename to remote folder file Parameters ---------- filename : str Input local filename path : str, default is '' Absolute or relative output filename or folder (basename inferred from local filename). If blank: upload to current remote folder silent : bool, default False if False, print file statistics if successful Returns ------- total_file_size : int or None if unsuccessful and silent flag is set to True Notes ----- see https://developers.google.com/drive/api/v3/manage-uploads """ if not path: # if path not specified, put in current remote folder path = self.pwd path = self._fullpath(path) if self.fetchone(path, field='mimeType') == _FOLDER: base = os.path.basename(filename) # infer base from input filename folder = path # if output path is folder else: folder, base = os.path.split(path) media_body = MediaFileUpload(filename, resumable=True) fileId = self.fetchone(os.path.join(folder, base), field='id') tic = time.time() if fileId: # fileId already exists, so use update method self.service.files().update(fileId=fileId, media_body=media_body).execute() else: folderId = self.fetchone(folder, field='id') # try to get folder ID if folderId is None: if not silent: # raise Exception if verbose raise Exception('Cannot put ' + path) return None # else silently return self.service.files().create( # method creates new file in folder body={ 'name': base, "parents": [folderId] }, media_body=media_body).execute() if not silent: print("{} to {}, len={}, in {:.0f} secs".format( "Updated" if fileId else "Saved", os.path.join(folder, base), media_body.size(), time.time() - tic)) return media_body.size()
def test_resumable_multipart_media_good_upload(self): self.http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=self.http) media_upload = MediaFileUpload(datafile('small.png'), resumable=True) request = zoo.animals().insert(media_body=media_upload, body={}) self.assertTrue(request.headers['content-type'].startswith( 'application/json')) self.assertEquals('{"data": {}}', request.body) self.assertEquals(media_upload, request.resumable) self.assertEquals('image/png', request.resumable.mimetype()) self.assertNotEquals(request.body, None) self.assertEquals(request.resumable_uri, None) http = HttpMockSequence([ ({'status': '200', 'location': 'http://upload.example.com'}, ''), ({'status': '308', 'location': 'http://upload.example.com/2', 'range': '0-12'}, ''), ({'status': '308', 'location': 'http://upload.example.com/3', 'range': '0-%d' % (media_upload.size() - 2)}, ''), ({'status': '200'}, '{"foo": "bar"}'), ]) status, body = request.next_chunk(http=http) self.assertEquals(None, body) self.assertTrue(isinstance(status, MediaUploadProgress)) self.assertEquals(13, status.resumable_progress) # Two requests should have been made and the resumable_uri should have been # updated for each one. self.assertEquals(request.resumable_uri, 'http://upload.example.com/2') self.assertEquals(media_upload, request.resumable) self.assertEquals(13, request.resumable_progress) status, body = request.next_chunk(http=http) self.assertEquals(request.resumable_uri, 'http://upload.example.com/3') self.assertEquals(media_upload.size()-1, request.resumable_progress) self.assertEquals('{"data": {}}', request.body) # Final call to next_chunk should complete the upload. status, body = request.next_chunk(http=http) self.assertEquals(body, {"foo": "bar"}) self.assertEquals(status, None)
def test_resumable_media_good_upload_from_execute(self): """Not a multipart upload.""" self.http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=self.http) media_upload = MediaFileUpload(datafile('small.png'), resumable=True) request = zoo.animals().insert(media_body=media_upload, body=None) assertUrisEqual(self, 'https://www.googleapis.com/upload/zoo/v1/animals?uploadType=resumable&alt=json', request.uri) http = HttpMockSequence([ ({'status': '200', 'location': 'http://upload.example.com'}, ''), ({'status': '308', 'location': 'http://upload.example.com/2', 'range': '0-12'}, ''), ({'status': '308', 'location': 'http://upload.example.com/3', 'range': '0-%d' % media_upload.size()}, ''), ({'status': '200'}, '{"foo": "bar"}'), ]) body = request.execute(http=http) self.assertEquals(body, {"foo": "bar"})
def update_file(service, update_drive_service_name, local_file_path, update_drive_service_folder_id): """ 將本地端的檔案傳到雲端上 :param update_drive_service_folder_id: 判斷是否有 Folder id 沒有的話,會上到雲端的目錄 :param service: 認證用 :param update_drive_service_name: 存到 雲端上的名稱 :param local_file_path: 本地端的位置 :param local_file_name: 本地端的檔案名稱 """ print("正在上傳檔案...") if update_drive_service_folder_id is None: file_metadata = {'name': update_drive_service_name} else: print("雲端資料夾id: %s" % update_drive_service_folder_id) file_metadata = { 'name': update_drive_service_name, 'parents': update_drive_service_folder_id } media = MediaFileUpload(local_file_path, ) file_metadata_size = media.size() start = time.time() file_id = service.files().create(body=file_metadata, media_body=media, fields='id').execute() end = time.time() print("上傳檔案成功!") print('雲端檔案名稱為: ' + str(file_metadata['name'])) print('雲端檔案ID為: ' + str(file_id['id'])) print('檔案大小為: ' + str(file_metadata_size) + ' byte') print("上傳時間為: " + str(end - start))
def update_file(service, update_drive_service_name, local_file_path, update_drive_service_folder_id): """ 將本地端的檔案傳到雲端上 :param update_drive_service_folder_id: 判斷是否有 Folder id 沒有的話,會上到雲端的目錄 :param service: 認證用 :param update_drive_service_name: 存到 雲端上的名稱 :param local_file_path: 本地端的位置 :param local_file_name: 本地端的檔案名稱 """ if update_drive_service_folder_id is None: file_metadata = {'name': update_drive_service_name} else: # print("雲端資料夾id: %s" % update_drive_service_folder_id) file_metadata = { 'name': update_drive_service_name, 'parents': update_drive_service_folder_id } media = MediaFileUpload(local_file_path, ) file_metadata_size = media.size() start = time.time() file_id = service.files().create(body=file_metadata, media_body=media, fields='id').execute() end = time.time() print('%10s\033[0;34mλ 雲端檔案名稱:\033[0m' % " " + str(file_metadata['name'])) print('%10s\033[0;34mλ 雲端檔案 ID:\033[0m' % " " + str(file_id['id'])) print('%10s\033[0;34mλ 檔案大小:\033[0m' % " " + str(file_metadata_size) + ' byte') print("%10s\033[0;34mλ 上傳時間:\033[0m" % " " + str(end - start) + '\n') return file_metadata['name'], file_id['id']
def update_file(service, update_drive_service_name, local_file_path, update_drive_service_folder_id): """ 将本地端的文件上传到云端 :param service: 认证用 :param update_drive_service_name: 存到云端的文件名 :param local_file_path: 本地文件位置加文件名 """ print("Uploading file...") # file_metadata = {'name': update_drive_service_name} if update_drive_service_folder_id is None: file_metadata = {'name': update_drive_service_name} else: # print(update_drive_service_folder_id) file_metadata = {'name': update_drive_service_name, 'parents': update_drive_service_folder_id} media = MediaFileUpload(local_file_path, ) file_metadata_size = media.size() start = time.time() file_id = service.files().create(body=file_metadata, media_body=media, fields='id').execute() end = time.time() print('File name: ' + str(file_metadata['name'])) print('Could file ID: ' + str(file_id['id'])) print('File size: ' + str(file_metadata_size) + ' byte') print("Upload time: " + str(end-start)) return file_metadata['name'], file_id['id']
def upload_file(file_name): link_file = f'{file_name}.webViewLink' if not os.path.exists(link_file): media = MediaFileUpload(file_name, resumable=True) if media.size() > 0: request = drive_service.files().create( fields='id,webViewLink', body={ 'name': file_name.split('/')[-1], 'parents': ['1twO1fPD1gCC7MgH3WnlMweX8BOtDUMke'] }, media_body=media) response = None logger.info(f'Uploading {file_name}') while response is None: status, response = request.next_chunk() if status: logger.info("Uploaded %d%%." % int(status.progress() * 100)) logger.info("Upload Complete!") with open(f'{file_name}.webViewLink', 'w+') as f: f.write(response['webViewLink']) return response['webViewLink'] else: return None with open(link_file) as f: return f.read()
def test_resumable_media_good_upload_from_execute(self): """Not a multipart upload.""" self.http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=self.http) media_upload = MediaFileUpload(datafile('small.png'), resumable=True) request = zoo.animals().insert(media_body=media_upload, body=None) assertUrisEqual( self, 'https://www.googleapis.com/upload/zoo/v1/animals?uploadType=resumable&alt=json', request.uri) http = HttpMockSequence([ ({ 'status': '200', 'location': 'http://upload.example.com' }, ''), ({ 'status': '308', 'location': 'http://upload.example.com/2', 'range': '0-12' }, ''), ({ 'status': '308', 'location': 'http://upload.example.com/3', 'range': '0-%d' % media_upload.size() }, ''), ({ 'status': '200' }, '{"foo": "bar"}'), ]) body = request.execute(http=http) self.assertEquals(body, {"foo": "bar"})
def update_file(service, update_drive_service_name, local_file_path): """ 將本地端的檔案傳到雲端上 :param service: 認證用 :param update_drive_service_name: 存到 雲端上的名稱 :param local_file_path: 本地端的位置 :param local_file_name: 本地端的檔案名稱 """ print("正在上傳檔案...") file_metadata = {'name': update_drive_service_name} media = MediaFileUpload(local_file_path, ) file_metadata_size = media.size() start = time.time() file_id = service.files().create(body=file_metadata, media_body=media, fields='id').execute() end = time.time() print("上傳檔案成功!") print('雲端檔案名稱為: ' + str(file_metadata['name'])) print('雲端檔案ID為: ' + str(file_id['id'])) print('檔案大小為: ' + str(file_metadata_size) + ' byte') print("上傳時間為: " + str(end - start)) return file_metadata['name'], file_id['id']
def upload_file(service, file_path, mimetype=None, folder_id=None): file_name = os.path.basename(file_path) parents = [folder_id] if folder_id is not None else None file_metadata = {'name': file_name, 'parents': parents} media = MediaFileUpload(file_path) file_size = media.size() file_id = service.files().create(body=file_metadata, media_body=media, fields='id').execute() if file_id: print('Upload {} success, total {} byte'.format(file_name, file_size))
def update_file(service, update_drive_service_name, local_file_path, update_drive_service_folder_id): """ 將本地端的檔案傳到雲端上 :param update_drive_service_folder_id: 判斷是否有 Folder id 沒有的話,會上到雲端的目錄 :param service: 認證用 :param update_drive_service_name: 存到 雲端上的名稱 :param local_file_path: 本地端的位置 :param local_file_name: 本地端的檔案名稱 """ print("正在上傳檔案...") if update_drive_service_folder_id is None: file_metadata = {'name': update_drive_service_name} else: print("雲端資料夾id: %s" % update_drive_service_folder_id) file_metadata = {'name': update_drive_service_name, 'parents': update_drive_service_folder_id} media = MediaFileUpload(local_file_path, ) file_metadata_size = media.size() start = time.time() file_id = service.files().create(body=file_metadata, media_body=media, fields='id').execute() end = time.time() print("上傳檔案成功!") print('雲端檔案名稱為: ' + str(file_metadata['name'])) print('雲端檔案ID為: ' + str(file_id['id'])) print('檔案大小為: ' + str(file_metadata_size) + ' byte') print("上傳時間為: " + str(end-start)) print("時間戳: " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) pid = mcs_api.get_mcs_id() pid = pid.split('*') pid = pid[0] try: connection = psycopg2.connect(database = "smartmeeting", user = "******", password = "******", host = "140.136.155.145", port = "5432" )#連線資料庫 cursor = connection.cursor() cursor.execute("INSERT INTO audiotext (at_id, at_name, at_proid, at_time) VALUES (%s, %s, %s, %s)", (file_id['id'], file_metadata['name'], pid, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))) connection.commit() print("insert successfully") except (Exception, psycopg2.Error) as error : if(connection): print("fail to insert", error) finally: if(connection): cursor.close() connection.close() print("pg connection is closed") return file_metadata['name'], file_id['id']
def test_media_file_upload_to_from_json(self): upload = MediaFileUpload( datafile('small.png'), chunksize=500, resumable=True) self.assertEqual('image/png', upload.mimetype()) self.assertEqual(190, upload.size()) self.assertEqual(True, upload.resumable()) self.assertEqual(500, upload.chunksize()) self.assertEqual('PNG', upload.getbytes(1, 3)) json = upload.to_json() new_upload = MediaUpload.new_from_json(json) self.assertEqual('image/png', new_upload.mimetype()) self.assertEqual(190, new_upload.size()) self.assertEqual(True, new_upload.resumable()) self.assertEqual(500, new_upload.chunksize()) self.assertEqual('PNG', new_upload.getbytes(1, 3))
def method(self, **kwargs): # Don't bother with doc string, it will be over-written by createMethod. for name in kwargs.iterkeys(): if name not in parameters.argmap: raise TypeError('Got an unexpected keyword argument "%s"' % name) # Remove args that have a value of None. keys = kwargs.keys() for name in keys: if kwargs[name] is None: del kwargs[name] for name in parameters.required_params: if name not in kwargs: raise TypeError('Missing required parameter "%s"' % name) for name, regex in parameters.pattern_params.iteritems(): if name in kwargs: if isinstance(kwargs[name], basestring): pvalues = [kwargs[name]] else: pvalues = kwargs[name] for pvalue in pvalues: if re.match(regex, pvalue) is None: raise TypeError( 'Parameter "%s" value "%s" does not match the pattern "%s"' % (name, pvalue, regex)) for name, enums in parameters.enum_params.iteritems(): if name in kwargs: # We need to handle the case of a repeated enum # name differently, since we want to handle both # arg='value' and arg=['value1', 'value2'] if (name in parameters.repeated_params and not isinstance(kwargs[name], basestring)): values = kwargs[name] else: values = [kwargs[name]] for value in values: if value not in enums: raise TypeError( 'Parameter "%s" value "%s" is not an allowed value in "%s"' % (name, value, str(enums))) actual_query_params = {} actual_path_params = {} for key, value in kwargs.iteritems(): to_type = parameters.param_types.get(key, 'string') # For repeated parameters we cast each member of the list. if key in parameters.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 parameters.query_params: actual_query_params[parameters.argmap[key]] = cast_value if key in parameters.path_params: actual_path_params[parameters.argmap[key]] = cast_value body_value = kwargs.get('body', None) media_filename = kwargs.get('media_body', None) if self._developerKey: actual_query_params['key'] = self._developerKey model = self._model if methodName.endswith('_media'): model = MediaModel() elif 'response' not in methodDesc: model = RawModel() headers = {} headers, params, query, body = model.request(headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = urlparse.urljoin(self._baseUrl, expanded_url + query) resumable = None multipart_boundary = '' if media_filename: # Ensure we end up with a valid MediaUpload object. if isinstance(media_filename, basestring): (media_mime_type, encoding) = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ','.join(accept)): raise UnacceptableMimeTypeError(media_mime_type) media_upload = MediaFileUpload(media_filename, mimetype=media_mime_type) elif isinstance(media_filename, MediaUpload): media_upload = media_filename else: raise TypeError('media_filename must be str or MediaUpload.') # Check the maxSize if maxSize > 0 and media_upload.size() > maxSize: raise MediaUploadSizeError("Media larger than: %s" % maxSize) # Use the media path uri for media uploads expanded_url = uritemplate.expand(mediaPathUrl, params) url = urlparse.urljoin(self._baseUrl, expanded_url + query) if media_upload.resumable(): url = _add_query_parameter(url, 'uploadType', 'resumable') if media_upload.resumable(): # This is all we need to do for resumable, if the body exists it gets # sent in the first request, otherwise an empty body is sent. resumable = media_upload else: # A non-resumable upload if body is None: # This is a simple media upload headers['content-type'] = media_upload.mimetype() body = media_upload.getbytes(0, media_upload.size()) url = _add_query_parameter(url, 'uploadType', 'media') else: # This is a multipart/related upload. msgRoot = MIMEMultipart('related') # msgRoot should not write out it's own headers setattr(msgRoot, '_write_headers', lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers['content-type'].split('/')) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_upload.mimetype().split('/')) msg['Content-Transfer-Encoding'] = 'binary' payload = media_upload.getbytes(0, media_upload.size()) msg.set_payload(payload) msgRoot.attach(msg) body = msgRoot.as_string() multipart_boundary = msgRoot.get_boundary() headers['content-type'] = ('multipart/related; ' 'boundary="%s"') % multipart_boundary url = _add_query_parameter(url, 'uploadType', 'multipart') logger.info('URL being requested: %s %s' % (httpMethod,url)) return self._requestBuilder(self._http, model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId, resumable=resumable)
def method(self, **kwargs): # Don't bother with doc string, it will be over-written by createMethod. for name in six.iterkeys(kwargs): if name not in parameters.argmap: raise TypeError('Got an unexpected keyword argument "%s"' % name) # Remove args that have a value of None. keys = list(kwargs.keys()) for name in keys: if kwargs[name] is None: del kwargs[name] for name in parameters.required_params: if name not in kwargs: # temporary workaround for non-paging methods incorrectly requiring # page token parameter (cf. drive.changes.watch vs. drive.changes.list) if name not in _PAGE_TOKEN_NAMES or _findPageTokenName( _methodProperties(methodDesc, schema, 'response')): raise TypeError('Missing required parameter "%s"' % name) for name, regex in six.iteritems(parameters.pattern_params): if name in kwargs: if isinstance(kwargs[name], six.string_types): pvalues = [kwargs[name]] else: pvalues = kwargs[name] for pvalue in pvalues: if re.match(regex, pvalue) is None: raise TypeError( 'Parameter "%s" value "%s" does not match the pattern "%s"' % (name, pvalue, regex)) for name, enums in six.iteritems(parameters.enum_params): if name in kwargs: # We need to handle the case of a repeated enum # name differently, since we want to handle both # arg='value' and arg=['value1', 'value2'] if (name in parameters.repeated_params and not isinstance(kwargs[name], six.string_types)): values = kwargs[name] else: values = [kwargs[name]] for value in values: if value not in enums: raise TypeError( 'Parameter "%s" value "%s" is not an allowed value in "%s"' % (name, value, str(enums))) actual_query_params = {} actual_path_params = {} for key, value in six.iteritems(kwargs): to_type = parameters.param_types.get(key, 'string') # For repeated parameters we cast each member of the list. if key in parameters.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 parameters.query_params: actual_query_params[parameters.argmap[key]] = cast_value if key in parameters.path_params: actual_path_params[parameters.argmap[key]] = cast_value body_value = kwargs.get('body', None) media_filename = kwargs.get('media_body', None) media_mime_type = kwargs.get('media_mime_type', None) if self._developerKey: actual_query_params['key'] = self._developerKey model = self._model if methodName.endswith('_media'): model = MediaModel() elif 'response' not in methodDesc: model = RawModel() headers = {} headers, params, query, body = model.request(headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) resumable = None multipart_boundary = '' if media_filename: # Ensure we end up with a valid MediaUpload object. if isinstance(media_filename, six.string_types): if media_mime_type is None: logger.warning( 'media_mime_type argument not specified: trying to auto-detect for %s', media_filename) media_mime_type, _ = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ','.join(accept)): raise UnacceptableMimeTypeError(media_mime_type) media_upload = MediaFileUpload(media_filename, mimetype=media_mime_type) elif isinstance(media_filename, MediaUpload): media_upload = media_filename else: raise TypeError('media_filename must be str or MediaUpload.') # Check the maxSize if media_upload.size( ) is not None and media_upload.size() > maxSize > 0: raise MediaUploadSizeError("Media larger than: %s" % maxSize) # Use the media path uri for media uploads expanded_url = uritemplate.expand(mediaPathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) if media_upload.resumable(): url = _add_query_parameter(url, 'uploadType', 'resumable') if media_upload.resumable(): # This is all we need to do for resumable, if the body exists it gets # sent in the first request, otherwise an empty body is sent. resumable = media_upload else: # A non-resumable upload if body is None: # This is a simple media upload headers['content-type'] = media_upload.mimetype() body = media_upload.getbytes(0, media_upload.size()) url = _add_query_parameter(url, 'uploadType', 'media') else: # This is a multipart/related upload. msgRoot = MIMEMultipart('related') # msgRoot should not write out it's own headers setattr(msgRoot, '_write_headers', lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers['content-type'].split('/')) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_upload.mimetype().split('/')) msg['Content-Transfer-Encoding'] = 'binary' payload = media_upload.getbytes(0, media_upload.size()) msg.set_payload(payload) msgRoot.attach(msg) # encode the body: note that we can't use `as_string`, because # it plays games with `From ` lines. fp = BytesIO() g = _BytesGenerator(fp, mangle_from_=False) g.flatten(msgRoot, unixfrom=False) body = fp.getvalue() multipart_boundary = msgRoot.get_boundary() headers['content-type'] = ( 'multipart/related; ' 'boundary="%s"') % multipart_boundary url = _add_query_parameter(url, 'uploadType', 'multipart') logger.info('URL being requested: %s %s' % (httpMethod, url)) return self._requestBuilder(self._http, model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId, resumable=resumable)
def method(self, **kwargs): # Don't bother with doc string, it will be over-written by createMethod. for name in six.iterkeys(kwargs): if name not in parameters.argmap: raise TypeError('Got an unexpected keyword argument "{0!s}"'.format(name)) # Remove args that have a value of None. keys = list(kwargs.keys()) for name in keys: if kwargs[name] is None: del kwargs[name] for name in parameters.required_params: if name not in kwargs: raise TypeError('Missing required parameter "{0!s}"'.format(name)) for name, regex in six.iteritems(parameters.pattern_params): if name in kwargs: if isinstance(kwargs[name], six.string_types): pvalues = [kwargs[name]] else: pvalues = kwargs[name] for pvalue in pvalues: if re.match(regex, pvalue) is None: raise TypeError( 'Parameter "{0!s}" value "{1!s}" does not match the pattern "{2!s}"'.format( name, pvalue, regex ) ) for name, enums in six.iteritems(parameters.enum_params): if name in kwargs: # We need to handle the case of a repeated enum # name differently, since we want to handle both # arg='value' and arg=['value1', 'value2'] if name in parameters.repeated_params and not isinstance(kwargs[name], six.string_types): values = kwargs[name] else: values = [kwargs[name]] for value in values: if value not in enums: raise TypeError( 'Parameter "{0!s}" value "{1!s}" is not an allowed value in "{2!s}"'.format( name, value, str(enums) ) ) actual_query_params = {} actual_path_params = {} for key, value in six.iteritems(kwargs): to_type = parameters.param_types.get(key, "string") # For repeated parameters we cast each member of the list. if key in parameters.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 parameters.query_params: actual_query_params[parameters.argmap[key]] = cast_value if key in parameters.path_params: actual_path_params[parameters.argmap[key]] = cast_value body_value = kwargs.get("body", None) media_filename = kwargs.get("media_body", None) if self._developerKey: actual_query_params["key"] = self._developerKey model = self._model if methodName.endswith("_media"): model = MediaModel() elif "response" not in methodDesc: model = RawModel() headers = {} headers, params, query, body = model.request(headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) resumable = None multipart_boundary = "" if media_filename: # Ensure we end up with a valid MediaUpload object. if isinstance(media_filename, six.string_types): (media_mime_type, encoding) = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ",".join(accept)): raise UnacceptableMimeTypeError(media_mime_type) media_upload = MediaFileUpload(media_filename, mimetype=media_mime_type) elif isinstance(media_filename, MediaUpload): media_upload = media_filename else: raise TypeError("media_filename must be str or MediaUpload.") # Check the maxSize if media_upload.size() is not None and media_upload.size() > maxSize > 0: raise MediaUploadSizeError("Media larger than: {0!s}".format(maxSize)) # Use the media path uri for media uploads expanded_url = uritemplate.expand(mediaPathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) if media_upload.resumable(): url = _add_query_parameter(url, "uploadType", "resumable") if media_upload.resumable(): # This is all we need to do for resumable, if the body exists it gets # sent in the first request, otherwise an empty body is sent. resumable = media_upload else: # A non-resumable upload if body is None: # This is a simple media upload headers["content-type"] = media_upload.mimetype() body = media_upload.getbytes(0, media_upload.size()) url = _add_query_parameter(url, "uploadType", "media") else: # This is a multipart/related upload. msgRoot = MIMEMultipart("related") # msgRoot should not write out it's own headers setattr(msgRoot, "_write_headers", lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers["content-type"].split("/")) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_upload.mimetype().split("/")) msg["Content-Transfer-Encoding"] = "binary" payload = media_upload.getbytes(0, media_upload.size()) msg.set_payload(payload) msgRoot.attach(msg) # encode the body: note that we can't use `as_string`, because # it plays games with `From ` lines. fp = BytesIO() g = _BytesGenerator(fp, mangle_from_=False) g.flatten(msgRoot, unixfrom=False) body = fp.getvalue() multipart_boundary = msgRoot.get_boundary() headers["content-type"] = ("multipart/related; " 'boundary="%s"') % multipart_boundary url = _add_query_parameter(url, "uploadType", "multipart") logger.info("URL being requested: {0!s} {1!s}".format(httpMethod, url)) return self._requestBuilder( self._http, model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId, resumable=resumable, )