1616
1717import concurrent .futures
1818
19+ import os
1920import tempfile
21+ import warnings
2022
2123from google .api_core import exceptions
2224
25+ warnings .warn (
26+ "The module `transfer_manager` is a preview feature. Functionality and API "
27+ "may change. This warning will be removed in a future release."
28+ )
29+
2330
2431DEFAULT_CHUNK_SIZE = 200 * 1024 * 1024
2532
@@ -305,7 +312,7 @@ def download_range_via_tempfile(blob, start, end, download_kwargs):
305312def upload_many_from_filenames (
306313 bucket ,
307314 filenames ,
308- root = "" ,
315+ source_directory = "" ,
309316 blob_name_prefix = "" ,
310317 skip_if_exists = False ,
311318 blob_constructor_kwargs = None ,
@@ -321,10 +328,10 @@ def upload_many_from_filenames(
321328 The destination blobs are automatically created, with blob names based on
322329 the source filenames and the blob_name_prefix.
323330
324- For example, if the `filenames` include "images/icon.jpg", `root` is
325- "/home/myuser/", and `blob_name_prefix` is "myfiles/", then the file at
326- "/home/myuser/images/icon.jpg" will be uploaded to a blob named
327- "myfiles/images/icon.jpg".
331+ For example, if the `filenames` include "images/icon.jpg",
332+ `source_directory` is "/home/myuser/", and `blob_name_prefix` is "myfiles/",
333+ then the file at "/home/myuser/images/icon.jpg" will be uploaded to a blob
334+ named "myfiles/images/icon.jpg".
328335
329336 :type bucket: 'google.cloud.storage.bucket.Bucket'
330337 :param bucket:
@@ -333,35 +340,35 @@ def upload_many_from_filenames(
333340 :type filenames: list(str)
334341 :param filenames:
335342 A list of filenames to be uploaded. This may include part of the path.
336- The full path to the file must be root + filename. The filename is
337- separate from the root because the filename will also determine the
338- name of the destination blob.
343+ The full path to the file must be source_directory + filename.
339344
340- :type root: str
341- :param root:
342- A string that will be prepended to each filename in the input list, in
343- order to find the source file for each blob. Unlike the filename itself,
344- the root string does not affect the name of the uploaded blob itself.
345- The root string will usually end in "/" (or "\\ " depending on platform)
346- but is not required to do so.
345+ :type source_directory: str
346+ :param source_directory:
347+ A string that will be prepended (with os.path.join()) to each filename
348+ in the input list, in order to find the source file for each blob.
349+ Unlike the filename itself, the source_directory does not affect the
350+ name of the uploaded blob.
347351
348- For instance, if the root string is "/tmp/img- " and a filename is
352+ For instance, if the source_directory is "/tmp/img/ " and a filename is
349353 "0001.jpg", with an empty blob_name_prefix, then the file uploaded will
350- be "/tmp/img- 0001.jpg" and the destination blob will be "0001.jpg".
354+ be "/tmp/img/ 0001.jpg" and the destination blob will be "0001.jpg".
351355
352356 This parameter can be an empty string.
353357
358+ Note that this parameter allows directory traversal (e.g. "/", "../")
359+ and is not intended for unsanitized end user input.
360+
354361 :type blob_name_prefix: str
355362 :param blob_name_prefix:
356363 A string that will be prepended to each filename in the input list, in
357364 order to determine the name of the destination blob. Unlike the filename
358365 itself, the prefix string does not affect the location the library will
359366 look for the source data on the local filesystem.
360367
361- For instance, if the root is "/tmp/img- ", the blob_name_prefix is
362- "myuser/mystuff-" and a filename is "0001.jpg" then the file uploaded
363- will be "/tmp/img- 0001.jpg" and the destination blob will be
364- "myuser/mystuff-0001.jpg".
368+ For instance, if the source_directory is "/tmp/img/ ", the
369+ blob_name_prefix is "myuser/mystuff-" and a filename is "0001.jpg" then
370+ the file uploaded will be "/tmp/img/ 0001.jpg" and the destination blob
371+ will be "myuser/mystuff-0001.jpg".
365372
366373 The blob_name_prefix can be blank (an empty string).
367374
@@ -370,7 +377,7 @@ def upload_many_from_filenames(
370377 If True, blobs that already have a live version will not be overwritten.
371378 This is accomplished by setting "if_generation_match = 0" on uploads.
372379 Uploads so skipped will result in a 412 Precondition Failed response
373- code, which will be included in the return value but not raised
380+ code, which will be included in the return value, but not raised
374381 as an exception regardless of the value of raise_exception.
375382
376383 :type blob_constructor_kwargs: dict
@@ -426,7 +433,7 @@ def upload_many_from_filenames(
426433 file_blob_pairs = []
427434
428435 for filename in filenames :
429- path = root + filename
436+ path = os . path . join ( source_directory , filename )
430437 blob_name = blob_name_prefix + filename
431438 blob = bucket .blob (blob_name , ** blob_constructor_kwargs )
432439 file_blob_pairs .append ((path , blob ))
@@ -444,26 +451,27 @@ def upload_many_from_filenames(
444451def download_many_to_path (
445452 bucket ,
446453 blob_names ,
447- path_root = "" ,
454+ destination_directory = "" ,
448455 blob_name_prefix = "" ,
449456 download_kwargs = None ,
450457 max_workers = None ,
451458 deadline = None ,
459+ create_directories = True ,
452460 raise_exception = False ,
453461):
454462 """Download many files concurrently by their blob names.
455463
456464 This function is a PREVIEW FEATURE: the API may change in a future version.
457465
458- The destination files are automatically created, with filenames based on
459- the source blob_names and the path_root .
466+ The destination files are automatically created, with paths based on the
467+ source blob_names and the destination_directory .
460468
461469 The destination files are not automatically deleted if their downloads fail,
462470 so please check the return value of this function for any exceptions, or
463471 enable `raise_exception=True`, and process the files accordingly.
464472
465- For example, if the `blob_names` include "icon.jpg", `path_root` is
466- "/home/myuser/", and `blob_name_prefix` is "images/", then the blob named
473+ For example, if the `blob_names` include "icon.jpg", `destination_directory`
474+ is "/home/myuser/", and `blob_name_prefix` is "images/", then the blob named
467475 "images/icon.jpg" will be downloaded to a file named
468476 "/home/myuser/icon.jpg".
469477
@@ -482,26 +490,31 @@ def download_many_to_path(
482490 the blob names that need not be part of the destination path should be
483491 included in the blob_name_prefix.
484492
485- :type path_root: str
486- :param path_root:
487- A string that will be prepended to each blob_name in the input list,
488- in order to determine the destination path for that blob. The path_root
489- string will usually end in "/" (or "\\ " depending on platform) but is
490- not required to do so. For instance, if the path_root string is
491- "/tmp/img-" and a blob_name is "0001.jpg", with an empty
492- blob_name_prefix, then the source blob "0001.jpg" will be downloaded to
493- destination "/tmp/img-0001.jpg" . This parameter can be an empty string.
493+ :type destination_directory: str
494+ :param destination_directory:
495+ A string that will be prepended (with os.path.join()) to each blob_name
496+ in the input list, in order to determine the destination path for that
497+ blob.
498+
499+ For instance, if the destination_directory string is "/tmp/img" and a
500+ blob_name is "0001.jpg", with an empty blob_name_prefix, then the source
501+ blob "0001.jpg" will be downloaded to destination "/tmp/img/0001.jpg" .
502+
503+ This parameter can be an empty string.
504+
505+ Note that this parameter allows directory traversal (e.g. "/", "../")
506+ and is not intended for unsanitized end user input.
494507
495508 :type blob_name_prefix: str
496509 :param blob_name_prefix:
497510 A string that will be prepended to each blob_name in the input list, in
498511 order to determine the name of the source blob. Unlike the blob_name
499512 itself, the prefix string does not affect the destination path on the
500- local filesystem. For instance, if the path_root is "/tmp/img-", the
501- blob_name_prefix is "myuser/mystuff-" and a blob_name is "0001.jpg" then
502- the source blob "myuser/mystuff-0001.jpg" will be downloaded to
503- "/tmp/img- 0001.jpg". The blob_name_prefix can be blank (an empty
504- string).
513+ local filesystem. For instance, if the destination_directory is
514+ "/tmp/img/", the blob_name_prefix is "myuser/mystuff-" and a blob_name
515+ is "0001.jpg" then the source blob "myuser/mystuff-0001.jpg" will be
516+ downloaded to "/tmp/img/ 0001.jpg". The blob_name_prefix can be blank
517+ (an empty string).
505518
506519 :type download_kwargs: dict
507520 :param download_kwargs:
@@ -523,6 +536,12 @@ def download_many_to_path(
523536 progress and concurrent.futures.TimeoutError will be raised. This can be
524537 left as the default of None (no deadline) for most use cases.
525538
539+ :type create_directories: bool
540+ :param create_directories:
541+ If True, recursively create any directories that do not exist. For
542+ instance, if downloading object "images/img001.png", create the
543+ directory "images" before downloading.
544+
526545 :type raise_exception: bool
527546 :param raise_exception:
528547 If True, instead of adding exceptions to the list of return values,
@@ -545,7 +564,10 @@ def download_many_to_path(
545564
546565 for blob_name in blob_names :
547566 full_blob_name = blob_name_prefix + blob_name
548- path = path_root + blob_name
567+ path = os .path .join (destination_directory , blob_name )
568+ if create_directories :
569+ directory , _ = os .path .split (path )
570+ os .makedirs (directory , exist_ok = True )
549571 blob_file_pairs .append ((bucket .blob (full_blob_name ), path ))
550572
551573 return download_many (
0 commit comments