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

Move 'bucket.BucketIterator' -> 'connection._BucketIterator'. #358

Merged
merged 3 commits into from
Nov 11, 2014
Merged
Show file tree
Hide file tree
Changes from all 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
55 changes: 29 additions & 26 deletions gcloud/storage/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,31 @@
from gcloud.storage.acl import DefaultObjectACL
from gcloud.storage.iterator import Iterator
from gcloud.storage.key import Key
from gcloud.storage.key import _KeyIterator


class _KeyIterator(Iterator):
"""An iterator listing keys in a bucket

You shouldn't have to use this directly, but instead should use the
helper methods on :class:`gcloud.storage.key.Bucket` objects.

:type bucket: :class:`gcloud.storage.bucket.Bucket`
:param bucket: The bucket from which to list keys.
"""
def __init__(self, bucket, connection=None, extra_params=None):
self.bucket = bucket
super(_KeyIterator, self).__init__(
connection=bucket.connection, path=bucket.path + '/o',
extra_params=extra_params)

def get_items_from_response(self, response):
"""Yield :class:`.storage.key.Key` items from response.

:type response: dict
:param response: The JSON API response for a page of keys.
"""
for item in response.get('items', []):
yield Key.from_dict(item, bucket=self.bucket)


class Bucket(_PropertyMixin):
Expand All @@ -21,6 +45,7 @@ class Bucket(_PropertyMixin):
:type name: string
:param name: The name of the bucket.
"""
_iterator_class = _KeyIterator

CUSTOM_PROPERTY_ACCESSORS = {
'acl': 'get_acl()',
Expand Down Expand Up @@ -66,7 +91,7 @@ def __repr__(self):
return '<Bucket: %s>' % self.name

def __iter__(self):
return iter(_KeyIterator(bucket=self))
return iter(self._iterator_class(bucket=self))

def __contains__(self, key):
return self.get_key(key) is not None
Expand Down Expand Up @@ -640,29 +665,7 @@ def make_public(self, recursive=False, future=False):
doa.save()

if recursive:
for key in self:
iterator = self._iterator_class(self)
for key in iterator:
key.get_acl().all().grant_read()
key.save_acl()


class BucketIterator(Iterator):
"""An iterator listing all buckets.

You shouldn't have to use this directly, but instead should use the helper
methods on :class:`gcloud.storage.connection.Connection` objects.

:type connection: :class:`gcloud.storage.connection.Connection`
:param connection: The connection to use for querying the list of buckets.
"""

def __init__(self, connection):
super(BucketIterator, self).__init__(connection=connection, path='/b')

def get_items_from_response(self, response):
"""Factory method which yields :class:`.Bucket` items from a response.

:type response: dict
:param response: The JSON API response for a page of buckets.
"""
for item in response.get('items', []):
yield Bucket.from_dict(item, connection=self.connection)
31 changes: 27 additions & 4 deletions gcloud/storage/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
from OpenSSL import crypto
import pytz

from gcloud import connection
from gcloud.connection import Connection as _Base
from gcloud.storage import exceptions
from gcloud.storage.bucket import Bucket
from gcloud.storage.bucket import BucketIterator
from gcloud.storage.iterator import Iterator


def _utcnow(): # pragma: NO COVER testing replaces
Expand All @@ -26,7 +26,7 @@ def _utcnow(): # pragma: NO COVER testing replaces
return datetime.datetime.utcnow()


class Connection(connection.Connection):
class Connection(_Base):
"""A connection to Google Cloud Storage via the JSON REST API.

This class should understand only the basic types (and protobufs)
Expand Down Expand Up @@ -84,7 +84,7 @@ def __init__(self, project, *args, **kwargs):
self.project = project

def __iter__(self):
return iter(BucketIterator(connection=self))
return iter(_BucketIterator(connection=self))

def __contains__(self, bucket_name):
return self.lookup(bucket_name) is not None
Expand Down Expand Up @@ -488,6 +488,29 @@ def generate_signed_url(self, resource, expiration,
querystring=urllib.urlencode(query_params))


class _BucketIterator(Iterator):
"""An iterator listing all buckets.

You shouldn't have to use this directly, but instead should use the helper
methods on :class:`gcloud.storage.connection.Connection` objects.

:type connection: :class:`gcloud.storage.connection.Connection`
:param connection: The connection to use for querying the list of buckets.
"""

