Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'Bucket.requester_pays' property. #3488

Merged
merged 5 commits into from
Jun 9, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion storage/google/cloud/storage/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,10 +798,39 @@ def versioning_enabled(self, value):
details.

:type value: convertible to boolean
:param value: should versioning be anabled for the bucket?
:param value: should versioning be enabled for the bucket?
"""
self._patch_property('versioning', {'enabled': bool(value)})

@property
def requester_pays(self):
"""Does the requester pay for API requests for this bucket?

See https://cloud.google.com/storage/docs/<DOCS-MISSING> for

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

details.

:setter: Update whether requester pays for this bucket.
:getter: Query whether requester pays for this bucket.

:rtype: bool
:returns: True if requester pays for API requests for the bucket,
else False.
"""
versioning = self._properties.get('billing', {})
return versioning.get('requesterPays', False)

@requester_pays.setter
def requester_pays(self, value):
"""Update whether requester pays for API requests for this bucket.

See https://cloud.google.com/storage/docs/<DOCS-MISSING> for
details.

:type value: convertible to boolean
:param value: should requester pay for API requests for the bucket?
"""
self._patch_property('billing', {'requesterPays': bool(value)})

def configure_website(self, main_page_suffix=None, not_found_page=None):
"""Configure website-related properties.

Expand Down
8 changes: 7 additions & 1 deletion storage/google/cloud/storage/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def lookup_bucket(self, bucket_name):
except NotFound:
return None

def create_bucket(self, bucket_name):
def create_bucket(self, bucket_name, requester_pays=None):

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

"""Create a new bucket.

For example:
Expand All @@ -211,10 +211,16 @@ def create_bucket(self, bucket_name):
:type bucket_name: str
:param bucket_name: The bucket name to create.

:type requester_pays: bool
:param requester_pays: (Optional) Whether requester pays for
API requests for this bucket and its blobs.

This comment was marked as spam.

This comment was marked as spam.


:rtype: :class:`google.cloud.storage.bucket.Bucket`
:returns: The newly created bucket.
"""
bucket = Bucket(self, name=bucket_name)
if requester_pays is not None:
bucket.requester_pays = requester_pays
bucket.create(client=self)
return bucket

Expand Down
9 changes: 9 additions & 0 deletions storage/tests/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ def test_create_bucket(self):
self.case_buckets_to_delete.append(new_bucket_name)
self.assertEqual(created.name, new_bucket_name)

@unittest.skipIf(True, "requesterPays needs whitelisting?")

This comment was marked as spam.

def test_create_bucket_with_requester_pays(self):
new_bucket_name = 'w-requester-pays' + unique_resource_id('-')
created = Config.CLIENT.create_bucket(
new_bucket_name, requester_pays=True)
self.case_buckets_to_delete.append(new_bucket_name)
self.assertEqual(created.name, new_bucket_name)
self.assertTrue(created.requester_pays)

def test_list_buckets(self):
buckets_to_create = [
'new' + unique_resource_id(),
Expand Down
20 changes: 20 additions & 0 deletions storage/tests/unit/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ def test_create_w_extra_properties(self):
'location': LOCATION,
'storageClass': STORAGE_CLASS,
'versioning': {'enabled': True},
'billing': {'requesterPays': True},
'labels': LABELS,
}
connection = _Connection(DATA)
Expand All @@ -186,6 +187,7 @@ def test_create_w_extra_properties(self):
bucket.location = LOCATION
bucket.storage_class = STORAGE_CLASS
bucket.versioning_enabled = True
bucket.requester_pays = True
bucket.labels = LABELS
bucket.create()

Expand Down Expand Up @@ -866,6 +868,24 @@ def test_versioning_enabled_setter(self):
bucket.versioning_enabled = True
self.assertTrue(bucket.versioning_enabled)

def test_requester_pays_getter_missing(self):
NAME = 'name'
bucket = self._make_one(name=NAME)
self.assertEqual(bucket.requester_pays, False)

def test_requester_pays_getter(self):
NAME = 'name'
before = {'billing': {'requesterPays': True}}
bucket = self._make_one(name=NAME, properties=before)
self.assertEqual(bucket.requester_pays, True)

def test_requester_pays_setter(self):
NAME = 'name'
bucket = self._make_one(name=NAME)
self.assertFalse(bucket.requester_pays)
bucket.requester_pays = True
self.assertTrue(bucket.requester_pays)

