Skip to content

Commit d4c77ef

Browse files
committed
Merge pull request #1005 from dhermes/add-storage-factories
Adding storage factories for owned objects.
2 parents 94d4fc1 + 6bc49c3 commit d4c77ef

File tree

11 files changed

+103
-16
lines changed

11 files changed

+103
-16
lines changed

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ how to create a bucket.
107107
blob = bucket.get_blob('/remote/path/to/file.txt')
108108
print blob.download_as_string()
109109
blob.upload_from_string('New contents!')
110-
blob2 = storage.Blob('/remote/path/storage.txt', bucket)
110+
blob2 = bucket.blob('/remote/path/storage.txt')
111111
blob2.upload_from_filename(filename='/local/path.txt')
112112
113113
Contributing

docs/_components/storage-getting-started.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Python built-in ``object``.
9191
If you want to set some data, you just create a ``Blob`` inside your bucket
9292
and store your data inside the blob::
9393

94-
>>> blob = storage.Blob('greeting.txt', bucket=bucket)
94+
>>> blob = bucket.blob('greeting.txt')
9595
>>> blob.upload_from_string('Hello world!')
9696

9797
This creates a :class:`Blob <gcloud.storage.blob.Blob>` object locally and
@@ -116,7 +116,7 @@ Then you can look at the file in a terminal::
116116
And what about when you're not dealing with text?
117117
That's pretty simple too::
118118

119-
>>> blob = storage.Blob('kitten.jpg', bucket)
119+
>>> blob = bucket.blob('kitten.jpg')
120120
>>> blob.upload_from_filename('kitten.jpg')
121121

122122
And to test whether it worked?

docs/_components/storage-quickstart.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ you can create buckets and blobs::
6161
>>> bucket = client.create_bucket('my-new-bucket')
6262
>>> print bucket
6363
<Bucket: my-new-bucket>
64-
>>> blob = storage.Blob('my-test-file.txt', bucket=bucket)
64+
>>> blob = bucket.blob('my-test-file.txt')
6565
>>> print blob
6666
<Blob: my-new-bucket, my-test-file.txt>
6767
>>> blob = blob.upload_from_string('this is test content!')

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,5 @@ Cloud Storage
5454
from gcloud import storage
5555
client = storage.Client()
5656
bucket = client.get_bucket('<your-bucket-name>')
57-
blob = storage.Blob('my-test-file.txt', bucket=bucket)
57+
blob = bucket.blob('my-test-file.txt')
5858
blob.upload_from_string('this is test content!')

gcloud/storage/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
>>> blob = bucket.get_blob('/remote/path/to/file.txt')
2424
>>> print blob.download_as_string()
2525
>>> blob.upload_from_string('New contents!')
26-
>>> blob2 = storage.Blob('/remote/path/storage.txt', bucket)
26+
>>> blob2 = bucket.blob('/remote/path/storage.txt')
2727
>>> blob2.upload_from_filename(filename='/local/path.txt')
2828
2929
The main concepts with this API are:

gcloud/storage/bucket.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,26 @@ def __init__(self, client, name=None):
9898
def __repr__(self):
9999
return '<Bucket: %s>' % self.name
100100

101+
def blob(self, blob_name, chunk_size=None):
102+
"""Factory constructor for blob object.
103+
104+
.. note::
105+
This will not make an HTTP request; it simply instantiates
106+
a blob object owned by this bucket.
107+
108+
:type blob_name: string
109+
:param blob_name: The name of the blob to be instantiated.
110+
111+
:type chunk_size: integer
112+
:param chunk_size: The size of a chunk of data whenever iterating
113+
(1 MB). This must be a multiple of 256 KB per the
114+
API specification.
115+
116+
:rtype: :class:`gcloud.storage.blob.Blob`
117+
:returns: The blob object created.
118+
"""
119+
return Blob(name=blob_name, bucket=self, chunk_size=chunk_size)
120+
101121
def exists(self, client=None):
102122
"""Determines whether or not this bucket exists.
103123

gcloud/storage/client.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from gcloud.client import JSONClient
2020
from gcloud.exceptions import NotFound
2121
from gcloud.iterator import Iterator
22+
from gcloud.storage.batch import Batch
2223
from gcloud.storage.bucket import Bucket
2324
from gcloud.storage.connection import Connection
2425

@@ -113,6 +114,33 @@ def current_batch(self):
113114
"""
114115
return self._batch_stack.top
115116

