Skip to content

Commit f2561e7

Browse files
committed
Merge pull request #932 from dhermes/fix-920
Making _BlobIterator accumulate prefixes.
2 parents 85c7e37 + 5d273f5 commit f2561e7

3 files changed

Lines changed: 52 additions & 34 deletions

File tree

gcloud/storage/bucket.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class _BlobIterator(Iterator):
5252
def __init__(self, bucket, extra_params=None, connection=None):
5353
connection = _require_connection(connection)
5454
self.bucket = bucket
55-
self.prefixes = ()
55+
self.prefixes = set()
56+
self._current_prefixes = None
5657
super(_BlobIterator, self).__init__(
5758
connection=connection, path=bucket.path + '/o',
5859
extra_params=extra_params)
@@ -63,7 +64,8 @@ def get_items_from_response(self, response):
6364
:type response: dict
6465
:param response: The JSON API response for a page of blobs.
6566
"""
66-
self.prefixes = tuple(response.get('prefixes', ()))
67+
self._current_prefixes = tuple(response.get('prefixes', ()))
68+
self.prefixes.update(self._current_prefixes)
6769
for item in response.get('items', []):
6870
name = item.get('name')
6971
blob = Blob(name, bucket=self.bucket)

gcloud/storage/test_bucket.py

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def test_ctor_w_implicit_connection(self):
3737
self.assertEqual(iterator.path, '%s/o' % bucket.path)
3838
self.assertEqual(iterator.page_number, 0)
3939
self.assertEqual(iterator.next_page_token, None)
40-
self.assertEqual(iterator.prefixes, ())
40+
self.assertEqual(iterator.prefixes, set())
4141

4242
def test_ctor_w_explicit_connection(self):
4343
connection = _Connection()
@@ -48,33 +48,52 @@ def test_ctor_w_explicit_connection(self):
4848
self.assertEqual(iterator.path, '%s/o' % bucket.path)
4949
self.assertEqual(iterator.page_number, 0)
5050
self.assertEqual(iterator.next_page_token, None)
51-
self.assertEqual(iterator.prefixes, ())
51+
self.assertEqual(iterator.prefixes, set())
5252

5353
def test_get_items_from_response_empty(self):
54-
from gcloud.storage._testing import _monkey_defaults
5554
connection = _Connection()
5655
bucket = _Bucket()
57-
with _monkey_defaults(connection=connection):
58-
iterator = self._makeOne(bucket)
59-
blobs = list(iterator.get_items_from_response({}))
56+
iterator = self._makeOne(bucket, connection=connection)
57+
blobs = list(iterator.get_items_from_response({}))
6058
self.assertEqual(blobs, [])
61-
self.assertEqual(iterator.prefixes, ())
59+
self.assertEqual(iterator.prefixes, set())
6260

6361
def test_get_items_from_response_non_empty(self):
6462
from gcloud.storage.blob import Blob
65-
from gcloud.storage._testing import _monkey_defaults
6663
BLOB_NAME = 'blob-name'
6764
response = {'items': [{'name': BLOB_NAME}], 'prefixes': ['foo']}
6865
connection = _Connection()
6966
bucket = _Bucket()
70-
with _monkey_defaults(connection=connection):
71-
iterator = self._makeOne(bucket)
72-
blobs = list(iterator.get_items_from_response(response))
67+
iterator = self._makeOne(bucket, connection=connection)
68+
blobs = list(iterator.get_items_from_response(response))
69+
self.assertEqual(len(blobs), 1)
70+
blob = blobs[0]
71+
self.assertTrue(isinstance(blob, Blob))
72+
self.assertEqual(blob.name, BLOB_NAME)
73+
self.assertEqual(iterator.prefixes, set(['foo']))
74+
75+
def test_get_items_from_response_cumulative_prefixes(self):
76+
from gcloud.storage.blob import Blob
77+
BLOB_NAME = 'blob-name1'
78+
response1 = {'items': [{'name': BLOB_NAME}], 'prefixes': ['foo']}
79+
response2 = {
80+
'items': [],
81+
'prefixes': ['foo', 'bar'],
82+
}
83+
connection = _Connection()
84+
bucket = _Bucket()
85+
iterator = self._makeOne(bucket, connection=connection)
86+
# Parse first response.
87+
blobs = list(iterator.get_items_from_response(response1))
7388
self.assertEqual(len(blobs), 1)
7489
blob = blobs[0]
7590
self.assertTrue(isinstance(blob, Blob))
7691
self.assertEqual(blob.name, BLOB_NAME)
77-
self.assertEqual(iterator.prefixes, ('foo',))
92+
self.assertEqual(iterator.prefixes, set(['foo']))
93+
# Parse second response.
94+
blobs = list(iterator.get_items_from_response(response2))
95+
self.assertEqual(len(blobs), 0)
96+
self.assertEqual(iterator.prefixes, set(['foo', 'bar']))
7897

7998

8099
class Test_Bucket(unittest2.TestCase):
@@ -243,21 +262,18 @@ def test_get_blob_hit(self):
243262
self.assertEqual(kw['path'], '/b/%s/o/%s' % (NAME, BLOB_NAME))
244263

245264
def test_list_blobs_defaults(self):
246-
from gcloud.storage._testing import _monkey_defaults
247265
NAME = 'name'
248266
connection = _Connection({'items': []})
249267
bucket = self._makeOne(NAME)
250-
with _monkey_defaults(connection=connection):
251-
iterator = bucket.list_blobs()
252-
blobs = list(iterator)
268+
iterator = bucket.list_blobs(connection=connection)
269+
blobs = list(iterator)
253270
self.assertEqual(blobs, [])
254271
kw, = connection._requested
255272
self.assertEqual(kw['method'], 'GET')
256273
self.assertEqual(kw['path'], '/b/%s/o' % NAME)
257274
self.assertEqual(kw['query_params'], {'projection': 'noAcl'})
258275

259276
def test_list_blobs_explicit(self):
260-
from gcloud.storage._testing import _monkey_defaults
261277
NAME = 'name'
262278
MAX_RESULTS = 10
263279
PAGE_TOKEN = 'ABCD'
@@ -277,17 +293,17 @@ def test_list_blobs_explicit(self):
277293
}
278294
connection = _Connection({'items': []})
279295
bucket = self._makeOne(NAME)
280-
with _monkey_defaults(connection=connection):
281-
iterator = bucket.list_blobs(
282-
max_results=MAX_RESULTS,
283-
page_token=PAGE_TOKEN,
284-
prefix=PREFIX,
285-
delimiter=DELIMITER,
286-
versions=VERSIONS,
287-
projection=PROJECTION,
288-
fields=FIELDS,
289-
)
290-
blobs = list(iterator)
296+
iterator = bucket.list_blobs(
297+
max_results=MAX_RESULTS,
298+
page_token=PAGE_TOKEN,
299+
prefix=PREFIX,
300+
delimiter=DELIMITER,
301+
versions=VERSIONS,
302+
projection=PROJECTION,
303+
fields=FIELDS,
304+
connection=connection,
305+
)
306+
blobs = list(iterator)
291307
self.assertEqual(blobs, [])
292308
kw, = connection._requested
293309
self.assertEqual(kw['method'], 'GET')

regression/storage.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ def test_root_level_w_delimiter(self):
259259
self.assertEqual([blob.name for blob in blobs], ['file01.txt'])
260260
self.assertEqual(iterator.page_number, 1)
261261
self.assertTrue(iterator.next_page_token is None)
262-
self.assertEqual(iterator.prefixes, ('parent/',))
262+
self.assertEqual(iterator.prefixes, set(['parent/']))
263263

264264
def test_first_level(self):
265265
iterator = self.bucket.list_blobs(delimiter='/', prefix='parent/')
@@ -268,7 +268,7 @@ def test_first_level(self):
268268
self.assertEqual([blob.name for blob in blobs], ['parent/file11.txt'])
269269
self.assertEqual(iterator.page_number, 1)
270270
self.assertTrue(iterator.next_page_token is None)
271-
self.assertEqual(iterator.prefixes, ('parent/child/',))
271+
self.assertEqual(iterator.prefixes, set(['parent/child/']))
272272

273273
def test_second_level(self):
274274
iterator = self.bucket.list_blobs(delimiter='/',
@@ -281,7 +281,7 @@ def test_second_level(self):
281281
self.assertEqual(iterator.page_number, 1)
282282
self.assertTrue(iterator.next_page_token is None)
283283
self.assertEqual(iterator.prefixes,
284-
('parent/child/grand/', 'parent/child/other/'))
284+
set(['parent/child/grand/', 'parent/child/other/']))
285285

286286
def test_third_level(self):
287287
# Pseudo-hierarchy can be arbitrarily deep, subject to the limit
@@ -296,7 +296,7 @@ def test_third_level(self):
296296
['parent/child/grand/file31.txt'])
297297
self.assertEqual(iterator.page_number, 1)
298298
self.assertTrue(iterator.next_page_token is None)
299-
self.assertEqual(iterator.prefixes, ())
299+
self.assertEqual(iterator.prefixes, set())
300300

301301

302302
class TestStorageSignURLs(TestStorageFiles):

0 commit comments

Comments
 (0)