Exemple #1
0
    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)

        # TODO: Google API does not recognize the PNG content type
        #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(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)
        self.assertEqual(media_upload, request.resumable)

        # TODO: Google API does not recognize the PNG content type
        # self.assertEqual('image/png', request.resumable.mimetype())

        # self.assertEqual(request.body, None)
        # self.assertEqual(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.assertEqual(None, body)
        self.assertTrue(isinstance(status, MediaUploadProgress))
        self.assertEqual(13, status.resumable_progress)

        # Two requests should have been made and the resumable_uri should have been
        # updated for each one.
        self.assertEqual(request.resumable_uri, "http://upload.example.com/2")

        self.assertEqual(media_upload, request.resumable)
        self.assertEqual(13, request.resumable_progress)

        status, body = request.next_chunk(http=http)
        self.assertEqual(request.resumable_uri, "http://upload.example.com/3")
        self.assertEqual(media_upload.size() - 1, request.resumable_progress)
        self.assertEqual(request.body, None)

        # Final call to next_chunk should complete the upload.
        status, body = request.next_chunk(http=http)
        self.assertEqual(body, {"foo": "bar"})
        self.assertEqual(status, None)
  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)

    # TODO: Google API does not recognize the PNG content type
    #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)
Exemple #4
0
    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 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 updateFile(self, localFilePath, remoteFile, timestamp):
     body = {
         'parents': [{
             'id': self.id
         }],
         'title':
         remoteFile.name,
         'modifiedDate':
         datetime.utcfromtimestamp(timestamp).isoformat() + '.000Z'
     }
     media_body = MediaFileUpload(localFilePath,
                                  mimetype='*/*',
                                  resumable=True)
     if media_body != None and media_body.size() > 0:
         request = self.service.files().update(fileId=remoteFile.id,
                                               body=body,
                                               media_body=media_body,
                                               setModifiedDate=True)
         response = None
         while response is None:
             status, response = request.next_chunk()
         item = response
         return self.getFileFromItem(item)
     else:
         request = self.service.files().update(fileId=remoteFile.id,
                                               body=body,
                                               setModifiedDate=True)
         response = request.execute()
         return self.getFileFromItem(response)
Exemple #7
0
    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))
Exemple #8
0
  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))
Exemple #9
0
    def update(self, new_path=None, parent_id='root'):
        try:
            if not hasattr(self, 'id'):
                return self.create(parent_id)

            existing_file = self.get_file(self.id)

            if new_path is not None:
                self.path = new_path

            mime_type = defaul_mime_type
            media_body = None

            if not os.path.isdir(self.path):
                media_body = MediaFileUpload(self.path, resumable=True)
                if media_body.size() == 0:
                    logger.error('cannot update no content file %s', self.path)
                    return None
                if media_body.mimetype() is not None:
                    mime_type = media_body.mimetype()
                else:
                    media_body._mimetype = mime_type
            else:
                mime_type = folder_mime_type

            existing_file['title'] = os.path.basename(self.path)
            existing_file['parents'] = [{'id': parent_id}]
            existing_file['mimeType'] = mime_type

            logger.info('updated %s', self.path)
            with drive.lock:
                metadata = drive.service.files().update(
                    fileId=self.id,
                    body=existing_file,
                    media_body=media_body).execute()

            self.id = metadata['id']
            if metadata.has_key('downloadUrl'):
                self.download_url = metadata['downloadUrl']
            if metadata.has_key('md5Checksum'):
                self.md5Checksum = metadata['md5Checksum']
            return metadata
        except errors.HttpError, error:
            logger.error('an error occurred: %s', error)
            return None
 def updateFile(self, localFilePath, remoteFile, timestamp):
     body = {
         "parents": [{"id": self.id}],
         "title": remoteFile.name,
         "modifiedDate": datetime.utcfromtimestamp(timestamp).isoformat() + ".000Z",
     }
     media_body = MediaFileUpload(localFilePath, mimetype="*/*", resumable=True)
     if media_body != None and media_body.size() > 0:
         request = self.service.files().update(
             fileId=remoteFile.id, body=body, media_body=media_body, setModifiedDate=True
         )
         response = None
         while response is None:
             status, response = request.next_chunk()
         item = response
         return self.getFileFromItem(item)
     else:
         request = self.service.files().update(fileId=remoteFile.id, body=body, setModifiedDate=True)
         response = request.execute()
         return self.getFileFromItem(response)
Exemple #11
0
    def create(self, parent_id='root'):
        mime_type = defaul_mime_type
        media_body = None

        if not os.path.isdir(self.path):
            media_body = MediaFileUpload(self.path, resumable=True)
            if media_body.size() == 0:
                logger.error('cannot create no content file %s', self.path)
                return None
            if media_body.mimetype() is not None:
                mime_type = media_body.mimetype()
            else:
                media_body._mimetype = mime_type
        else:
            mime_type = folder_mime_type

        body = {
            'title': os.path.basename(self.path),
            'mimeType': mime_type,
            'parents': [{'id': parent_id}]
        }

        try:
            with drive.lock:
                metadata = drive.service.files().insert(
                    body=body,
                    media_body=media_body).execute()

            logger.info('created %s, %s', self.path, body['mimeType'])

            self.id = metadata['id']
            if metadata.has_key('downloadUrl'):
                self.download_url = metadata['downloadUrl']
            if metadata.has_key('md5Checksum'):
                self.md5Checksum = metadata['md5Checksum']
            return metadata
        except errors.HttpError, error:
            logger.error('an error occurred: %s', error)
            return None
