'Store an object in S3 using the name of the Key object as the
key in S3 and the contents of the file pointed to by \'fp\' as the
contents. The data is read from \'fp\' from its current position until
\'size\' bytes have been read or EOF.
:type fp: file
:param fp: the file whose contents to upload
:type headers: dict
:param headers: Additional HTTP headers that will be sent with
the PUT request.
:type replace: bool
:param replace: If this parameter is False, the method will
first check to see if an object exists in the bucket with
the same key.  If it does, it won\'t overwrite it.  The
default value is True which will overwrite the object.
:type cb: function
:param cb: a callback function that will be called to report
progress on the upload.  The callback should accept two
integer parameters, the first representing the number of
bytes that have been successfully transmitted to S3 and
the second representing the size of the to be transmitted
object.
:type num_cb: int
:param num_cb: (optional) If a callback is specified with the
cb parameter this parameter determines the granularity of
the callback by defining the maximum number of times the
callback will be called during the file transfer.
:type policy: :class:`boto.s3.acl.CannedACLStrings`
:param policy: A canned ACL policy that will be applied to the
new key in S3.
:type md5: A tuple containing the hexdigest version of the MD5
checksum of the file as the first element and the
Base64-encoded version of the plain checksum as the second
element.  This is the same format returned by the
compute_md5 method.
:param md5: If you need to compute the MD5 for any reason
prior to upload, it\'s silly to have to do it twice so this
param, if present, will be used as the MD5 values of the
file.  Otherwise, the checksum will be computed.
:type reduced_redundancy: bool
:param reduced_redundancy: If True, this will set the storage
class of the new Key to be REDUCED_REDUNDANCY. The Reduced
Redundancy Storage (RRS) feature of S3, provides lower
redundancy at lower storage cost.
:type encrypt_key: bool
:param encrypt_key: If True, the new copy of the object will
be encrypted on the server-side by S3 and will be stored
in an encrypted form while at rest in S3.
:type size: int
:param size: (optional) The Maximum number of bytes to read
from the file pointer (fp). This is useful when uploading
a file in multiple parts where you are splitting the file
up into different ranges to be uploaded. If not specified,
the default behaviour is to read all bytes from the file
pointer. Less bytes may be available.
:type rewind: bool
:param rewind: (optional) If True, the file pointer (fp) will
be rewound to the start before any bytes are read from
it. The default behaviour is False which reads from the
current position of the file pointer (fp).
:rtype: int
:return: The number of bytes written to the key.'

def set_contents_from_file(self, fp, headers=None, replace=True, cb=None, num_cb=10, policy=None, md5=None, reduced_redundancy=False, query_args=None, encrypt_key=False, size=None, rewind=False):

    provider = self.bucket.connection.provider
    headers = (headers or {})
    if policy:
        headers[provider.acl_header] = policy
    if encrypt_key:
        headers[provider.server_side_encryption_header] = 'AES256'
    if rewind:
        fp.seek(0, os.SEEK_SET)
    elif (not isinstance(fp, KeyFile)):
        spos = fp.tell()
        fp.seek(0, os.SEEK_END)
        if (fp.tell() == spos):
            fp.seek(0, os.SEEK_SET)
            if (fp.tell() != spos):
                fp.seek(spos)
                raise AttributeError('fp    is    at    EOF.    Use    rewind    option    or    seek()    to    data    start.')
        fp.seek(spos)
    if reduced_redundancy:
        self.storage_class = 'REDUCED_REDUNDANCY'
        if provider.storage_class_header:
            headers[provider.storage_class_header] = self.storage_class
    if hasattr(fp, 'name'):
        self.path = fp.name
    if (self.bucket is not None):
        if ((not md5) and provider.supports_chunked_transfer()):
            chunked_transfer = True
            self.size = None
        else:
            chunked_transfer = False
            if isinstance(fp, KeyFile):
                key = fp.getkey()
                size = (key.size - fp.tell())
                self.size = size
                if re.match('^"[a-fA-F0-9]{32}"$', key.etag):
                    etag = key.etag.strip('"')
                    md5 = (etag, base64.b64encode(binascii.unhexlify(etag)))
            if (not md5):
                md5 = self.compute_md5(fp, size)
                size = self.size
            elif size:
                self.size = size
            else:
                spos = fp.tell()
                fp.seek(0, os.SEEK_END)
                self.size = (fp.tell() - spos)
                fp.seek(spos)
                size = self.size
            self.md5 = md5[0]
            self.base64md5 = md5[1]
        if (self.name is None):
            self.name = self.md5
        if (not replace):
            if self.bucket.lookup(self.name):
                return
        self.send_file(fp, headers=headers, cb=cb, num_cb=num_cb, query_args=query_args, chunked_transfer=chunked_transfer, size=size)
        return self.size