def __init__(self, connection):
super(_BucketIterator, self).__init__(connection=connection, path='/b')

def get_items_from_response(self, response):
"""Factory method which yields :class:`.Bucket` items from a response.

:type response: dict
:param response: The JSON API response for a page of buckets.
"""
for item in response.get('items', []):
yield Bucket.from_dict(item, connection=self.connection)


def _get_expiration_seconds(expiration):
"""Convert 'expiration' to a number of seconds in the future.

Expand Down
26 changes: 0 additions & 26 deletions gcloud/storage/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from gcloud.storage._helpers import _scalar_property
from gcloud.storage.acl import ObjectACL
from gcloud.storage.exceptions import StorageError
from gcloud.storage.iterator import Iterator


class Key(_PropertyMixin):
Expand Down Expand Up @@ -595,31 +594,6 @@ def updated(self):
return self.properties['updated']


class _KeyIterator(Iterator):
"""An iterator listing keys.

You shouldn't have to use this directly, but instead should use the
helper methods on :class:`gcloud.storage.key.Key` objects.

:type bucket: :class:`gcloud.storage.bucket.Bucket`
:param bucket: The bucket from which to list keys.
"""
def __init__(self, bucket, extra_params=None):
self.bucket = bucket
super(_KeyIterator, self).__init__(
connection=bucket.connection, path=bucket.path + '/o',
extra_params=extra_params)

def get_items_from_response(self, response):
"""Yield :class:`.storage.key.Key` items from response.

:type response: dict
:param response: The JSON API response for a page of keys.
"""
for item in response.get('items', []):
yield Key.from_dict(item, bucket=self.bucket)


class _KeyDataIterator(object):
"""An iterator listing data stored in a key.

Expand Down
50 changes: 30 additions & 20 deletions gcloud/storage/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -832,9 +832,7 @@ def test_make_public_w_future(self):

def test_make_public_recursive(self):
from gcloud.storage.acl import _ACLEntity
from gcloud._testing import _Monkey
from gcloud.storage import key
from gcloud.storage import bucket as MUT
from gcloud.storage.bucket import _KeyIterator
_saved = []

class _Key(object):
Expand All @@ -856,7 +854,7 @@ def grant_read(self):
def save_acl(self):
_saved.append((self._bucket, self._name, self._granted))

class _KeyIterator(key._KeyIterator):
class _Iterator(_KeyIterator):
def get_items_from_response(self, response):
for item in response.get('items', []):
yield _Key(self.bucket, item['name'])
Expand All @@ -868,8 +866,8 @@ def get_items_from_response(self, response):
connection = _Connection(after, {'items': [{'name': KEY}]})
bucket = self._makeOne(connection, NAME)
bucket.acl.loaded = True
with _Monkey(MUT, _KeyIterator=_KeyIterator):
bucket.make_public(recursive=True)
bucket._iterator_class = _Iterator
bucket.make_public(recursive=True)
self.assertEqual(list(bucket.acl), permissive)
self.assertEqual(list(bucket.default_object_acl), [])
self.assertEqual(_saved, [(bucket, KEY, True)])
Expand All @@ -884,40 +882,44 @@ def get_items_from_response(self, response):
self.assertEqual(kw[1]['query_params'], {})


class TestBucketIterator(unittest2.TestCase):
class Test__KeyIterator(unittest2.TestCase):

def _getTargetClass(self):
from gcloud.storage.bucket import BucketIterator
return BucketIterator
from gcloud.storage.bucket import _KeyIterator
return _KeyIterator

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_ctor(self):
connection = _Connection()
iterator = self._makeOne(connection)
bucket = _Bucket(connection)
iterator = self._makeOne(bucket)
self.assertTrue(iterator.bucket is bucket)
self.assertTrue(iterator.connection is connection)
self.assertEqual(iterator.path, '/b')
self.assertEqual(iterator.path, '%s/o' % bucket.path)
self.assertEqual(iterator.page_number, 0)
self.assertEqual(iterator.next_page_token, None)

