<commit_before>"""Create / interact with gcloud storage keys."""

import errno
import mimetypes
import os
from StringIO import StringIO

from gcloud.storage.acl import ObjectACL
from gcloud.storage.iterator import KeyDataIterator


class Key(object):
    """A wrapper around Cloud Storage's concept of an ``Object``."""

    CHUNK_SIZE = 1024 * 1024  # 1 MB.
    """The size of a chunk of data whenever iterating (1 MB).

  This must be a multiple of 256 KB per the API specification.
  """

    def __init__(self, bucket=None, name=None, metadata=None):
        """Key constructor.

        :type bucket: :class:`gcloud.storage.bucket.Bucket`
        :param bucket: The bucket to which this key belongs.

        :type name: string
        :param name: The name of the key.
                     This corresponds to the unique path of the object
                     in the bucket.

        :type metadata: dict
        :param metadata: All the other data provided by Cloud Storage.
        """

        self.bucket = bucket
        self.name = name
        self.metadata = metadata or {}

        # Lazily get the ACL information.
        self.acl = None

    @classmethod
    def from_dict(cls, key_dict, bucket=None):
        """Instantiate a :class:`Key` from data returned by the JSON API.

        :type key_dict: dict
        :param key_dict: A dictionary of data returned from
                         getting an Cloud Storage object.

        :type bucket: :class:`gcloud.storage.bucket.Bucket`
        :param bucket: The bucket to which this key belongs
                       (and by proxy, which connection to use).

        :rtype: :class:`Key`
        :returns: A key based on the data provided.
        """

        return cls(bucket=bucket, name=key_dict['name'], metadata=key_dict)

    def __repr__(self):  # pragma NO COVER
        if self.bucket:
            bucket_name = self.bucket.name
        else:
            bucket_name = None

        return '<Key: %s, %s>' % (bucket_name, self.name)

    @property
    def connection(self):
        """Getter property for the connection to use with this Key.

        :rtype: :class:`gcloud.storage.connection.Connection` or None
        :returns: The connection to use, or None if no connection is set.
        """

        if self.bucket and self.bucket.connection:
            return self.bucket.connection

    @property
    def path(self):
        """Getter property for the URL path to this Key.

        :rtype: string
        :returns: The URL path to this Key.
        """

        if not self.bucket:
            raise ValueError('Cannot determine path without a bucket defined.')
        elif not self.name:
            raise ValueError('Cannot determine path without a key name.')

        return self.bucket.path + '/o/' + self.name

    @property
    def public_url(self):
        """
        :rtype: `string`
        :returns: The public URL for this key.
        """
        return '{storage_base_url}/{self.bucket.name}/{self.name}'.format(
            storage_base_url='http://commondatastorage.googleapis.com',
            self=self)

    def generate_signed_url(self, expiration,
                            method='GET'):  # pragma NO COVER
        """Generates a signed URL for this key.

        If you have a key that you want to allow access to
        for a set amount of time,
        you can use this method to generate a URL
        that is only valid within a certain time period.

        This is particularly useful if you don't want publicly accessible keys,
        but don't want to require users to explicitly log in.

        :type expiration: int, long, datetime.datetime, datetime.timedelta
        :param expiration: When the signed URL should expire.

        :type method: string
        :param method: The HTTP verb that will be used when requesting the URL.

        :rtype: string
        :returns: A signed URL you can use to access the resource
                  until expiration.
        """

        resource = '/{self.bucket.name}/{self.name}'.format(self=self)
        return self.connection.generate_signed_url(resource=resource,
                                                   expiration=expiration,
                                                   method=method)

    def exists(self):
        """Determines whether or not this key exists.

        :rtype: bool
        :returns: True if the key exists in Cloud Storage.
        """

        return self.bucket.get_key(self.name) is not None

    def rename(self, new_name):
        """Renames this key using copy and delete operations.

        Effectively, copies key to the same bucket with a new name, then
        deletes the key.

        .. warning::
          This method will first duplicate the data
          and then delete the old key.
          This means that with very large objects
          renaming could be a very (temporarily) costly
          or a very slow operation.

        :type new_name: string
        :param new_name: The new name for this key.

        :rtype: :class:`Key`
        :returns: The newly-copied key.
        """
        new_key = self.bucket.copy_key(self, self.bucket, new_name)
        self.bucket.delete_key(self)
        return new_key

    def delete(self):
        """Deletes a key from Cloud Storage.

        :rtype: :class:`Key`
        :returns: The key that was just deleted.
        """

        return self.bucket.delete_key(self)

    def get_contents_to_file(self, fh):
        """Gets the contents of this key to a file-like object.

        :type fh: file
        :param fh: A file handle to which to write the key's data.

        :raises: :class:`gcloud.storage.exceptions.NotFoundError`
        """

        for chunk in KeyDataIterator(self):
            try:
                fh.write(chunk)
            except IOError, e:  # pragma NO COVER
                if e.errno == errno.ENOSPC:
                    raise Exception('No space left on device.')

    def get_contents_to_filename(self, filename):
        """Get the contents of this key to a file by name.

        :type filename: string
        :param filename: A filename to be passed to ``open``.

        :raises: :class:`gcloud.storage.exceptions.NotFoundError`
        """

        with open(filename, 'wb') as fh:
            self.get_contents_to_file(fh)

    def get_contents_as_string(self):
        """Gets the data stored on this Key as a string.

        :rtype: string
        :returns: The data stored in this key.
        :raises: :class:`gcloud.storage.exceptions.NotFoundError`
        """

        string_buffer = StringIO()
        self.get_contents_to_file(string_buffer)
        return string_buffer.getvalue()

    def set_contents_from_file(self, fh, rewind=False, size=None,
                               content_type=None):<commit_msg>Don't remap (only some) IOError.<commit_after>"""Create / interact with gcloud storage keys."""

