3131from gcloud .credentials import generate_signed_url
3232from gcloud .exceptions import NotFound
3333from gcloud .storage ._helpers import _PropertyMixin
34+ from gcloud .storage ._helpers import _require_connection
3435from gcloud .storage ._helpers import _scalar_property
3536from gcloud .storage import _implicit_environ
3637from gcloud .storage .acl import ObjectACL
@@ -164,7 +165,8 @@ def public_url(self):
164165 bucket_name = self .bucket .name ,
165166 quoted_name = quote (self .name , safe = '' ))
166167
167- def generate_signed_url (self , expiration , method = 'GET' ):
168+ def generate_signed_url (self , expiration , method = 'GET' ,
169+ connection = None , credentials = None ):
168170 """Generates a signed URL for this blob.
169171
170172 If you have a blob that you want to allow access to for a set
@@ -181,6 +183,15 @@ def generate_signed_url(self, expiration, method='GET'):
181183 :type method: string
182184 :param method: The HTTP verb that will be used when requesting the URL.
183185
186+ :type connection: :class:`gcloud.storage.connection.Connection` or
187+ ``NoneType``
188+ :param connection: Optional. The connection to use when sending
189+ requests. If not provided, falls back to default.
190+
191+ :type credentials: :class:`oauth2client.client.OAuth2Credentials` or
192+ :class:`NoneType`
193+ :param credentials: The OAuth2 credentials to use to sign the URL.
194+
184195 :rtype: string
185196 :returns: A signed URL you can use to access the resource
186197 until expiration.
@@ -189,23 +200,33 @@ def generate_signed_url(self, expiration, method='GET'):
189200 bucket_name = self .bucket .name ,
190201 quoted_name = quote (self .name , safe = '' ))
191202
203+ if credentials is None :
204+ connection = _require_connection (connection )
205+ credentials = connection .credentials
206+
192207 return generate_signed_url (
193- self . connection . credentials , resource = resource ,
208+ credentials , resource = resource ,
194209 api_access_endpoint = _API_ACCESS_ENDPOINT ,
195210 expiration = expiration , method = method )
196211
197- def exists (self ):
212+ def exists (self , connection = None ):
198213 """Determines whether or not this blob exists.
199214
215+ :type connection: :class:`gcloud.storage.connection.Connection` or
216+ ``NoneType``
217+ :param connection: Optional. The connection to use when sending
218+ requests. If not provided, falls back to default.
219+
200220 :rtype: boolean
201221 :returns: True if the blob exists in Cloud Storage.
202222 """
223+ connection = _require_connection (connection )
203224 try :
204225 # We only need the status code (200 or not) so we seek to
205226 # minimize the returned payload.
206227 query_params = {'fields' : 'name' }
207- self . connection .api_request (method = 'GET' , path = self .path ,
208- query_params = query_params )
228+ connection .api_request (method = 'GET' , path = self .path ,
229+ query_params = query_params )
209230 return True
210231 except NotFound :
211232 return False
@@ -242,15 +263,20 @@ def delete(self):
242263 """
243264 return self .bucket .delete_blob (self .name )
244265
245- def download_to_file (self , file_obj ):
266+ def download_to_file (self , file_obj , connection = None ):
246267 """Download the contents of this blob into a file-like object.
247268
248269 :type file_obj: file
249270 :param file_obj: A file handle to which to write the blob's data.
250271
272+ :type connection: :class:`gcloud.storage.connection.Connection` or
273+ ``NoneType``
274+ :param connection: Optional. The connection to use when sending
275+ requests. If not provided, falls back to default.
276+
251277 :raises: :class:`gcloud.exceptions.NotFound`
252278 """
253-
279+ connection = _require_connection ( connection )
254280 download_url = self .media_link
255281
256282 # Use apitools 'Download' facility.
@@ -261,41 +287,51 @@ def download_to_file(self, file_obj):
261287 headers ['Range' ] = 'bytes=0-%d' % (self .chunk_size - 1 ,)
262288 request = http_wrapper .Request (download_url , 'GET' , headers )
263289
264- download .InitializeDownload (request , self . connection .http )
290+ download .InitializeDownload (request , connection .http )
265291
266292 # Should we be passing callbacks through from caller? We can't
267293 # pass them as None, because apitools wants to print to the console
268294 # by default.
269295 download .StreamInChunks (callback = lambda * args : None ,
270296 finish_callback = lambda * args : None )
271297
272- def download_to_filename (self , filename ):
298+ def download_to_filename (self , filename , connection = None ):
273299 """Download the contents of this blob into a named file.
274300
275301 :type filename: string
276302 :param filename: A filename to be passed to ``open``.
277303
304+ :type connection: :class:`gcloud.storage.connection.Connection` or
305+ ``NoneType``
306+ :param connection: Optional. The connection to use when sending
307+ requests. If not provided, falls back to default.
308+
278309 :raises: :class:`gcloud.exceptions.NotFound`
279310 """
280311 with open (filename , 'wb' ) as file_obj :
281- self .download_to_file (file_obj )
312+ self .download_to_file (file_obj , connection = connection )
282313
283314 mtime = time .mktime (self .updated .timetuple ())
284315 os .utime (file_obj .name , (mtime , mtime ))
285316
286- def download_as_string (self ):
317+ def download_as_string (self , connection = None ):
287318 """Download the contents of this blob as a string.
288319
320+ :type connection: :class:`gcloud.storage.connection.Connection` or
321+ ``NoneType``
322+ :param connection: Optional. The connection to use when sending
323+ requests. If not provided, falls back to default.
324+
289325 :rtype: bytes
290326 :returns: The data stored in this blob.
291327 :raises: :class:`gcloud.exceptions.NotFound`
292328 """
293329 string_buffer = BytesIO ()
294- self .download_to_file (string_buffer )
330+ self .download_to_file (string_buffer , connection = connection )
295331 return string_buffer .getvalue ()
296332
297333 def upload_from_file (self , file_obj , rewind = False , size = None ,
298- content_type = None , num_retries = 6 ):
334+ content_type = None , num_retries = 6 , connection = None ):
299335 """Upload the contents of this blob from a file-like object.
300336
301337 The content type of the upload will either be
@@ -331,7 +367,13 @@ def upload_from_file(self, file_obj, rewind=False, size=None,
331367
332368 :type num_retries: integer
333369 :param num_retries: Number of upload retries. Defaults to 6.
370+
371+ :type connection: :class:`gcloud.storage.connection.Connection` or
372+ ``NoneType``
373+ :param connection: Optional. The connection to use when sending
374+ requests. If not provided, falls back to default.
334375 """
376+ connection = _require_connection (connection )
335377 content_type = (content_type or self ._properties .get ('contentType' ) or
336378 'application/octet-stream' )
337379
@@ -341,11 +383,10 @@ def upload_from_file(self, file_obj, rewind=False, size=None,
341383
342384 # Get the basic stats about the file.
343385 total_bytes = size or os .fstat (file_obj .fileno ()).st_size
344- conn = self .connection
345386 headers = {
346387 'Accept' : 'application/json' ,
347388 'Accept-Encoding' : 'gzip, deflate' ,
348- 'User-Agent' : conn .USER_AGENT ,
389+ 'User-Agent' : connection .USER_AGENT ,
349390 }
350391
351392 upload = transfer .Upload (file_obj , content_type , total_bytes ,
@@ -357,20 +398,20 @@ def upload_from_file(self, file_obj, rewind=False, size=None,
357398 upload_config = _UploadConfig ()
358399
359400 # Temporary URL, until we know simple vs. resumable.
360- base_url = conn .API_BASE_URL + '/upload'
361- upload_url = conn .build_api_url (api_base_url = base_url ,
362- path = self .bucket .path + '/o' )
401+ base_url = connection .API_BASE_URL + '/upload'
402+ upload_url = connection .build_api_url (api_base_url = base_url ,
403+ path = self .bucket .path + '/o' )
363404
364405 # Use apitools 'Upload' facility.
365406 request = http_wrapper .Request (upload_url , 'POST' , headers )
366407
367408 upload .ConfigureRequest (upload_config , request , url_builder )
368409 query_params = url_builder .query_params
369- base_url = conn .API_BASE_URL + '/upload'
370- request .url = conn .build_api_url (api_base_url = base_url ,
371- path = self .bucket .path + '/o' ,
372- query_params = query_params )
373- upload .InitializeUpload (request , conn .http )
410+ base_url = connection .API_BASE_URL + '/upload'
411+ request .url = connection .build_api_url (api_base_url = base_url ,
412+ path = self .bucket .path + '/o' ,
413+ query_params = query_params )
414+ upload .InitializeUpload (request , connection .http )
374415
375416 # Should we be passing callbacks through from caller? We can't
376417 # pass them as None, because apitools wants to print to the console
@@ -380,15 +421,16 @@ def upload_from_file(self, file_obj, rewind=False, size=None,
380421 callback = lambda * args : None ,
381422 finish_callback = lambda * args : None )
382423 else :
383- http_response = http_wrapper .MakeRequest (conn .http , request ,
424+ http_response = http_wrapper .MakeRequest (connection .http , request ,
384425 retries = num_retries )
385426 response_content = http_response .content
386427 if not isinstance (response_content ,
387428 six .string_types ): # pragma: NO COVER Python3
388429 response_content = response_content .decode ('utf-8' )
389430 self ._set_properties (json .loads (response_content ))
390431
391- def upload_from_filename (self , filename , content_type = None ):
432+ def upload_from_filename (self , filename , content_type = None ,
433+ connection = None ):
392434 """Upload this blob's contents from the content of a named file.
393435
394436 The content type of the upload will either be
@@ -412,15 +454,22 @@ def upload_from_filename(self, filename, content_type=None):
412454
413455 :type content_type: string or ``NoneType``
414456 :param content_type: Optional type of content being uploaded.
457+
458+ :type connection: :class:`gcloud.storage.connection.Connection` or
459+ ``NoneType``
460+ :param connection: Optional. The connection to use when sending
461+ requests. If not provided, falls back to default.
415462 """
416463 content_type = content_type or self ._properties .get ('contentType' )
417464 if content_type is None :
418465 content_type , _ = mimetypes .guess_type (filename )
419466
420467 with open (filename , 'rb' ) as file_obj :
421- self .upload_from_file (file_obj , content_type = content_type )
468+ self .upload_from_file (file_obj , content_type = content_type ,
469+ connection = connection )
422470
423- def upload_from_string (self , data , content_type = 'text/plain' ):
471+ def upload_from_string (self , data , content_type = 'text/plain' ,
472+ connection = None ):
424473 """Upload contents of this blob from the provided string.
425474
426475 .. note::
@@ -437,14 +486,19 @@ def upload_from_string(self, data, content_type='text/plain'):
437486 :type data: bytes or text
438487 :param data: The data to store in this blob. If the value is
439488 text, it will be encoded as UTF-8.
489+
490+ :type connection: :class:`gcloud.storage.connection.Connection` or
491+ ``NoneType``
492+ :param connection: Optional. The connection to use when sending
493+ requests. If not provided, falls back to default.
440494 """
441495 if isinstance (data , six .text_type ):
442496 data = data .encode ('utf-8' )
443497 string_buffer = BytesIO ()
444498 string_buffer .write (data )
445499 self .upload_from_file (file_obj = string_buffer , rewind = True ,
446- size = len (data ),
447- content_type = content_type )
500+ size = len (data ), content_type = content_type ,
501+ connection = connection )
448502
449503 def make_public (self ):
450504 """Make this blob public giving all users read access."""
0 commit comments