'Uploads data from an iterator in fixed sized chunks to S3
:param container: The destination container
:type container: :class:`Container`
:param object_name: The name of the object which we are uploading
:type object_name: ``str``
:param upload_id: The upload id allocated for this multipart upload
:type upload_id: ``str``
:param stream: The generator for fetching the upload data
:type stream: ``generator``
:keyword calculate_hash: Indicates if we must calculate the data hash
:type calculate_hash: ``bool``
:return: A tuple of (chunk info, checksum, bytes transferred)
:rtype: ``tuple``'

def _upload_multipart_chunks(self, container, object_name, upload_id, stream, calculate_hash=True):

    data_hash = None
    if calculate_hash:
        data_hash = self._get_hash_function()
    bytes_transferred = 0
    count = 1
    chunks = []
    params = {'uploadId': upload_id}
    request_path = self._get_object_path(container, object_name)
    for data in read_in_chunks(stream, chunk_size=CHUNK_SIZE, fill_size=True, yield_empty=True):
        bytes_transferred += len(data)
        if calculate_hash:
            data_hash.update(data)
        chunk_hash = self._get_hash_function()
        chunk_hash.update(data)
        chunk_hash = base64.b64encode(chunk_hash.digest()).decode('utf-8')
        headers = {'Content-Length': len(data), 'Content-MD5': chunk_hash}
        params['partNumber'] = count
        resp = self.connection.request(request_path, method='PUT', data=data, headers=headers, params=params)
        if (resp.status != httplib.OK):
            raise LibcloudError('Error    uploading    chunk', driver=self)
        server_hash = resp.headers['etag'].replace('"', '')
        chunks.append((count, server_hash))
        count += 1
    if calculate_hash:
        data_hash = data_hash.hexdigest()
    return (chunks, data_hash, bytes_transferred)