import errno
import mimetypes
import os
from StringIO import StringIO

from gcloud.storage.acl import ObjectACL
from gcloud.storage.iterator import KeyDataIterator


class Key(object):
    """A wrapper around Cloud Storage's concept of an ``Object``."""

    CHUNK_SIZE = 1024 * 1024  # 1 MB.
    """The size of a chunk of data whenever iterating (1 MB).

  This must be a multiple of 256 KB per the API specification.
  """

    def __init__(self, bucket=None, name=None, metadata=None):
        """Key constructor.

        :type bucket: :class:`gcloud.storage.bucket.Bucket`
        :param bucket: The bucket to which this key belongs.

        :type name: string
        :param name: The name of the key.
                     This corresponds to the unique path of the object
                     in the bucket.

        :type metadata: dict
        :param metadata: All the other data provided by Cloud Storage.
        """

        self.bucket = bucket
        self.name = name
        self.metadata = metadata or {}

        # Lazily get the ACL information.
        self.acl = None

    @classmethod
    def from_dict(cls, key_dict, bucket=None):
        """Instantiate a :class:`Key` from data returned by the JSON API.

        :type key_dict: dict
        :param key_dict: A dictionary of data returned from
                         getting an Cloud Storage object.

        :type bucket: :class:`gcloud.storage.bucket.Bucket`
        :param bucket: The bucket to which this key belongs
                       (and by proxy, which connection to use).

        :rtype: :class:`Key`
        :returns: A key based on the data provided.
        """

        return cls(bucket=bucket, name=key_dict['name'], metadata=key_dict)

    def __repr__(self):  # pragma NO COVER
        if self.bucket:
            bucket_name = self.bucket.name
        else:
            bucket_name = None

        return '<Key: %s, %s>' % (bucket_name, self.name)

    @property
    def connection(self):
        """Getter property for the connection to use with this Key.

        :rtype: :class:`gcloud.storage.connection.Connection` or None
        :returns: The connection to use, or None if no connection is set.
        """

        if self.bucket and self.bucket.connection:
            return self.bucket.connection

    @property
    def path(self):
        """Getter property for the URL path to this Key.

        :rtype: string
        :returns: The URL path to this Key.
        """

        if not self.bucket:
            raise ValueError('Cannot determine path without a bucket defined.')
        elif not self.name:
            raise ValueError('Cannot determine path without a key name.')

        return self.bucket.path + '/o/' + self.name

    @property
    def public_url(self):
        """
        :rtype: `string`
        :returns: The public URL for this key.
        """
        return '{storage_base_url}/{self.bucket.name}/{self.name}'.format(
            storage_base_url='http://commondatastorage.googleapis.com',
            self=self)

    def generate_signed_url(self, expiration,
                            method='GET'):  # pragma NO COVER
        """Generates a signed URL for this key.

        If you have a key that you want to allow access to
        for a set amount of time,
        you can use this method to generate a URL
        that is only valid within a certain time period.

        This is particularly useful if you don't want publicly accessible keys,
        but don't want to require users to explicitly log in.

        :type expiration: int, long, datetime.datetime, datetime.timedelta
        :param expiration: When the signed URL should expire.

        :type method: string
        :param method: The HTTP verb that will be used when requesting the URL.

        :rtype: string
        :returns: A signed URL you can use to access the resource
                  until expiration.
        """

        resource = '/{self.bucket.name}/{self.name}'.format(self=self)
        return self.connection.generate_signed_url(resource=resource,
                                                   expiration=expiration,
                                                   method=method)

    def exists(self):
        """Determines whether or not this key exists.

        :rtype: bool
        :returns: True if the key exists in Cloud Storage.
        """

        return self.bucket.get_key(self.name) is not None

    def rename(self, new_name):
        """Renames this key using copy and delete operations.

        Effectively, copies key to the same bucket with a new name, then
        deletes the key.

        .. warning::
          This method will first duplicate the data
          and then delete the old key.
          This means that with very large objects
          renaming could be a very (temporarily) costly
          or a very slow operation.

        :type new_name: string
        :param new_name: The new name for this key.

        :rtype: :class:`Key`
        :returns: The newly-copied key.
        """
        new_key = self.bucket.copy_key(self, self.bucket, new_name)
        self.bucket.delete_key(self)
        return new_key

    def delete(self):
        """Deletes a key from Cloud Storage.

        :rtype: :class:`Key`
        :returns: The key that was just deleted.
        """

        return self.bucket.delete_key(self)

    def get_contents_to_file(self, fh):
        """Gets the contents of this key to a file-like object.

        :type fh: file
        :param fh: A file handle to which to write the key's data.

        :raises: :class:`gcloud.storage.exceptions.NotFoundError`
        """

        for chunk in KeyDataIterator(self):
            fh.write(chunk)

    def get_contents_to_filename(self, filename):
        """Get the contents of this key to a file by name.

        :type filename: string
        :param filename: A filename to be passed to ``open``.

        :raises: :class:`gcloud.storage.exceptions.NotFoundError`
        """

        with open(filename, 'wb') as fh:
            self.get_contents_to_file(fh)

    def get_contents_as_string(self):
        """Gets the data stored on this Key as a string.

        :rtype: string
        :returns: The data stored in this key.
        :raises: :class:`gcloud.storage.exceptions.NotFoundError`
        """

        string_buffer = StringIO()
        self.get_contents_to_file(string_buffer)
        return string_buffer.getvalue()

    def set_contents_from_file(self, fh, rewind=False, size=None,
                               content_type=None):
{'fraction_non_alphanumeric': 0.08428044280442805, 'fraction_numerical': 0.001918819188191882, 'mean_word_length': 2.0207311636201517, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7518538', 'n_tokens_mistral': 3691, 'n_tokens_neox': 3509, 'n_words': 1345}