From dd1ae8d8b6717cccb8e9a48a05517cb49d04feb5 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Tue, 28 Apr 2015 11:16:44 -0700 Subject: [PATCH] Putting optional connection on Bucket.get_blob and DELETE methods. --- gcloud/storage/bucket.py | 45 +++++++++++++++++++++++++++-------- gcloud/storage/test_bucket.py | 45 ++++++++++++++++++++--------------- 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/gcloud/storage/bucket.py b/gcloud/storage/bucket.py index 955d2e4adcd1..1647a8489bdd 100644 --- a/gcloud/storage/bucket.py +++ b/gcloud/storage/bucket.py @@ -211,7 +211,7 @@ def path(self): return self.path_helper(self.name) - def get_blob(self, blob_name): + def get_blob(self, blob_name, connection=None): """Get a blob object by name. This will return None if the blob doesn't exist:: @@ -227,13 +227,19 @@ def get_blob(self, blob_name): :type blob_name: string :param blob_name: The name of the blob to retrieve. + :type connection: :class:`gcloud.storage.connection.Connection` or + ``NoneType`` + :param connection: Optional. The connection to use when sending + requests. If not provided, falls back to default. + :rtype: :class:`gcloud.storage.blob.Blob` or None :returns: The blob object if it exists, otherwise None. """ + connection = _require_connection(connection) blob = Blob(bucket=self, name=blob_name) try: - response = self.connection.api_request(method='GET', - path=blob.path) + response = connection.api_request(method='GET', + path=blob.path) name = response.get('name') # Expect this to be blob_name blob = Blob(name, bucket=self) blob._set_properties(response) @@ -304,7 +310,7 @@ def list_blobs(self, max_results=None, page_token=None, prefix=None, result.next_page_token = page_token return result - def delete(self, force=False): + def delete(self, force=False, connection=None): """Delete this bucket. The bucket **must** be empty in order to submit a delete request. If @@ -323,9 +329,15 @@ def delete(self, force=False): :type force: boolean :param force: If True, empties the bucket's objects then deletes it. + :type connection: :class:`gcloud.storage.connection.Connection` or + ``NoneType`` + :param connection: Optional. The connection to use when sending + requests. If not provided, falls back to default. + :raises: :class:`ValueError` if ``force`` is ``True`` and the bucket contains more than 256 objects / blobs. """ + connection = _require_connection(connection) if force: blobs = list(self.list_blobs( max_results=self._MAX_OBJECTS_FOR_BUCKET_DELETE + 1)) @@ -339,11 +351,12 @@ def delete(self, force=False): raise ValueError(message) # Ignore 404 errors on delete. - self.delete_blobs(blobs, on_error=lambda blob: None) + self.delete_blobs(blobs, on_error=lambda blob: None, + connection=connection) - self.connection.api_request(method='DELETE', path=self.path) + connection.api_request(method='DELETE', path=self.path) - def delete_blob(self, blob_name): + def delete_blob(self, blob_name, connection=None): """Deletes a blob from the current bucket. If the blob isn't found (backend 404), raises a @@ -366,16 +379,22 @@ def delete_blob(self, blob_name): :type blob_name: string :param blob_name: A blob name to delete. + :type connection: :class:`gcloud.storage.connection.Connection` or + ``NoneType`` + :param connection: Optional. The connection to use when sending + requests. If not provided, falls back to default. + :raises: :class:`gcloud.exceptions.NotFound` (to suppress the exception, call ``delete_blobs``, passing a no-op ``on_error`` callback, e.g.:: >>> bucket.delete_blobs([blob], on_error=lambda blob: None) """ + connection = _require_connection(connection) blob_path = Blob.path_helper(self.path, blob_name) - self.connection.api_request(method='DELETE', path=blob_path) + connection.api_request(method='DELETE', path=blob_path) - def delete_blobs(self, blobs, on_error=None): + def delete_blobs(self, blobs, on_error=None, connection=None): """Deletes a list of blobs from the current bucket. Uses :func:`Bucket.delete_blob` to delete each individual blob. @@ -388,15 +407,21 @@ def delete_blobs(self, blobs, on_error=None): :class:`gcloud.exceptions.NotFound`; otherwise, the exception is propagated. + :type connection: :class:`gcloud.storage.connection.Connection` or + ``NoneType`` + :param connection: Optional. The connection to use when sending + requests. If not provided, falls back to default. + :raises: :class:`gcloud.exceptions.NotFound` (if `on_error` is not passed). """ + connection = _require_connection(connection) for blob in blobs: try: blob_name = blob if not isinstance(blob_name, six.string_types): blob_name = blob.name - self.delete_blob(blob_name) + self.delete_blob(blob_name, connection=connection) except NotFound: if on_error is not None: on_error(blob) diff --git a/gcloud/storage/test_bucket.py b/gcloud/storage/test_bucket.py index 349c6e606f0e..c7d58f7b1f5d 100644 --- a/gcloud/storage/test_bucket.py +++ b/gcloud/storage/test_bucket.py @@ -255,8 +255,9 @@ def test_get_blob_miss(self): NAME = 'name' NONESUCH = 'nonesuch' connection = _Connection() - bucket = self._makeOne(NAME, connection) - self.assertTrue(bucket.get_blob(NONESUCH) is None) + bucket = self._makeOne(NAME) + result = bucket.get_blob(NONESUCH, connection=connection) + self.assertTrue(result is None) kw, = connection._requested self.assertEqual(kw['method'], 'GET') self.assertEqual(kw['path'], '/b/%s/o/%s' % (NAME, NONESUCH)) @@ -265,8 +266,8 @@ def test_get_blob_hit(self): NAME = 'name' BLOB_NAME = 'blob-name' connection = _Connection({'name': BLOB_NAME}) - bucket = self._makeOne(NAME, connection) - blob = bucket.get_blob(BLOB_NAME) + bucket = self._makeOne(NAME) + blob = bucket.get_blob(BLOB_NAME, connection=connection) self.assertTrue(blob.bucket is bucket) self.assertEqual(blob.name, BLOB_NAME) kw, = connection._requested @@ -325,8 +326,8 @@ def test_delete_default_miss(self): from gcloud.exceptions import NotFound NAME = 'name' connection = _Connection() - bucket = self._makeOne(NAME, connection) - self.assertRaises(NotFound, bucket.delete) + bucket = self._makeOne(NAME) + self.assertRaises(NotFound, bucket.delete, connection=connection) expected_cw = [{'method': 'DELETE', 'path': bucket.path}] self.assertEqual(connection._deleted_buckets, expected_cw) @@ -336,7 +337,8 @@ def test_delete_explicit_hit(self): connection = _Connection(GET_BLOBS_RESP) connection._delete_bucket = True bucket = self._makeOne(NAME, connection) - self.assertEqual(bucket.delete(force=True), None) + result = bucket.delete(force=True, connection=connection) + self.assertTrue(result is None) expected_cw = [{'method': 'DELETE', 'path': bucket.path}] self.assertEqual(connection._deleted_buckets, expected_cw) @@ -355,7 +357,8 @@ def test_delete_explicit_force_delete_blobs(self): DELETE_BLOB2_RESP) connection._delete_bucket = True bucket = self._makeOne(NAME, connection) - self.assertEqual(bucket.delete(force=True), None) + result = bucket.delete(force=True, connection=connection) + self.assertTrue(result is None) expected_cw = [{'method': 'DELETE', 'path': bucket.path}] self.assertEqual(connection._deleted_buckets, expected_cw) @@ -367,7 +370,8 @@ def test_delete_explicit_force_miss_blobs(self): connection = _Connection(GET_BLOBS_RESP) connection._delete_bucket = True bucket = self._makeOne(NAME, connection) - self.assertEqual(bucket.delete(force=True), None) + result = bucket.delete(force=True, connection=connection) + self.assertTrue(result is None) expected_cw = [{'method': 'DELETE', 'path': bucket.path}] self.assertEqual(connection._deleted_buckets, expected_cw) @@ -395,8 +399,9 @@ def test_delete_blob_miss(self): NAME = 'name' NONESUCH = 'nonesuch' connection = _Connection() - bucket = self._makeOne(NAME, connection) - self.assertRaises(NotFound, bucket.delete_blob, NONESUCH) + bucket = self._makeOne(NAME) + self.assertRaises(NotFound, bucket.delete_blob, NONESUCH, + connection=connection) kw, = connection._requested self.assertEqual(kw['method'], 'DELETE') self.assertEqual(kw['path'], '/b/%s/o/%s' % (NAME, NONESUCH)) @@ -405,8 +410,8 @@ def test_delete_blob_hit(self): NAME = 'name' BLOB_NAME = 'blob-name' connection = _Connection({}) - bucket = self._makeOne(NAME, connection) - result = bucket.delete_blob(BLOB_NAME) + bucket = self._makeOne(NAME) + result = bucket.delete_blob(BLOB_NAME, connection=connection) self.assertTrue(result is None) kw, = connection._requested self.assertEqual(kw['method'], 'DELETE') @@ -423,8 +428,8 @@ def test_delete_blobs_hit(self): NAME = 'name' BLOB_NAME = 'blob-name' connection = _Connection({}) - bucket = self._makeOne(NAME, connection) - bucket.delete_blobs([BLOB_NAME]) + bucket = self._makeOne(NAME) + bucket.delete_blobs([BLOB_NAME], connection=connection) kw = connection._requested self.assertEqual(len(kw), 1) self.assertEqual(kw[0]['method'], 'DELETE') @@ -436,8 +441,9 @@ def test_delete_blobs_miss_no_on_error(self): BLOB_NAME = 'blob-name' NONESUCH = 'nonesuch' connection = _Connection({}) - bucket = self._makeOne(NAME, connection) - self.assertRaises(NotFound, bucket.delete_blobs, [BLOB_NAME, NONESUCH]) + bucket = self._makeOne(NAME) + self.assertRaises(NotFound, bucket.delete_blobs, [BLOB_NAME, NONESUCH], + connection=connection) kw = connection._requested self.assertEqual(len(kw), 2) self.assertEqual(kw[0]['method'], 'DELETE') @@ -450,9 +456,10 @@ def test_delete_blobs_miss_w_on_error(self): BLOB_NAME = 'blob-name' NONESUCH = 'nonesuch' connection = _Connection({}) - bucket = self._makeOne(NAME, connection) + bucket = self._makeOne(NAME) errors = [] - bucket.delete_blobs([BLOB_NAME, NONESUCH], errors.append) + bucket.delete_blobs([BLOB_NAME, NONESUCH], errors.append, + connection=connection) self.assertEqual(errors, [NONESUCH]) kw = connection._requested self.assertEqual(len(kw), 2)