Skip to content

Commit

Permalink
Update names and types
Browse files Browse the repository at this point in the history
  • Loading branch information
daspecster committed Jun 14, 2016
1 parent c2fe9e1 commit 11b8011
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 50 deletions.
6 changes: 3 additions & 3 deletions gcloud/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,13 +394,13 @@ def _to_bytes(value, encoding='ascii'):
raise TypeError('%r could not be converted to bytes' % (value,))


def _from_bytes(value):
"""Converts bytes to a string value, if necessary.
def _to_unicode(value):
"""Converts bytes to a unicode value, if necessary.
:type value: bytes
:param value: bytes value to attempt string conversion on.
:rtype: bytes
:rtype: str
:returns: The original value converted to unicode (if bytes) or as passed
in if it started out as unicode.
Expand Down
99 changes: 58 additions & 41 deletions gcloud/storage/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

from gcloud._helpers import _rfc3339_to_datetime
from gcloud._helpers import _to_bytes
from gcloud._helpers import _from_bytes
from gcloud._helpers import _to_unicode
from gcloud.credentials import generate_signed_url
from gcloud.exceptions import NotFound
from gcloud.exceptions import make_exception
Expand Down Expand Up @@ -280,35 +280,40 @@ def delete(self, client=None):
"""
return self.bucket.delete_blob(self.name, client=client)

def download_to_file(self, file_obj, key=None, client=None):
def download_to_file(self, file_obj, encryption_key=None, client=None):
"""Download the contents of this blob into a file-like object.
.. note::
If the server-set property, :attr:`media_link`, is not yet
initialized, makes an additional API request to load it.
Downloading a file that has been encrypted with a
`customer-supplied`_ key::
Downloading a file that has been encrypted with a `customer-supplied`_
encryption key::
>>> from gcloud import storage
>>> from gcloud.storage import Blob
>>> client = storage.Client(project='my-project')
>>> bucket = client.get_bucket('my-bucket')
>>> key = 'aa426195405adee2c8081bb9e7e74b19'
>>> encryption_key = 'aa426195405adee2c8081bb9e7e74b19'
>>> blob = Blob('secure-data', bucket)
>>> with open('/tmp/my-secure-file', 'wb') as file_obj:
>>> blob.download_to_file(file_obj, key=key)
>>> blob.download_to_file(file_obj,
... encryption_key=encryption_key)
The ``encryption_key`` should be a str or bytes with a length of at
least 32.
.. _customer-supplied: https://cloud.google.com/storage/docs/\
encryption#customer-supplied
:type file_obj: file
:param file_obj: A file handle to which to write the blob's data.
:type key: str
:param key: Optional 32 byte key for customer-supplied encryption.
:type encryption_key: str or bytes
:param encryption_key: Optional 32 byte encryption key for
customer-supplied encryption.
:type client: :class:`gcloud.storage.client.Client` or ``NoneType``
:param client: Optional. The client to use. If not passed, falls back
Expand All @@ -329,8 +334,8 @@ def download_to_file(self, file_obj, key=None, client=None):
download.chunksize = self.chunk_size

headers = {}
if key:
_set_encryption_headers(key, headers)
if encryption_key:
_set_encryption_headers(encryption_key, headers)

request = Request(download_url, 'GET', headers)

Expand All @@ -342,14 +347,15 @@ def download_to_file(self, file_obj, key=None, client=None):
# it has all three (http, API_BASE_URL and build_api_url).
download.initialize_download(request, client._connection.http)

def download_to_filename(self, filename, key=None, client=None):
def download_to_filename(self, filename, encryption_key=None, client=None):
"""Download the contents of this blob into a named file.
:type filename: string
:param filename: A filename to be passed to ``open``.
:type key: str
:param key: Optional 32 byte key for customer-supplied encryption.
:type encryption_key: str or bytes
:param encryption_key: Optional 32 byte encryption key for
customer-supplied encryption.
:type client: :class:`gcloud.storage.client.Client` or ``NoneType``
:param client: Optional. The client to use. If not passed, falls back
Expand All @@ -358,16 +364,18 @@ def download_to_filename(self, filename, key=None, client=None):
:raises: :class:`gcloud.exceptions.NotFound`
"""
with open(filename, 'wb') as file_obj:
self.download_to_file(file_obj, key=key, client=client)
self.download_to_file(file_obj, encryption_key=encryption_key,
client=client)

