diff env/lib/python3.7/site-packages/boto/gs/key.py @ 5:9b1c78e6ba9c draft default tip

"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author shellac
date Mon, 01 Jun 2020 08:59:25 -0400
parents 79f47841a781
children
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/boto/gs/key.py	Thu May 14 16:47:39 2020 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,948 +0,0 @@
-# Copyright 2010 Google Inc.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-import base64
-import binascii
-import os
-import re
-
-from boto.compat import StringIO
-from boto.exception import BotoClientError
-from boto.s3.key import Key as S3Key
-from boto.s3.keyfile import KeyFile
-from boto.utils import compute_hash
-from boto.utils import get_utf8_value
-
-class Key(S3Key):
-    """
-    Represents a key (object) in a GS bucket.
-
-    :ivar bucket: The parent :class:`boto.gs.bucket.Bucket`.
-    :ivar name: The name of this Key object.
-    :ivar metadata: A dictionary containing user metadata that you
-        wish to store with the object or that has been retrieved from
-        an existing object.
-    :ivar cache_control: The value of the `Cache-Control` HTTP header.
-    :ivar content_type: The value of the `Content-Type` HTTP header.
-    :ivar content_encoding: The value of the `Content-Encoding` HTTP header.
-    :ivar content_disposition: The value of the `Content-Disposition` HTTP
-        header.
-    :ivar content_language: The value of the `Content-Language` HTTP header.
-    :ivar etag: The `etag` associated with this object.
-    :ivar last_modified: The string timestamp representing the last
-        time this object was modified in GS.
-    :ivar owner: The ID of the owner of this object.
-    :ivar storage_class: The storage class of the object. Currently, one of:
-        STANDARD | DURABLE_REDUCED_AVAILABILITY.
-    :ivar md5: The MD5 hash of the contents of the object.
-    :ivar size: The size, in bytes, of the object.
-    :ivar generation: The generation number of the object.
-    :ivar metageneration: The generation number of the object metadata.
-    :ivar encrypted: Whether the object is encrypted while at rest on
-        the server.
-    :ivar cloud_hashes: Dictionary of checksums as supplied by the storage
-        provider.
-    """
-
-    def __init__(self, bucket=None, name=None, generation=None):
-        super(Key, self).__init__(bucket=bucket, name=name)
-        self.generation = generation
-        self.meta_generation = None
-        self.cloud_hashes = {}
-        self.component_count = None
-
-    def __repr__(self):
-        if self.generation and self.metageneration:
-            ver_str = '#%s.%s' % (self.generation, self.metageneration)
-        else:
-            ver_str = ''
-        if self.bucket:
-            return '<Key: %s,%s%s>' % (self.bucket.name, self.name, ver_str)
-        else:
-            return '<Key: None,%s%s>' % (self.name, ver_str)
-
-    def endElement(self, name, value, connection):
-        if name == 'Key':
-            self.name = value
-        elif name == 'ETag':
-            self.etag = value
-        elif name == 'IsLatest':
-            if value == 'true':
-                self.is_latest = True
-            else:
-                self.is_latest = False
-        elif name == 'LastModified':
-            self.last_modified = value
-        elif name == 'Size':
-            self.size = int(value)
-        elif name == 'StorageClass':
-            self.storage_class = value
-        elif name == 'Owner':
-            pass
-        elif name == 'VersionId':
-            self.version_id = value
-        elif name == 'Generation':
-            self.generation = value
-        elif name == 'MetaGeneration':
-            self.metageneration = value
-        else:
-            setattr(self, name, value)
-
-    def handle_version_headers(self, resp, force=False):
-        self.metageneration = resp.getheader('x-goog-metageneration', None)
-        self.generation = resp.getheader('x-goog-generation', None)
-
-    def handle_restore_headers(self, response):
-        return
-
-    def handle_addl_headers(self, headers):
-        for key, value in headers:
-            if key == 'x-goog-hash':
-                for hash_pair in value.split(','):
-                    alg, b64_digest = hash_pair.strip().split('=', 1)
-                    self.cloud_hashes[alg] = binascii.a2b_base64(b64_digest)
-            elif key == 'x-goog-component-count':
-                self.component_count = int(value)
-            elif key == 'x-goog-generation':
-                self.generation = value
-            # Use x-goog-stored-content-encoding and
-            # x-goog-stored-content-length to indicate original content length
-            # and encoding, which are transcoding-invariant (so are preferable
-            # over using content-encoding and size headers).
-            elif key == 'x-goog-stored-content-encoding':
-                self.content_encoding = value
-            elif key == 'x-goog-stored-content-length':
-                self.size = int(value)
-            elif key == 'x-goog-storage-class':
-                self.storage_class = value
-
-    def open_read(self, headers=None, query_args='',
-                  override_num_retries=None, response_headers=None):
-        """
-        Open this key for reading
-
-        :type headers: dict
-        :param headers: Headers to pass in the web request
-
-        :type query_args: string
-        :param query_args: Arguments to pass in the query string
-            (ie, 'torrent')
-
-        :type override_num_retries: int
-        :param override_num_retries: If not None will override configured
-            num_retries parameter for underlying GET.
-
-        :type response_headers: dict
-        :param response_headers: A dictionary containing HTTP
-            headers/values that will override any headers associated
-            with the stored object in the response.  See
-            http://goo.gl/EWOPb for details.
-        """
-        # For GCS we need to include the object generation in the query args.
-        # The rest of the processing is handled in the parent class.
-        if self.generation:
-            if query_args:
-                query_args += '&'
-            query_args += 'generation=%s' % self.generation
-        super(Key, self).open_read(headers=headers, query_args=query_args,
-                                   override_num_retries=override_num_retries,
-                                   response_headers=response_headers)
-
-    def get_file(self, fp, headers=None, cb=None, num_cb=10,
-                 torrent=False, version_id=None, override_num_retries=None,
-                 response_headers=None, hash_algs=None):
-        query_args = None
-        if self.generation:
-            query_args = ['generation=%s' % self.generation]
-        self._get_file_internal(fp, headers=headers, cb=cb, num_cb=num_cb,
-                                override_num_retries=override_num_retries,
-                                response_headers=response_headers,
-                                hash_algs=hash_algs,
-                                query_args=query_args)
-
-    def get_contents_to_file(self, fp, headers=None,
-                             cb=None, num_cb=10,
-                             torrent=False,
-                             version_id=None,
-                             res_download_handler=None,
-                             response_headers=None,
-                             hash_algs=None):
-        """
-        Retrieve an object from GCS using the name of the Key object as the
-        key in GCS. Write the contents of the object to the file pointed
-        to by 'fp'.
-
-        :type fp: File -like object
-        :param fp:
-
-        :type headers: dict
-        :param headers: additional HTTP headers that will be sent with
-            the GET request.
-
-        :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 GCS and
-            the second representing the size of the to be transmitted
-            object.
-
-        :type 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 torrent: bool
-        :param torrent: If True, returns the contents of a torrent
-            file as a string.
-
-        :type res_upload_handler: ResumableDownloadHandler
-        :param res_download_handler: If provided, this handler will
-            perform the download.
-
-        :type response_headers: dict
-        :param response_headers: A dictionary containing HTTP
-            headers/values that will override any headers associated
-            with the stored object in the response. See
-            http://goo.gl/sMkcC for details.
-        """
-        if self.bucket is not None:
-            if res_download_handler:
-                res_download_handler.get_file(self, fp, headers, cb, num_cb,
-                                              torrent=torrent,
-                                              version_id=version_id,
-                                              hash_algs=hash_algs)
-            else:
-                self.get_file(fp, headers, cb, num_cb, torrent=torrent,
-                              version_id=version_id,
-                              response_headers=response_headers,
-                              hash_algs=hash_algs)
-
-    def compute_hash(self, fp, algorithm, size=None):
-        """
-        :type fp: file
-        :param fp: File pointer to the file to hash. The file
-            pointer will be reset to the same position before the
-            method returns.
-
-        :type algorithm: zero-argument constructor for hash objects that
-            implements update() and digest() (e.g. hashlib.md5)
-
-        :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 the file is being split
-            in place into different parts. Less bytes may be available.
-        """
-        hex_digest, b64_digest, data_size = compute_hash(
-            fp, size=size, hash_algorithm=algorithm)
-        # The internal implementation of compute_hash() needs to return the
-        # data size, but we don't want to return that value to the external
-        # caller because it changes the class interface (i.e. it might
-        # break some code), so we consume the third tuple value here and
-        # return the remainder of the tuple to the caller, thereby preserving
-        # the existing interface.
-        self.size = data_size
-        return (hex_digest, b64_digest)
-
-    def send_file(self, fp, headers=None, cb=None, num_cb=10,
-                  query_args=None, chunked_transfer=False, size=None,
-                  hash_algs=None):
-        """
-        Upload a file to GCS.
-
-        :type fp: file
-        :param fp: The file pointer to upload. The file pointer must
-            point at the offset from which you wish to upload.
-            ie. if uploading the full file, it should point at the
-            start of the file. Normally when a file is opened for
-            reading, the fp will point at the first byte. See the
-            bytes parameter below for more info.
-
-        :type headers: dict
-        :param headers: The headers to pass along with the PUT request
-
-        :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. Providing a negative integer will cause your
-            callback to be called with each buffer read.
-
-        :type query_args: string
-        :param query_args: Arguments to pass in the query string.
-
-        :type chunked_transfer: boolean
-        :param chunked_transfer: (optional) If true, we use chunked
-            Transfer-Encoding.
-
-        :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 hash_algs: dictionary
-        :param hash_algs: (optional) Dictionary of hash algorithms and
-            corresponding hashing class that implements update() and digest().
-            Defaults to {'md5': hashlib.md5}.
-        """
-        self._send_file_internal(fp, headers=headers, cb=cb, num_cb=num_cb,
-                                 query_args=query_args,
-                                 chunked_transfer=chunked_transfer, size=size,
-                                 hash_algs=hash_algs)
-
-    def delete(self, headers=None):
-        return self.bucket.delete_key(self.name, version_id=self.version_id,
-                                      generation=self.generation,
-                                      headers=headers)
-
-    def add_email_grant(self, permission, email_address):
-        """
-        Convenience method that provides a quick way to add an email grant to a
-        key. This method retrieves the current ACL, creates a new grant based on
-        the parameters passed in, adds that grant to the ACL and then PUT's the
-        new ACL back to GS.
-
-        :type permission: string
-        :param permission: The permission being granted. Should be one of:
-            READ|FULL_CONTROL
-            See http://code.google.com/apis/storage/docs/developer-guide.html#authorization
-            for more details on permissions.
-
-        :type email_address: string
-        :param email_address: The email address associated with the Google
-                              account to which you are granting the permission.
-        """
-        acl = self.get_acl()
-        acl.add_email_grant(permission, email_address)
-        self.set_acl(acl)
-
-    def add_user_grant(self, permission, user_id):
-        """
-        Convenience method that provides a quick way to add a canonical user
-        grant to a key. This method retrieves the current ACL, creates a new
-        grant based on the parameters passed in, adds that grant to the ACL and
-        then PUT's the new ACL back to GS.
-
-        :type permission: string
-        :param permission: The permission being granted. Should be one of:
-            READ|FULL_CONTROL
-            See http://code.google.com/apis/storage/docs/developer-guide.html#authorization
-            for more details on permissions.
-
-        :type user_id: string
-        :param user_id: The canonical user id associated with the GS account to
-             which you are granting the permission.
-        """
-        acl = self.get_acl()
-        acl.add_user_grant(permission, user_id)
-        self.set_acl(acl)
-
-    def add_group_email_grant(self, permission, email_address, headers=None):
-        """
-        Convenience method that provides a quick way to add an email group
-        grant to a key. This method retrieves the current ACL, creates a new
-        grant based on the parameters passed in, adds that grant to the ACL and
-        then PUT's the new ACL back to GS.
-
-        :type permission: string
-        :param permission: The permission being granted. Should be one of:
-            READ|FULL_CONTROL
-            See http://code.google.com/apis/storage/docs/developer-guide.html#authorization
-            for more details on permissions.
-
-        :type email_address: string
-        :param email_address: The email address associated with the Google
-            Group to which you are granting the permission.
-        """
-        acl = self.get_acl(headers=headers)
-        acl.add_group_email_grant(permission, email_address)
-        self.set_acl(acl, headers=headers)
-
-    def add_group_grant(self, permission, group_id):
-        """
-        Convenience method that provides a quick way to add a canonical group
-        grant to a key. This method retrieves the current ACL, creates a new
-        grant based on the parameters passed in, adds that grant to the ACL and
-        then PUT's the new ACL back to GS.
-
-        :type permission: string
-        :param permission: The permission being granted. Should be one of:
-            READ|FULL_CONTROL
-            See http://code.google.com/apis/storage/docs/developer-guide.html#authorization
-            for more details on permissions.
-
-        :type group_id: string
-        :param group_id: The canonical group id associated with the Google
-            Groups account you are granting the permission to.
-        """
-        acl = self.get_acl()
-        acl.add_group_grant(permission, group_id)
-        self.set_acl(acl)
-
-    def set_contents_from_file(self, fp, headers=None, replace=True,
-                               cb=None, num_cb=10, policy=None, md5=None,
-                               res_upload_handler=None, size=None, rewind=False,
-                               if_generation=None):
-        """
-        Store an object in GS using the name of the Key object as the
-        key in GS and the contents of the file pointed to by 'fp' as the
-        contents.
-
-        :type fp: file
-        :param fp: The file whose contents are to be uploaded.
-
-        :type headers: dict
-        :param headers: (optional) Additional HTTP headers to be sent with the
-            PUT request.
-
-        :type replace: bool
-        :param replace: (optional) 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: (optional) 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 GS and the second representing the
-            total number of bytes that need to be transmitted.
-
-        :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.gs.acl.CannedACLStrings`
-        :param policy: (optional) A canned ACL policy that will be applied to
-            the new key in GS.
-
-        :type md5: tuple
-        :param md5: (optional) 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.
-
-            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 res_upload_handler: :py:class:`boto.gs.resumable_upload_handler.ResumableUploadHandler`
-        :param res_upload_handler: (optional) If provided, this handler will
-            perform the upload.
-
-        :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.
-
-            Notes:
-
-                1. The "size" parameter currently cannot be used when a
-                   resumable upload handler is given but is still useful for
-                   uploading part of a file as implemented by the parent class.
-                2. At present Google Cloud Storage does not support multipart
-                   uploads.
-
-        :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).
-
-        :type if_generation: int
-        :param if_generation: (optional) If set to a generation number, the
-            object will only be written to if its current generation number is
-            this value. If set to the value 0, the object will only be written
-            if it doesn't already exist.
-
-        :rtype: int
-        :return: The number of bytes written to the key.
-
-        TODO: At some point we should refactor the Bucket and Key classes,
-        to move functionality common to all providers into a parent class,
-        and provider-specific functionality into subclasses (rather than
-        just overriding/sharing code the way it currently works).
-        """
-        provider = self.bucket.connection.provider
-        if res_upload_handler and size:
-            # could use size instead of file_length if provided but...
-            raise BotoClientError(
-                '"size" param not supported for resumable uploads.')
-        headers = headers or {}
-        if policy:
-            headers[provider.acl_header] = policy
-
-        if rewind:
-            # caller requests reading from beginning of fp.
-            fp.seek(0, os.SEEK_SET)
-        else:
-            # The following seek/tell/seek logic is intended
-            # to detect applications using the older interface to
-            # set_contents_from_file(), which automatically rewound the
-            # file each time the Key was reused. This changed with commit
-            # 14ee2d03f4665fe20d19a85286f78d39d924237e, to support uploads
-            # split into multiple parts and uploaded in parallel, and at
-            # the time of that commit this check was added because otherwise
-            # older programs would get a success status and upload an empty
-            # object. Unfortuantely, it's very inefficient for fp's implemented
-            # by KeyFile (used, for example, by gsutil when copying between
-            # providers). So, we skip the check for the KeyFile case.
-            # TODO: At some point consider removing this seek/tell/seek
-            # logic, after enough time has passed that it's unlikely any
-            # programs remain that assume the older auto-rewind interface.
-            if 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:
-                        # Raise an exception as this is likely a programming
-                        # error whereby there is data before the fp but nothing
-                        # after it.
-                        fp.seek(spos)
-                        raise AttributeError('fp is at EOF. Use rewind option '
-                                             'or seek() to data start.')
-                # seek back to the correct position.
-                fp.seek(spos)
-
-        if hasattr(fp, 'name'):
-            self.path = fp.name
-        if self.bucket is not None:
-            if isinstance(fp, KeyFile):
-                # Avoid EOF seek for KeyFile case as it's very inefficient.
-                key = fp.getkey()
-                size = key.size - fp.tell()
-                self.size = size
-                # At present both GCS and S3 use MD5 for the etag for
-                # non-multipart-uploaded objects. If the etag is 32 hex
-                # chars use it as an MD5, to avoid having to read the file
-                # twice while transferring.
-                if (re.match('^"[a-fA-F0-9]{32}"$', key.etag)):
-                    etag = key.etag.strip('"')
-                    md5 = (etag, base64.b64encode(binascii.unhexlify(etag)))
-            if size:
-                self.size = size
-            else:
-                # If md5 is provided, still need to size so
-                # calculate based on bytes to end of content
-                spos = fp.tell()
-                fp.seek(0, os.SEEK_END)
-                self.size = fp.tell() - spos
-                fp.seek(spos)
-                size = self.size
-
-            if md5 is None:
-                md5 = self.compute_md5(fp, 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
-
-            if if_generation is not None:
-                headers['x-goog-if-generation-match'] = str(if_generation)
-
-            if res_upload_handler:
-                res_upload_handler.send_file(self, fp, headers, cb, num_cb)
-            else:
-                # Not a resumable transfer so use basic send_file mechanism.
-                self.send_file(fp, headers, cb, num_cb, size=size)
-
-    def set_contents_from_filename(self, filename, headers=None, replace=True,
-                                   cb=None, num_cb=10, policy=None, md5=None,
-                                   reduced_redundancy=None,
-                                   res_upload_handler=None,
-                                   if_generation=None):
-        """
-        Store an object in GS using the name of the Key object as the
-        key in GS and the contents of the file named by 'filename'.
-        See set_contents_from_file method for details about the
-        parameters.
-
-        :type filename: string
-        :param filename: The name of the file that you want to put onto GS.
-
-        :type headers: dict
-        :param headers: (optional) Additional headers to pass along with the
-            request to GS.
-
-        :type replace: bool
-        :param replace: (optional) If True, replaces the contents of the file
-            if it already exists.
-
-        :type cb: function
-        :param cb: (optional) 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 GS and the second representing the
-            total number of bytes that need to be transmitted.
-
-        :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: :py:attribute:`boto.gs.acl.CannedACLStrings`
-        :param policy: (optional) A canned ACL policy that will be applied to
-            the new key in GS.
-
-        :type md5: tuple
-        :param md5: (optional) 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.
-
-            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 res_upload_handler: :py:class:`boto.gs.resumable_upload_handler.ResumableUploadHandler`
-        :param res_upload_handler: (optional) If provided, this handler will
-            perform the upload.
-
-        :type if_generation: int
-        :param if_generation: (optional) If set to a generation number, the
-            object will only be written to if its current generation number is
-            this value. If set to the value 0, the object will only be written
-            if it doesn't already exist.
-        """
-        # Clear out any previously computed hashes, since we are setting the
-        # content.
-        self.local_hashes = {}
-
-        with open(filename, 'rb') as fp:
-            self.set_contents_from_file(fp, headers, replace, cb, num_cb,
-                                        policy, md5, res_upload_handler,
-                                        if_generation=if_generation)
-
-    def set_contents_from_string(self, s, headers=None, replace=True,
-                                 cb=None, num_cb=10, policy=None, md5=None,
-                                 if_generation=None):
-        """
-        Store an object in GCS using the name of the Key object as the
-        key in GCS and the string 's' as the contents.
-        See set_contents_from_file method for details about the
-        parameters.
-
-        :type headers: dict
-        :param headers: Additional headers to pass along with the
-                        request to AWS.
-
-        :type replace: bool
-        :param replace: If True, replaces the contents of the file if
-                        it already exists.
-
-        :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 GCS and the second representing the
-                   size of the to be transmitted object.
-
-        :type 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.gs.acl.CannedACLStrings`
-        :param policy: A canned ACL policy that will be applied to the
-                       new key in GCS.
-
-        :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 if_generation: int
-        :param if_generation: (optional) If set to a generation number, the
-            object will only be written to if its current generation number is
-            this value. If set to the value 0, the object will only be written
-            if it doesn't already exist.
-        """
-
-        # Clear out any previously computed md5 hashes, since we are setting the content.
-        self.md5 = None
-        self.base64md5 = None
-
-        fp = StringIO(get_utf8_value(s))
-        r = self.set_contents_from_file(fp, headers, replace, cb, num_cb,
-                                        policy, md5,
-                                        if_generation=if_generation)
-        fp.close()
-        return r
-
-    def set_contents_from_stream(self, *args, **kwargs):
-        """
-        Store an object using the name of the Key object as the key in
-        cloud and the contents of the data stream pointed to by 'fp' as
-        the contents.
-
-        The stream object is not seekable and total size is not known.
-        This has the implication that we can't specify the
-        Content-Size and Content-MD5 in the header. So for huge
-        uploads, the delay in calculating MD5 is avoided but with a
-        penalty of inability to verify the integrity of the uploaded
-        data.
-
-        :type fp: file
-        :param fp: the file whose contents are to be uploaded
-
-        :type headers: dict
-        :param headers: additional HTTP headers to 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 GS and the second representing the
-            total number of bytes that need to be transmitted.
-
-        :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.gs.acl.CannedACLStrings`
-        :param policy: A canned ACL policy that will be applied to the new key
-            in GS.
-
-        :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 if_generation: int
-        :param if_generation: (optional) If set to a generation number, the
-            object will only be written to if its current generation number is
-            this value. If set to the value 0, the object will only be written
-            if it doesn't already exist.
-        """
-        if_generation = kwargs.pop('if_generation', None)
-        if if_generation is not None:
-            headers = kwargs.get('headers', {})
-            headers['x-goog-if-generation-match'] = str(if_generation)
-            kwargs['headers'] = headers
-        super(Key, self).set_contents_from_stream(*args, **kwargs)
-
-    def set_acl(self, acl_or_str, headers=None, generation=None,
-                 if_generation=None, if_metageneration=None):
-        """Sets the ACL for this object.
-
-        :type acl_or_str: string or :class:`boto.gs.acl.ACL`
-        :param acl_or_str: A canned ACL string (see
-            :data:`~.gs.acl.CannedACLStrings`) or an ACL object.
-
-        :type headers: dict
-        :param headers: Additional headers to set during the request.
-
-        :type generation: int
-        :param generation: If specified, sets the ACL for a specific generation
-            of a versioned object. If not specified, the current version is
-            modified.
-
-        :type if_generation: int
-        :param if_generation: (optional) If set to a generation number, the acl
-            will only be updated if its current generation number is this value.
-
-        :type if_metageneration: int
-        :param if_metageneration: (optional) If set to a metageneration number,
-            the acl will only be updated if its current metageneration number is
-            this value.
-        """
-        if self.bucket is not None:
-            self.bucket.set_acl(acl_or_str, self.name, headers=headers,
-                                generation=generation,
-                                if_generation=if_generation,
-                                if_metageneration=if_metageneration)
-
-    def get_acl(self, headers=None, generation=None):
-        """Returns the ACL of this object.
-
-        :param dict headers: Additional headers to set during the request.
-
-        :param int generation: If specified, gets the ACL for a specific
-            generation of a versioned object. If not specified, the current
-            version is returned.
-
-        :rtype: :class:`.gs.acl.ACL`
-        """
-        if self.bucket is not None:
-            return self.bucket.get_acl(self.name, headers=headers,
-                                       generation=generation)
-
-    def get_xml_acl(self, headers=None, generation=None):
-        """Returns the ACL string of this object.
-
-        :param dict headers: Additional headers to set during the request.
-
-        :param int generation: If specified, gets the ACL for a specific
-            generation of a versioned object. If not specified, the current
-            version is returned.
-
-        :rtype: str
-        """
-        if self.bucket is not None:
-            return self.bucket.get_xml_acl(self.name, headers=headers,
-                                           generation=generation)
-
-    def set_xml_acl(self, acl_str, headers=None, generation=None,
-                     if_generation=None, if_metageneration=None):
-        """Sets this objects's ACL to an XML string.
-
-        :type acl_str: string
-        :param acl_str: A string containing the ACL XML.
-
-        :type headers: dict
-        :param headers: Additional headers to set during the request.
-
-        :type generation: int
-        :param generation: If specified, sets the ACL for a specific generation
-            of a versioned object. If not specified, the current version is
-            modified.
-
-        :type if_generation: int
-        :param if_generation: (optional) If set to a generation number, the acl
-            will only be updated if its current generation number is this value.
-
-        :type if_metageneration: int
-        :param if_metageneration: (optional) If set to a metageneration number,
-            the acl will only be updated if its current metageneration number is
-            this value.
-        """
-        if self.bucket is not None:
-            return self.bucket.set_xml_acl(acl_str, self.name, headers=headers,
-                                           generation=generation,
-                                           if_generation=if_generation,
-                                           if_metageneration=if_metageneration)
-
-    def set_canned_acl(self, acl_str, headers=None, generation=None,
-                       if_generation=None, if_metageneration=None):
-        """Sets this objects's ACL using a predefined (canned) value.
-
-        :type acl_str: string
-        :param acl_str: A canned ACL string. See
-            :data:`~.gs.acl.CannedACLStrings`.
-
-        :type headers: dict
-        :param headers: Additional headers to set during the request.
-
-        :type generation: int
-        :param generation: If specified, sets the ACL for a specific generation
-            of a versioned object. If not specified, the current version is
-            modified.
-
-        :type if_generation: int
-        :param if_generation: (optional) If set to a generation number, the acl
-            will only be updated if its current generation number is this value.
-
-        :type if_metageneration: int
-        :param if_metageneration: (optional) If set to a metageneration number,
-            the acl will only be updated if its current metageneration number is
-            this value.
-        """
-        if self.bucket is not None:
-            return self.bucket.set_canned_acl(
-                acl_str,
-                self.name,
-                headers=headers,
-                generation=generation,
-                if_generation=if_generation,
-                if_metageneration=if_metageneration
-            )
-
-    def compose(self, components, content_type=None, headers=None):
-        """Create a new object from a sequence of existing objects.
-
-        The content of the object representing this Key will be the
-        concatenation of the given object sequence. For more detail, visit
-
-            https://developers.google.com/storage/docs/composite-objects
-
-        :type components list of Keys
-        :param components List of gs.Keys representing the component objects
-
-        :type content_type (optional) string
-        :param content_type Content type for the new composite object.
-        """
-        compose_req = []
-        for key in components:
-            if key.bucket.name != self.bucket.name:
-                raise BotoClientError(
-                    'GCS does not support inter-bucket composing')
-
-            generation_tag = ''
-            if key.generation:
-                generation_tag = ('<Generation>%s</Generation>'
-                                  % str(key.generation))
-            compose_req.append('<Component><Name>%s</Name>%s</Component>' %
-                               (key.name, generation_tag))
-        compose_req_xml = ('<ComposeRequest>%s</ComposeRequest>' %
-                         ''.join(compose_req))
-        headers = headers or {}
-        if content_type:
-            headers['Content-Type'] = content_type
-        resp = self.bucket.connection.make_request(
-            'PUT', get_utf8_value(self.bucket.name), get_utf8_value(self.name),
-            headers=headers, query_args='compose',
-            data=get_utf8_value(compose_req_xml))
-        if resp.status < 200 or resp.status > 299:
-            raise self.bucket.connection.provider.storage_response_error(
-                resp.status, resp.reason, resp.read())
-
-        # Return the generation so that the result URI can be built with this
-        # for automatic parallel uploads.
-        return resp.getheader('x-goog-generation')