Exemple #12
0
    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 = _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 = _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 = StringIO.StringIO()
                    g = Generator(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)
Exemple #13
0
    def method(self, **kwargs):
      for name in six.iterkeys(kwargs):
        if name not in argmap:
          raise TypeError('Got an unexpected keyword argument "%s"' % name)

      for name in required_params:
        if name not in kwargs:
          raise TypeError('Missing required parameter "%s"' % name)

      for name, regex in six.iteritems(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(enum_params):
        if name in kwargs:
          if kwargs[name] not in enums:
            raise TypeError(
                'Parameter "%s" value "%s" is not an allowed value in "%s"' %
                (name, kwargs[name], str(enums)))

      actual_query_params = {}
      actual_path_params = {}
      for key, value in six.iteritems(kwargs):
        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]] = cast_value
        if key in path_params:
          actual_path_params[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 there is no schema for the response then presume a binary blob.
      if '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 = six.moves.urllib.parse.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, 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
        if media_upload.resumable():
          expanded_url = uritemplate.expand(mediaResumablePathUrl, params)
        else:
          expanded_url = uritemplate.expand(mediaPathUrl, params)
        url = six.moves.urllib.parse.urljoin(self._baseUrl, expanded_url + query)

        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())
          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

      logging.info('URL being requested: %s' % url)
      return self._requestBuilder(self._http,
                                  model.response,
                                  url,
                                  method=httpMethod,
                                  body=body,
                                  headers=headers,
                                  methodId=methodId,
                                  resumable=resumable)
Exemple #14
0
        def method(self, **kwargs):
            for name in kwargs.iterkeys():
                if name not in argmap:
                    raise TypeError('Got an unexpected keyword argument "%s"' % name)

            for name in required_params:
                if name not in kwargs:
                    raise TypeError('Missing required parameter "%s"' % name)

            for name, regex in 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 enum_params.iteritems():
                if name in kwargs:
                    if kwargs[name] not in enums:
                        raise TypeError(
                            'Parameter "%s" value "%s" is not an allowed value in "%s"'
                            % (name, kwargs[name], str(enums))
                        )

            actual_query_params = {}
            actual_path_params = {}
            for key, value in kwargs.iteritems():
                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]] = cast_value
                if key in path_params:
                    actual_path_params[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 there is no schema for the response then presume a binary blob.
            if "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, 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
                if media_upload.resumable():
                    expanded_url = uritemplate.expand(mediaResumablePathUrl, params)
                else:
                    expanded_url = uritemplate.expand(mediaPathUrl, params)
                url = urlparse.urljoin(self._baseUrl, expanded_url + query)

                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())
                    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

            logging.info("URL being requested: %s" % url)
            return self._requestBuilder(
                self._http,
                model.response,
                url,
                method=httpMethod,
                body=body,
                headers=headers,
                methodId=methodId,
                resumable=resumable,
            )
    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.assertEqual(body, {"foo": "bar"})
Exemple #16
0
    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' % url)
        return self._requestBuilder(self._http,
                                    model.response,
                                    url,
                                    method=httpMethod,
                                    body=body,
                                    headers=headers,
                                    methodId=methodId,
                                    resumable=resumable)