mtime = time.mktime(self.updated.timetuple())
os.utime(file_obj.name, (mtime, mtime))

def download_as_string(self, key=None, client=None):
def download_as_string(self, encryption_key=None, client=None):
"""Download the contents of this blob as a string.
:type key: str
:param key: Optional 32 byte key for customer-supplied encryption.
:type encryption_key: str or bytes
:param encryption_key: Optional 32 byte encryption key for
customer-supplied encryption.
:type client: :class:`gcloud.storage.client.Client` or ``NoneType``
:param client: Optional. The client to use. If not passed, falls back
Expand All @@ -378,7 +386,8 @@ def download_as_string(self, key=None, client=None):
:raises: :class:`gcloud.exceptions.NotFound`
"""
string_buffer = BytesIO()
self.download_to_file(string_buffer, key=key, client=client)
self.download_to_file(string_buffer, encryption_key=encryption_key,
client=client)
return string_buffer.getvalue()

@staticmethod
Expand All @@ -392,8 +401,9 @@ def _check_response_error(request, http_response):
error_info=request.url)

# pylint: disable=too-many-locals
def upload_from_file(self, file_obj, rewind=False, size=None, key=None,
content_type=None, num_retries=6, client=None):
def upload_from_file(self, file_obj, rewind=False, size=None,
encryption_key=None, content_type=None, num_retries=6,
client=None):
"""Upload the contents of this blob from a file-like object.
The content type of the upload will either be
Expand All @@ -412,17 +422,21 @@ def upload_from_file(self, file_obj, rewind=False, size=None, key=None,
`lifecycle <https://cloud.google.com/storage/docs/lifecycle>`_
API documents for details.
Uploading a file with `customer-supplied`_ encryption::
Uploading a file with a `customer-supplied`_ encryption key::
>>> from gcloud import storage
>>> from gcloud.storage import Blob
>>> client = storage.Client(project='my-project')
>>> bucket = client.get_bucket('my-bucket')
>>> key = 'aa426195405adee2c8081bb9e7e74b19'
>>> encryption_key = 'aa426195405adee2c8081bb9e7e74b19'
>>> blob = Blob('secure-data', bucket)
>>> with open('my-file', 'rb') as my_file:
>>> blob.upload_from_file(my_file, key=key)
>>> blob.upload_from_file(my_file,
... encryption_key=encryption_key)
The ``encryption_key`` should be a str or bytes with a length of at
least 32.
.. _customer-supplied: https://cloud.google.com/storage/docs/\
encryption#customer-supplied
Expand All @@ -440,8 +454,9 @@ def upload_from_file(self, file_obj, rewind=False, size=None, key=None,
:func:`os.fstat`. (If the file handle is not from the
filesystem this won't be possible.)
:type key: str
:param key: Optional 32 byte key for customer-supplied encryption.
:type encryption_key: str or bytes
:param encryption_key: Optional 32 byte encryption key for
customer-supplied encryption.
:type content_type: string or ``NoneType``
:param content_type: Optional type of content being uploaded.
Expand Down Expand Up @@ -486,8 +501,8 @@ def upload_from_file(self, file_obj, rewind=False, size=None, key=None,
'User-Agent': connection.USER_AGENT,
}

if key:
_set_encryption_headers(key, headers)
if encryption_key:
_set_encryption_headers(encryption_key, headers)

upload = Upload(file_obj, content_type, total_bytes,
auto_transfer=False)
Expand Down Expand Up @@ -530,8 +545,8 @@ def upload_from_file(self, file_obj, rewind=False, size=None, key=None,
self._set_properties(json.loads(response_content))
# pylint: enable=too-many-locals

def upload_from_filename(self, filename, content_type=None, key=None,
client=None):
def upload_from_filename(self, filename, content_type=None,
encryption_key=None, client=None):
"""Upload this blob's contents from the content of a named file.
The content type of the upload will either be
Expand All @@ -556,8 +571,9 @@ def upload_from_filename(self, filename, content_type=None, key=None,
:type content_type: string or ``NoneType``
:param content_type: Optional type of content being uploaded.
:type key: str
:param key: Optional 32 byte key for customer-supplied encryption.
:type encryption_key: str or bytes
:param encryption_key: Optional 32 byte encryption key for
customer-supplied encryption.
:type client: :class:`gcloud.storage.client.Client` or ``NoneType``
:param client: Optional. The client to use. If not passed, falls back
Expand All @@ -568,11 +584,11 @@ def upload_from_filename(self, filename, content_type=None, key=None,
content_type, _ = mimetypes.guess_type(filename)

with open(filename, 'rb') as file_obj:
self.upload_from_file(file_obj, content_type=content_type, key=key,
client=client)
self.upload_from_file(file_obj, content_type=content_type,
encryption_key=encryption_key, client=client)

def upload_from_string(self, data, content_type='text/plain', key=None,
client=None):
def upload_from_string(self, data, content_type='text/plain',
encryption_key=None, client=None):
"""Upload contents of this blob from the provided string.
.. note::
Expand All @@ -594,8 +610,9 @@ def upload_from_string(self, data, content_type='text/plain', key=None,
:param content_type: Optional type of content being uploaded. Defaults
to ``'text/plain'``.
:type key: str
:param key: Optional 32 byte key for customer-supplied encryption.
:type encryption_key: str or bytes
:param encryption_key: Optional 32 byte encryption key for
customer-supplied encryption.
:type client: :class:`gcloud.storage.client.Client` or ``NoneType``
:param client: Optional. The client to use. If not passed, falls back
Expand All @@ -607,7 +624,7 @@ def upload_from_string(self, data, content_type='text/plain', key=None,
string_buffer.write(data)
self.upload_from_file(file_obj=string_buffer, rewind=True,
size=len(data), content_type=content_type,
key=key, client=client)
encryption_key=encryption_key, client=client)

def make_public(self, client=None):
"""Make this blob public giving all users read access.
Expand Down Expand Up @@ -905,7 +922,7 @@ def __init__(self, bucket_name, object_name):
def _set_encryption_headers(key, headers):
"""Builds customer encyrption key headers
:type key: str
:type key: str or bytes
:param key: 32 byte key to build request key and hash.
:type headers: dict
Expand All @@ -916,5 +933,5 @@ def _set_encryption_headers(key, headers):
key_hash = base64.b64encode(sha256_key).rstrip()
encoded_key = base64.b64encode(key).rstrip()
headers['X-Goog-Encryption-Algorithm'] = 'AES256'
headers['X-Goog-Encryption-Key'] = _from_bytes(encoded_key)
headers['X-Goog-Encryption-Key-Sha256'] = _from_bytes(key_hash)
headers['X-Goog-Encryption-Key'] = _to_unicode(encoded_key)
headers['X-Goog-Encryption-Key-Sha256'] = _to_unicode(key_hash)
6 changes: 3 additions & 3 deletions gcloud/storage/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ def test_download_to_filename_w_key(self):
blob.chunk_size = 3

with _NamedTemporaryFile() as temp:
blob.download_to_filename(temp.name, key=KEY)
blob.download_to_filename(temp.name, encryption_key=KEY)
with open(temp.name, 'rb') as file_obj:
wrote = file_obj.read()
mtime = os.path.getmtime(temp.name)
Expand Down Expand Up @@ -766,7 +766,7 @@ def test_upload_from_filename_w_key(self):
file_obj.write(DATA)
blob.upload_from_filename(temp.name,
content_type=EXPECTED_CONTENT_TYPE,
key=KEY)
encryption_key=KEY)

rq = connection.http._requested
self.assertEqual(len(rq), 1)
Expand Down Expand Up @@ -965,7 +965,7 @@ def test_upload_from_string_text_w_key(self):
blob = self._makeOne(BLOB_NAME, bucket=bucket)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 5
blob.upload_from_string(DATA, key=KEY)
blob.upload_from_string(DATA, encryption_key=KEY)
rq = connection.http._requested
self.assertEqual(len(rq), 1)
self.assertEqual(rq[0]['method'], 'POST')
Expand Down
6 changes: 3 additions & 3 deletions gcloud/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,11 +586,11 @@ def test_with_nonstring_type(self):
self.assertRaises(TypeError, self._callFUT, value)


class Test__from_bytes(unittest2.TestCase):
class Test__to_unicode(unittest2.TestCase):

def _callFUT(self, *args, **kwargs):
from gcloud._helpers import _from_bytes
return _from_bytes(*args, **kwargs)
from gcloud._helpers import _to_unicode
return _to_unicode(*args, **kwargs)

def test_with_bytes(self):
value = b'bytes-val'
Expand Down

0 comments on commit 11b8011

Please sign in to comment.