def send_file(self, fp, headers=None, cb=None, num_cb=10,
                  query_args=None, chunked_transfer=False, callback=None):
        provider = self.bucket.connection.provider

        def sender(http_conn, method, path, data, headers, sendback=None):
            http_conn.putrequest(method, path)
            for key in headers:
                http_conn.putheader(key, headers[key])
            http_conn.endheaders()
            if chunked_transfer:
                # MD5 for the stream has to be calculated on the fly, as
                # we don't know the size of the stream before hand.
                m = md5()
            else:
                fp.seek(0)

            save_debug = self.bucket.connection.debug
            self.bucket.connection.debug = 0
            # If the debuglevel < 3 we don't want to show connection
            # payload, so turn off HTTP connection-level debug output (to
            # be restored below).
            # Use the getattr approach to allow this to work in AppEngine.
            if getattr(http_conn, 'debuglevel', 0) < 3:
                http_conn.set_debuglevel(0)
            if cb:
                if chunked_transfer:
                    # For chunked Transfer, we call the cb for every 1MB
                    # of data transferred.
                    cb_count = (1024 * 1024)/self.BufferSize
                    self.size = 0
                elif num_cb > 2:
                    cb_count = self.size / self.BufferSize / (num_cb-2)
                elif num_cb < 0:
                    cb_count = -1
                else:
                    cb_count = 0
                i = total_bytes = 0
                cb(total_bytes, self.size)
            l = fp.read(self.BufferSize)
            while len(l) > 0:
                if chunked_transfer:
                    http_conn.send('%x;\r\n' % len(l))
                    http_conn.send(l)
                    http_conn.send('\r\n')
                else:
                    http_conn.send(l)
                if cb:
                    total_bytes += len(l)
                    i += 1
                    if i == cb_count or cb_count == -1:
                        cb(total_bytes, self.size)
                        i = 0
                if chunked_transfer:
                    m.update(l)
                l = fp.read(self.BufferSize)
            if chunked_transfer:
                http_conn.send('0\r\n')
                http_conn.send('\r\n')
                if cb:
                    self.size = total_bytes
                # Get the md5 which is calculated on the fly.
                self.md5 = m.hexdigest()
            else:
                fp.seek(0)
            if cb:
                cb(total_bytes, self.size)
            def sender_sent(response):
                body = response.read()
                http_conn.set_debuglevel(save_debug)
                self.bucket.connection.debug = save_debug
                if ((response.status == 500 or response.status == 503 or
                        response.getheader('location')) and not chunked_transfer):
                    # we'll try again.
                    if callable(sendback):
                        sendback(response)
                elif response.status >= 200 and response.status <= 299:
                    self.etag = response.getheader('etag')
                    if self.etag != '"%s"'  % self.md5:
                        raise provider.storage_data_error(
                            'ETag from S3 did not match computed MD5')
                    if callable(sendback):
                        sendback(response)
                else:
                    raise provider.storage_response_error(
                        response.status, response.reason, body)
            http_conn.getresponse(callback=sender_sent)

        if not headers:
            headers = {}
        else:
            headers = headers.copy()
        headers['User-Agent'] = UserAgent
        if self.base64md5:
            headers['Content-MD5'] = self.base64md5
        if self.storage_class != 'STANDARD':
            headers[provider.storage_class_header] = self.storage_class
        if headers.has_key('Content-Encoding'):
            self.content_encoding = headers['Content-Encoding']
        if headers.has_key('Content-Type'):
            self.content_type = headers['Content-Type']
        elif self.path:
            self.content_type = mimetypes.guess_type(self.path)[0]
            if self.content_type == None:
                self.content_type = self.DefaultContentType
            headers['Content-Type'] = self.content_type
        else:
            headers['Content-Type'] = self.content_type
        if not chunked_transfer:
            headers['Content-Length'] = str(self.size)
#       headers['Expect'] = '100-Continue'
        headers = boto.utils.merge_meta(headers, self.metadata, provider)
        def file_sent(resp):
            self.handle_version_headers(resp, force=True)
            if callable(callback):
                callback(resp)
        self.bucket.connection.make_request('PUT', self.bucket.name,
                                            self.name, headers,
                                            sender=sender,
                                            query_args=query_args, callback=file_sent)
Upload a file to a key into a bucket on S3.
dataset/ETHPy150Open yyuu/botornado/botornado/s3/key.py/AsyncKey.send_file