From 370aa7dfebba1a4a9ba03aa7f2709e8471826e3f Mon Sep 17 00:00:00 2001 From: Till Hoffmann Date: Mon, 17 Jul 2017 10:01:11 +0100 Subject: [PATCH 1/5] Add keyword arguments to google.cloud.storage.Bucket.get_blob. --- storage/google/cloud/storage/bucket.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/storage/google/cloud/storage/bucket.py b/storage/google/cloud/storage/bucket.py index 895a6e38473f..e0e9ccb0b1b9 100644 --- a/storage/google/cloud/storage/bucket.py +++ b/storage/google/cloud/storage/bucket.py @@ -228,7 +228,7 @@ def path(self): return self.path_helper(self.name) - def get_blob(self, blob_name, client=None): + def get_blob(self, blob_name, client=None, **kwargs): """Get a blob object by name. This will return None if the blob doesn't exist: @@ -245,11 +245,15 @@ def get_blob(self, blob_name, client=None): :param client: Optional. The client to use. If not passed, falls back to the ``client`` stored on the current bucket. + :type kwargs: dict + :param kwargs: Keyword arguments to pass to the :class:`~google.cloud.storage.blob.Blob` + constructor. + :rtype: :class:`google.cloud.storage.blob.Blob` or None :returns: The blob object if it exists, otherwise None. """ client = self._require_client(client) - blob = Blob(bucket=self, name=blob_name) + blob = Blob(bucket=self, name=blob_name, **kwargs) try: response = client._connection.api_request( method='GET', path=blob.path, _target_object=blob) From fafe37919ec0bd2cb6d588337129959fba3de3c6 Mon Sep 17 00:00:00 2001 From: Till Hoffmann Date: Mon, 17 Jul 2017 10:16:56 +0100 Subject: [PATCH 2/5] Fix linting errors. --- storage/google/cloud/storage/bucket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/google/cloud/storage/bucket.py b/storage/google/cloud/storage/bucket.py index e0e9ccb0b1b9..a6b9ac956739 100644 --- a/storage/google/cloud/storage/bucket.py +++ b/storage/google/cloud/storage/bucket.py @@ -246,8 +246,8 @@ def get_blob(self, blob_name, client=None, **kwargs): to the ``client`` stored on the current bucket. :type kwargs: dict - :param kwargs: Keyword arguments to pass to the :class:`~google.cloud.storage.blob.Blob` - constructor. + :param kwargs: Keyword arguments to pass to the + :class:`~google.cloud.storage.blob.Blob` constructor. :rtype: :class:`google.cloud.storage.blob.Blob` or None :returns: The blob object if it exists, otherwise None. From cdef7b15d5ee3052290ead6dbe007d88cc86a7d4 Mon Sep 17 00:00:00 2001 From: Till Hoffmann Date: Tue, 18 Jul 2017 13:54:54 +0100 Subject: [PATCH 3/5] Add encryption headers and test. --- storage/google/cloud/storage/blob.py | 2 +- storage/google/cloud/storage/bucket.py | 18 ++++++++++++++---- storage/tests/unit/test_bucket.py | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/storage/google/cloud/storage/blob.py b/storage/google/cloud/storage/blob.py index de59fdf1f2bd..7d967a3e4901 100644 --- a/storage/google/cloud/storage/blob.py +++ b/storage/google/cloud/storage/blob.py @@ -113,7 +113,7 @@ class Blob(_PropertyMixin): :type encryption_key: bytes :param encryption_key: Optional 32 byte encryption key for customer-supplied encryption. - See https://cloud.google.com/storage/docs/encryption#customer-supplied + See https://cloud.google.com/storage/docs/encryption#customer-supplied. """ _chunk_size = None # Default value for each instance. diff --git a/storage/google/cloud/storage/bucket.py b/storage/google/cloud/storage/bucket.py index a6b9ac956739..9b1a6ac0f265 100644 --- a/storage/google/cloud/storage/bucket.py +++ b/storage/google/cloud/storage/bucket.py @@ -33,7 +33,7 @@ from google.cloud.storage._helpers import _validate_name from google.cloud.storage.acl import BucketACL from google.cloud.storage.acl import DefaultObjectACL -from google.cloud.storage.blob import Blob +from google.cloud.storage.blob import Blob, _get_encryption_headers def _blobs_page_start(iterator, page, response): @@ -228,7 +228,7 @@ def path(self): return self.path_helper(self.name) - def get_blob(self, blob_name, client=None, **kwargs): + def get_blob(self, blob_name, client=None, encryption_key=None, **kwargs): """Get a blob object by name. This will return None if the blob doesn't exist: @@ -245,6 +245,12 @@ def get_blob(self, blob_name, client=None, **kwargs): :param client: Optional. The client to use. If not passed, falls back to the ``client`` stored on the current bucket. + :type encryption_key: bytes + :param encryption_key: + Optional 32 byte encryption key for customer-supplied encryption. + See + https://cloud.google.com/storage/docs/encryption#customer-supplied. + :type kwargs: dict :param kwargs: Keyword arguments to pass to the :class:`~google.cloud.storage.blob.Blob` constructor. @@ -253,10 +259,14 @@ def get_blob(self, blob_name, client=None, **kwargs): :returns: The blob object if it exists, otherwise None. """ client = self._require_client(client) - blob = Blob(bucket=self, name=blob_name, **kwargs) + blob = Blob(bucket=self, name=blob_name, encryption_key=encryption_key, + **kwargs) try: + headers = _get_encryption_headers(encryption_key) response = client._connection.api_request( - method='GET', path=blob.path, _target_object=blob) + method='GET', path=blob.path, _target_object=blob, + headers=headers + ) # NOTE: We assume response.get('name') matches `blob_name`. blob._set_properties(response) # NOTE: This will not fail immediately in a batch. However, when diff --git a/storage/tests/unit/test_bucket.py b/storage/tests/unit/test_bucket.py index 5e4a91575197..a37ffd00597c 100644 --- a/storage/tests/unit/test_bucket.py +++ b/storage/tests/unit/test_bucket.py @@ -245,6 +245,26 @@ def test_get_blob_hit(self): self.assertEqual(kw['method'], 'GET') self.assertEqual(kw['path'], '/b/%s/o/%s' % (NAME, BLOB_NAME)) + def test_get_blob_hit_with_kwargs(self): + NAME = 'name' + BLOB_NAME = 'blob-name' + CHUNK_SIZE = 1024 * 1024 + KEY = b'01234567890123456789012345678901' # 32 bytes + + connection = _Connection({'name': BLOB_NAME}) + client = _Client(connection) + bucket = self._make_one(name=NAME) + blob = bucket.get_blob( + BLOB_NAME, client=client, encryption_key=KEY, chunk_size=CHUNK_SIZE + ) + self.assertIs(blob.bucket, bucket) + self.assertEqual(blob.name, BLOB_NAME) + kw, = connection._requested + self.assertEqual(kw['method'], 'GET') + self.assertEqual(kw['path'], '/b/%s/o/%s' % (NAME, BLOB_NAME)) + self.assertEqual(blob.chunk_size, CHUNK_SIZE) + self.assertEqual(blob._encryption_key, KEY) + def test_list_blobs_defaults(self): NAME = 'name' connection = _Connection({'items': []}) From 81fb2615ec8cced44f9679eff54e72b0456bbb74 Mon Sep 17 00:00:00 2001 From: Till Hoffmann Date: Wed, 19 Jul 2017 10:21:34 +0100 Subject: [PATCH 4/5] Style changes. --- storage/google/cloud/storage/bucket.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/google/cloud/storage/bucket.py b/storage/google/cloud/storage/bucket.py index 9b1a6ac0f265..7969c24e343b 100644 --- a/storage/google/cloud/storage/bucket.py +++ b/storage/google/cloud/storage/bucket.py @@ -33,7 +33,8 @@ from google.cloud.storage._helpers import _validate_name from google.cloud.storage.acl import BucketACL from google.cloud.storage.acl import DefaultObjectACL -from google.cloud.storage.blob import Blob, _get_encryption_headers +from google.cloud.storage.blob import Blob +from google.cloud.storage.blob import _get_encryption_headers def _blobs_page_start(iterator, page, response): @@ -265,8 +266,7 @@ def get_blob(self, blob_name, client=None, encryption_key=None, **kwargs): headers = _get_encryption_headers(encryption_key) response = client._connection.api_request( method='GET', path=blob.path, _target_object=blob, - headers=headers - ) + headers=headers) # NOTE: We assume response.get('name') matches `blob_name`. blob._set_properties(response) # NOTE: This will not fail immediately in a batch. However, when From 1b25423c8de6afd59dd0a03aef6c29a0f1f2754c Mon Sep 17 00:00:00 2001 From: Till Hoffmann Date: Wed, 19 Jul 2017 10:30:32 +0100 Subject: [PATCH 5/5] Add assertion for encryption headers. --- storage/tests/unit/test_bucket.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/storage/tests/unit/test_bucket.py b/storage/tests/unit/test_bucket.py index a37ffd00597c..0df94dc5db3d 100644 --- a/storage/tests/unit/test_bucket.py +++ b/storage/tests/unit/test_bucket.py @@ -246,6 +246,8 @@ def test_get_blob_hit(self): self.assertEqual(kw['path'], '/b/%s/o/%s' % (NAME, BLOB_NAME)) def test_get_blob_hit_with_kwargs(self): + from google.cloud.storage.blob import _get_encryption_headers + NAME = 'name' BLOB_NAME = 'blob-name' CHUNK_SIZE = 1024 * 1024 @@ -262,6 +264,7 @@ def test_get_blob_hit_with_kwargs(self): kw, = connection._requested self.assertEqual(kw['method'], 'GET') self.assertEqual(kw['path'], '/b/%s/o/%s' % (NAME, BLOB_NAME)) + self.assertEqual(kw['headers'], _get_encryption_headers(KEY)) self.assertEqual(blob.chunk_size, CHUNK_SIZE) self.assertEqual(blob._encryption_key, KEY)