def test_get_items_from_response_empty(self):
connection = _Connection()
iterator = self._makeOne(connection)
bucket = _Bucket(connection)
iterator = self._makeOne(bucket)
self.assertEqual(list(iterator.get_items_from_response({})), [])

def test_get_items_from_response_non_empty(self):
from gcloud.storage.bucket import Bucket
from gcloud.storage.key import Key
KEY = 'key'
response = {'items': [{'name': KEY}]}
connection = _Connection()
iterator = self._makeOne(connection)
buckets = list(iterator.get_items_from_response(response))
self.assertEqual(len(buckets), 1)
bucket = buckets[0]
self.assertTrue(isinstance(bucket, Bucket))
self.assertTrue(bucket.connection is connection)
self.assertEqual(bucket.name, KEY)
bucket = _Bucket(connection)
iterator = self._makeOne(bucket)
keys = list(iterator.get_items_from_response(response))
self.assertEqual(len(keys), 1)
key = keys[0]
self.assertTrue(isinstance(key, Key))
self.assertTrue(key.connection is connection)
self.assertEqual(key.name, KEY)


class _Connection(object):
Expand Down Expand Up @@ -947,6 +949,14 @@ def delete_bucket(self, bucket, force=False):
return True


class _Bucket(object):
path = '/b/name'
name = 'name'

def __init__(self, connection):
self.connection = connection


class MockFile(io.StringIO):
name = None

Expand Down
36 changes: 36 additions & 0 deletions gcloud/storage/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,42 @@ def test_generate_signed_url_w_expiration_int(self):
self.assertEqual(frag, '')


class Test__BucketIterator(unittest2.TestCase):

def _getTargetClass(self):
from gcloud.storage.connection import _BucketIterator
return _BucketIterator

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_ctor(self):
connection = object()
iterator = self._makeOne(connection)
self.assertTrue(iterator.connection is connection)
self.assertEqual(iterator.path, '/b')
self.assertEqual(iterator.page_number, 0)
self.assertEqual(iterator.next_page_token, None)

def test_get_items_from_response_empty(self):
connection = object()
iterator = self._makeOne(connection)
self.assertEqual(list(iterator.get_items_from_response({})), [])

def test_get_items_from_response_non_empty(self):
from gcloud.storage.bucket import Bucket
KEY = 'key'
response = {'items': [{'name': KEY}]}
connection = object()
iterator = self._makeOne(connection)
buckets = list(iterator.get_items_from_response(response))
self.assertEqual(len(buckets), 1)
bucket = buckets[0]
self.assertTrue(isinstance(bucket, Bucket))
self.assertTrue(bucket.connection is connection)
self.assertEqual(bucket.name, KEY)


class Test__get_expiration_seconds(unittest2.TestCase):

def _callFUT(self, expiration):
Expand Down
40 changes: 0 additions & 40 deletions gcloud/storage/test_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,46 +662,6 @@ def test_updated(self):
self.assertEqual(key.updated, UPDATED)


class Test__KeyIterator(unittest2.TestCase):

def _getTargetClass(self):
from gcloud.storage.key import _KeyIterator
return _KeyIterator

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_ctor(self):
connection = _Connection()
bucket = _Bucket(connection)
iterator = self._makeOne(bucket)
self.assertTrue(iterator.bucket is bucket)
self.assertTrue(iterator.connection is connection)
self.assertEqual(iterator.path, '%s/o' % bucket.path)
self.assertEqual(iterator.page_number, 0)
self.assertEqual(iterator.next_page_token, None)

def test_get_items_from_response_empty(self):
connection = _Connection()
bucket = _Bucket(connection)
iterator = self._makeOne(bucket)
self.assertEqual(list(iterator.get_items_from_response({})), [])

def test_get_items_from_response_non_empty(self):
from gcloud.storage.key import Key
KEY = 'key'
response = {'items': [{'name': KEY}]}
connection = _Connection()
bucket = _Bucket(connection)
iterator = self._makeOne(bucket)
keys = list(iterator.get_items_from_response(response))
self.assertEqual(len(keys), 1)
key = keys[0]
self.assertTrue(isinstance(key, Key))
self.assertTrue(key.connection is connection)
self.assertEqual(key.name, KEY)


class Test__KeyDataIterator(unittest2.TestCase):

def _getTargetClass(self):
Expand Down