Exemple #17
0
    def method(self, **kwargs):
      for name in kwargs.iterkeys():
        if name not in argmap:
          raise TypeError('Got an unexpected keyword argument "%s"' % name)

      for name in required_params:
        if name not in kwargs:
          raise TypeError('Missing required parameter "%s"' % name)

      for name, regex in 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 enum_params.iteritems():
        if name in kwargs:
          if kwargs[name] not in enums:
            raise TypeError(
                'Parameter "%s" value "%s" is not an allowed value in "%s"' %
                (name, kwargs[name], str(enums)))

      actual_query_params = {}
      actual_path_params = {}
      for key, value in kwargs.iteritems():
        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]] = cast_value
        if key in path_params:
          actual_path_params[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 there is no schema for the response then presume a binary blob.
      if '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:
        # Convert a simple filename into a 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, media_mime_type)
        elif isinstance(media_filename, MediaUpload):
          media_upload = media_filename
        else:
          raise TypeError('media_filename must be str or MediaUpload.')

        if media_upload.resumable():
          resumable = media_upload

        # 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
        if media_upload.resumable():
          expanded_url = uritemplate.expand(mediaResumablePathUrl, params)
        else:
          expanded_url = uritemplate.expand(mediaPathUrl, params)
        url = urlparse.urljoin(self._baseUrl, expanded_url + query)

        if body is None:
          # This is a simple media upload
          headers['content-type'] = media_upload.mimetype()
          expanded_url = uritemplate.expand(mediaResumablePathUrl, params)
          if not media_upload.resumable():
            body = media_upload.getbytes(0, media_upload.size())
        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'

          if media_upload.resumable():
            # This is a multipart resumable upload, where a multipart payload
            # looks like this:
            #
            #  --===============1678050750164843052==
            #  Content-Type: application/json
            #  MIME-Version: 1.0
            #
            #  {'foo': 'bar'}
            #  --===============1678050750164843052==
            #  Content-Type: image/png
            #  MIME-Version: 1.0
            #  Content-Transfer-Encoding: binary
            #
            #  <BINARY STUFF>
            #  --===============1678050750164843052==--
            #
            # In the case of resumable multipart media uploads, the <BINARY
            # STUFF> is large and will be spread across multiple PUTs.  What we
            # do here is compose the multipart message with a random payload in
            # place of <BINARY STUFF> and then split the resulting content into
            # two pieces, text before <BINARY STUFF> and text after <BINARY
            # STUFF>. The text after <BINARY STUFF> is the multipart boundary.
            # In apiclient.http the HttpRequest will send the text before
            # <BINARY STUFF>, then send the actual binary media in chunks, and
            # then will send the multipart delimeter.

            payload = hex(random.getrandbits(300))
            msg.set_payload(payload)
            msgRoot.attach(msg)
            body = msgRoot.as_string()
            body, _ = body.split(payload)
            resumable = media_upload
          else:
            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

      logging.info('URL being requested: %s' % url)
      return self._requestBuilder(self._http,
                                  model.response,
                                  url,
                                  method=httpMethod,
                                  body=body,
                                  headers=headers,
                                  methodId=methodId,
                                  resumable=resumable)
Exemple #18
0
        def method(self, **kwargs):
            for name in kwargs.iterkeys():
                if name not in argmap:
                    raise TypeError('Got an unexpected keyword argument "%s"' %
                                    name)

            for name in required_params:
                if name not in kwargs:
                    raise TypeError('Missing required parameter "%s"' % name)

            for name, regex in 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 enum_params.iteritems():
                if name in kwargs:
                    if kwargs[name] not in enums:
                        raise TypeError(
                            'Parameter "%s" value "%s" is not an allowed value in "%s"'
                            % (name, kwargs[name], str(enums)))

            actual_query_params = {}
            actual_path_params = {}
            for key, value in kwargs.iteritems():
                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]] = cast_value
                if key in path_params:
                    actual_path_params[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 there is no schema for the response then presume a binary blob.
            if '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:
                # Convert a simple filename into a 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,
                                                   media_mime_type)
                elif isinstance(media_filename, MediaUpload):
                    media_upload = media_filename
                else:
                    raise TypeError(
                        'media_filename must be str or MediaUpload.')

                if media_upload.resumable():
                    resumable = media_upload

                # 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
                if media_upload.resumable():
                    expanded_url = uritemplate.expand(mediaResumablePathUrl,
                                                      params)
                else:
                    expanded_url = uritemplate.expand(mediaPathUrl, params)
                url = urlparse.urljoin(self._baseUrl, expanded_url + query)

                if body is None:
                    # This is a simple media upload
                    headers['content-type'] = media_upload.mimetype()
                    expanded_url = uritemplate.expand(mediaResumablePathUrl,
                                                      params)
                    if not media_upload.resumable():
                        body = media_upload.getbytes(0, media_upload.size())
                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'

                    if media_upload.resumable():
                        # This is a multipart resumable upload, where a multipart payload
                        # looks like this:
                        #
                        #  --===============1678050750164843052==
                        #  Content-Type: application/json
                        #  MIME-Version: 1.0
                        #
                        #  {'foo': 'bar'}
                        #  --===============1678050750164843052==
                        #  Content-Type: image/png
                        #  MIME-Version: 1.0
                        #  Content-Transfer-Encoding: binary
                        #
                        #  <BINARY STUFF>
                        #  --===============1678050750164843052==--
                        #
                        # In the case of resumable multipart media uploads, the <BINARY
                        # STUFF> is large and will be spread across multiple PUTs.  What we
                        # do here is compose the multipart message with a random payload in
                        # place of <BINARY STUFF> and then split the resulting content into
                        # two pieces, text before <BINARY STUFF> and text after <BINARY
                        # STUFF>. The text after <BINARY STUFF> is the multipart boundary.
                        # In apiclient.http the HttpRequest will send the text before
                        # <BINARY STUFF>, then send the actual binary media in chunks, and
                        # then will send the multipart delimeter.

                        payload = hex(random.getrandbits(300))
                        msg.set_payload(payload)
                        msgRoot.attach(msg)
                        body = msgRoot.as_string()
                        body, _ = body.split(payload)
                        resumable = media_upload
                    else:
                        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

            logging.info('URL being requested: %s' % url)
            return self._requestBuilder(self._http,
                                        model.response,
                                        url,
                                        method=httpMethod,
                                        body=body,
                                        headers=headers,
                                        methodId=methodId,
                                        resumable=resumable)