def test_configure_website_defaults(self):
NAME = 'name'
UNSET = {'website': {'mainPageSuffix': None,
Expand Down
41 changes: 24 additions & 17 deletions storage/tests/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,22 +155,22 @@ def test_get_bucket_hit(self):
CREDENTIALS = _make_credentials()
client = self._make_one(project=PROJECT, credentials=CREDENTIALS)

BLOB_NAME = 'blob-name'
BUCKET_NAME = 'bucket-name'
URI = '/'.join([
client._connection.API_BASE_URL,
'storage',
client._connection.API_VERSION,
'b',
'%s?projection=noAcl' % (BLOB_NAME,),
'%s?projection=noAcl' % (BUCKET_NAME,),
])
http = client._http_internal = _Http(
{'status': '200', 'content-type': 'application/json'},
'{{"name": "{0}"}}'.format(BLOB_NAME).encode('utf-8'),
'{{"name": "{0}"}}'.format(BUCKET_NAME).encode('utf-8'),
)

bucket = client.get_bucket(BLOB_NAME)
bucket = client.get_bucket(BUCKET_NAME)
self.assertIsInstance(bucket, Bucket)
self.assertEqual(bucket.name, BLOB_NAME)
self.assertEqual(bucket.name, BUCKET_NAME)
self.assertEqual(http._called_with['method'], 'GET')
self.assertEqual(http._called_with['uri'], URI)

Expand Down Expand Up @@ -203,33 +203,34 @@ def test_lookup_bucket_hit(self):
CREDENTIALS = _make_credentials()
client = self._make_one(project=PROJECT, credentials=CREDENTIALS)

BLOB_NAME = 'blob-name'
BUCKET_NAME = 'bucket-name'
URI = '/'.join([
client._connection.API_BASE_URL,
'storage',
client._connection.API_VERSION,
'b',
'%s?projection=noAcl' % (BLOB_NAME,),
'%s?projection=noAcl' % (BUCKET_NAME,),
])
http = client._http_internal = _Http(
{'status': '200', 'content-type': 'application/json'},
'{{"name": "{0}"}}'.format(BLOB_NAME).encode('utf-8'),
'{{"name": "{0}"}}'.format(BUCKET_NAME).encode('utf-8'),
)

bucket = client.lookup_bucket(BLOB_NAME)
bucket = client.lookup_bucket(BUCKET_NAME)
self.assertIsInstance(bucket, Bucket)
self.assertEqual(bucket.name, BLOB_NAME)
self.assertEqual(bucket.name, BUCKET_NAME)
self.assertEqual(http._called_with['method'], 'GET')
self.assertEqual(http._called_with['uri'], URI)

def test_create_bucket_conflict(self):
import json
from google.cloud.exceptions import Conflict

PROJECT = 'PROJECT'
CREDENTIALS = _make_credentials()
client = self._make_one(project=PROJECT, credentials=CREDENTIALS)

BLOB_NAME = 'blob-name'
BUCKET_NAME = 'bucket-name'
URI = '/'.join([
client._connection.API_BASE_URL,
'storage',
Expand All @@ -241,18 +242,21 @@ def test_create_bucket_conflict(self):
'{"error": {"message": "Conflict"}}',
)

self.assertRaises(Conflict, client.create_bucket, BLOB_NAME)
self.assertRaises(Conflict, client.create_bucket, BUCKET_NAME)
self.assertEqual(http._called_with['method'], 'POST')
self.assertEqual(http._called_with['uri'], URI)
body = json.loads(http._called_with['body'])
self.assertEqual(body, {'name': BUCKET_NAME})

def test_create_bucket_success(self):
import json
from google.cloud.storage.bucket import Bucket

PROJECT = 'PROJECT'
CREDENTIALS = _make_credentials()
client = self._make_one(project=PROJECT, credentials=CREDENTIALS)

BLOB_NAME = 'blob-name'
BUCKET_NAME = 'bucket-name'
URI = '/'.join([
client._connection.API_BASE_URL,
'storage',
Expand All @@ -261,14 +265,17 @@ def test_create_bucket_success(self):
])
http = client._http_internal = _Http(
{'status': '200', 'content-type': 'application/json'},
'{{"name": "{0}"}}'.format(BLOB_NAME).encode('utf-8'),
'{{"name": "{0}"}}'.format(BUCKET_NAME).encode('utf-8'),
)

bucket = client.create_bucket(BLOB_NAME)
bucket = client.create_bucket(BUCKET_NAME, requester_pays=True)
self.assertIsInstance(bucket, Bucket)
self.assertEqual(bucket.name, BLOB_NAME)
self.assertEqual(bucket.name, BUCKET_NAME)
self.assertEqual(http._called_with['method'], 'POST')
self.assertEqual(http._called_with['uri'], URI)
body = json.loads(http._called_with['body'])
self.assertEqual(
body, {'name': BUCKET_NAME, 'billing': {'requesterPays': True}})

def test_list_buckets_empty(self):
from six.moves.urllib.parse import parse_qs
Expand Down Expand Up @@ -400,7 +407,7 @@ def test_page_non_empty_response(self):
credentials = _make_credentials()
client = self._make_one(project=project, credentials=credentials)

blob_name = 'blob-name'
blob_name = 'bucket-name'
response = {'items': [{'name': blob_name}]}

def dummy_response():
Expand Down