117+
def bucket(self, bucket_name):
118+
"""Factory constructor for bucket object.
119+
120+
.. note::
121+
This will not make an HTTP request; it simply instantiates
122+
a bucket object owned by this client.
123+
124+
:type bucket_name: string
125+
:param bucket_name: The name of the bucket to be instantiated.
126+
127+
:rtype: :class:`gcloud.storage.bucket.Bucket`
128+
:returns: The bucket object created.
129+
"""
130+
return Bucket(client=self, name=bucket_name)
131+
132+
def batch(self):
133+
"""Factory constructor for batch object.
134+
135+
.. note::
136+
This will not make an HTTP request; it simply instantiates
137+
a batch object owned by this client.
138+
139+
:rtype: :class:`gcloud.storage.batch.Batch`
140+
:returns: The batch object created.
141+
"""
142+
return Batch(client=self)
143+
116144
def get_bucket(self, bucket_name):
117145
"""Get a bucket by name.
118146

gcloud/storage/demo/demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
print(list(client.list_buckets()))
3838

3939
# How about we create a new blob inside this bucket.
40-
blob = storage.Blob("my-new-file.txt", bucket=bucket)
40+
blob = bucket.blob("my-new-file.txt")
4141

4242
# Now let's put some data in there.
4343
blob.upload_from_string("this is some data!")

gcloud/storage/test_bucket.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,21 @@ def test_ctor(self):
107107
self.assertFalse(bucket._default_object_acl.loaded)
108108
self.assertTrue(bucket._default_object_acl.bucket is bucket)
109109

110+
def test_blob(self):
111+
from gcloud.storage.blob import Blob
112+
113+
BUCKET_NAME = 'BUCKET_NAME'
114+
BLOB_NAME = 'BLOB_NAME'
115+
CHUNK_SIZE = 1024 * 1024
116+
117+
bucket = self._makeOne(name=BUCKET_NAME)
118+
blob = bucket.blob(BLOB_NAME, chunk_size=CHUNK_SIZE)
119+
self.assertTrue(isinstance(blob, Blob))
120+
self.assertTrue(blob.bucket is bucket)
121+
self.assertTrue(blob.client is bucket.client)
122+
self.assertEqual(blob.name, BLOB_NAME)
123+
self.assertEqual(blob.chunk_size, CHUNK_SIZE)
124+
110125
def test_exists_miss(self):
111126
from gcloud.exceptions import NotFound
112127

gcloud/storage/test_client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,30 @@ def test_connection_getter_with_batch(self):
8989
self.assertTrue(client.connection is batch)
9090
self.assertTrue(client.current_batch is batch)
9191

92+
def test_bucket(self):
93+
from gcloud.storage.bucket import Bucket
94+
95+
PROJECT = object()
96+
CREDENTIALS = _Credentials()
97+
BUCKET_NAME = 'BUCKET_NAME'
98+
99+
client = self._makeOne(project=PROJECT, credentials=CREDENTIALS)
100+
bucket = client.bucket(BUCKET_NAME)
101+
self.assertTrue(isinstance(bucket, Bucket))
102+
self.assertTrue(bucket.client is client)
103+
self.assertEqual(bucket.name, BUCKET_NAME)
104+
105+
def test_batch(self):
106+
from gcloud.storage.batch import Batch
107+
108+
PROJECT = object()
109+
CREDENTIALS = _Credentials()
110+
111+
client = self._makeOne(project=PROJECT, credentials=CREDENTIALS)
112+
batch = client.batch()
113+
self.assertTrue(isinstance(batch, Batch))
114+
self.assertTrue(batch._client is client)
115+
92116
def test_get_bucket_miss(self):
93117
from gcloud.exceptions import NotFound
94118

system_tests/storage.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ def setUp(self):
5252
self.case_buckets_to_delete = []
5353

5454
def tearDown(self):
55-
with storage.Batch(CLIENT):
55+
with CLIENT.batch():
5656
for bucket_name in self.case_buckets_to_delete:
57-
storage.Bucket(CLIENT, name=bucket_name).delete()
57+
CLIENT.bucket(bucket_name).delete()
5858

5959
def test_create_bucket(self):
6060
new_bucket_name = 'a-new-bucket'
@@ -115,7 +115,7 @@ def tearDown(self):
115115
class TestStorageWriteFiles(TestStorageFiles):
116116

117117
def test_large_file_write_from_stream(self):
118-
blob = storage.Blob(bucket=self.bucket, name='LargeFile')
118+
blob = self.bucket.blob('LargeFile')
119119
self.assertEqual(blob._properties, {})
120120

121121
file_data = self.FILES['big']
@@ -129,7 +129,7 @@ def test_large_file_write_from_stream(self):
129129
self.assertEqual(md5_hash, file_data['hash'])
130130

131131
def test_small_file_write_from_filename(self):
132-
blob = storage.Blob(bucket=self.bucket, name='SmallFile')
132+
blob = self.bucket.blob('SmallFile')
133133
self.assertEqual(blob._properties, {})
134134

135135
file_data = self.FILES['simple']
@@ -155,12 +155,12 @@ def test_write_metadata(self):
155155
self.assertEqual(blob.content_type, 'image/png')
156156

157157
def test_direct_write_and_read_into_file(self):
158-
blob = storage.Blob(bucket=self.bucket, name='MyBuffer')
158+
blob = self.bucket.blob('MyBuffer')
159159
file_contents = b'Hello World'
160160
blob.upload_from_string(file_contents)
161161
self.case_blobs_to_delete.append(blob)
162162

163-
same_blob = storage.Blob(bucket=self.bucket, name='MyBuffer')
163+
same_blob = self.bucket.blob('MyBuffer')
164164
same_blob.reload() # Initialize properties.
165165
temp_filename = tempfile.mktemp()
166166
with open(temp_filename, 'wb') as file_obj:
@@ -317,7 +317,7 @@ def setUp(self):
317317
with open(logo_path, 'rb') as file_obj:
318318
self.LOCAL_FILE = file_obj.read()
319319

320-
blob = storage.Blob(bucket=self.bucket, name='LogoToSign.jpg')
320+
blob = self.bucket.blob('LogoToSign.jpg')
321321
blob.upload_from_string(self.LOCAL_FILE)
322322
self.case_blobs_to_delete.append(blob)
323323

@@ -327,7 +327,7 @@ def tearDown(self):
327327
blob.delete()
328328

329329
def test_create_signed_read_url(self):
330-
blob = storage.Blob(bucket=self.bucket, name='LogoToSign.jpg')
330+
blob = self.bucket.blob('LogoToSign.jpg')
331331
expiration = int(time.time() + 5)
332332
signed_url = blob.generate_signed_url(expiration, method='GET',
333333
client=CLIENT)
@@ -337,7 +337,7 @@ def test_create_signed_read_url(self):
337337
self.assertEqual(content, self.LOCAL_FILE)
338338

339339
def test_create_signed_delete_url(self):
340-
blob = storage.Blob(bucket=self.bucket, name='LogoToSign.jpg')
340+
blob = self.bucket.blob('LogoToSign.jpg')
341341
expiration = int(time.time() + 283473274)
342342
signed_delete_url = blob.generate_signed_url(expiration,
343343
method='DELETE',

0 commit comments

Comments
 (0)