@@ -374,7 +374,7 @@ def upload_folder(
374
374
375
375
@retry (ResponseStreamingError )
376
376
def upload_file (
377
- local_path : Path ,
377
+ local_path : Union [ str , Path ] ,
378
378
s3_path : S3URI ,
379
379
extra_args : Optional [Dict [str , Any ]] = None ,
380
380
transfer_config : Optional [TransferConfig ] = None ,
@@ -384,7 +384,7 @@ def upload_file(
384
384
):
385
385
s3_client = get_s3_client (** kwargs )
386
386
if force or should_sync (
387
- source_path = local_path , destination_path = s3_path , size_only = size_only , ** kwargs
387
+ source_path = Path ( local_path ) , destination_path = s3_path , size_only = size_only , ** kwargs
388
388
):
389
389
s3_client .upload_file (
390
390
Filename = str (local_path ),
@@ -527,15 +527,19 @@ def get_s3_path_stats(s3_path: S3URI, **kwargs) -> S3PathStats:
527
527
)
528
528
529
529
530
+ # TODO: Two things
531
+ # 1. allow for a way to specify `size_only` for this function when transfering large number of files
532
+ # 2. add flag for failing if no source data exists.
530
533
def sync_paths (
531
534
source_path : Union [Path , S3URI ],
532
535
destination_path : Union [Path , S3URI ],
533
- source_path_prefix : str = None ,
536
+ source_path_prefix : Optional [ str ] = None ,
534
537
include : Optional [List [Pattern ]] = None ,
535
538
exclude : Optional [List [Pattern ]] = None ,
536
539
extra_args : Optional [Dict [str , Any ]] = None ,
537
540
transfer_config : Optional [TransferConfig ] = None ,
538
541
force : bool = False ,
542
+ size_only : bool = False ,
539
543
delete : bool = False ,
540
544
** kwargs ,
541
545
) -> List [S3TransferResponse ]:
@@ -576,12 +580,17 @@ def sync_paths(
576
580
destination_path = destination_path ,
577
581
source_path_prefix = source_path_prefix ,
578
582
extra_args = extra_args ,
579
- force = force ,
580
583
)
581
584
for nested_source_path in nested_source_paths
582
585
]
583
586
584
- responses = process_transfer_requests (* requests , transfer_config = transfer_config , ** kwargs )
587
+ responses = process_transfer_requests (
588
+ * requests ,
589
+ transfer_config = transfer_config ,
590
+ force = force ,
591
+ size_only = size_only ,
592
+ ** kwargs ,
593
+ )
585
594
586
595
if delete :
587
596
logger .info (f"Sync: checking for files to delete following sync" )
@@ -613,7 +622,6 @@ def generate_transfer_request(
613
622
destination_path : Union [Path , S3URI ],
614
623
source_path_prefix : Optional [str ] = None ,
615
624
extra_args : Optional [Dict [str , Any ]] = None ,
616
- force : bool = True ,
617
625
) -> S3TransferRequest :
618
626
"""Create a S3 transfer request
619
627
@@ -641,26 +649,43 @@ def generate_transfer_request(
641
649
# This will be sanitized by S3URI class (removing double slashes)
642
650
new_destination_path = S3URI (destination_path + relative_source_path )
643
651
if isinstance (source_path , S3URI ):
644
- return S3CopyRequest (source_path , new_destination_path , force , extra_args = extra_args )
652
+ return S3CopyRequest (source_path , new_destination_path , extra_args = extra_args )
645
653
else :
646
- return S3UploadRequest (source_path , new_destination_path , force , extra_args = extra_args )
654
+ return S3UploadRequest (source_path , new_destination_path , extra_args = extra_args )
647
655
elif isinstance (source_path , S3URI ) and isinstance (destination_path , Path ):
648
656
local_destination_path : Path = (
649
657
Path (get_path_with_root (relative_source_path , destination_path ))
650
658
if relative_source_path
651
659
else destination_path
652
660
)
653
- return S3DownloadRequest (source_path , local_destination_path , force )
661
+ return S3DownloadRequest (source_path , local_destination_path )
654
662
else :
655
663
raise ValueError ("Local to local transfer is not " )
656
664
657
665
658
666
def process_transfer_requests (
659
667
* transfer_requests : S3TransferRequest ,
660
668
transfer_config : Optional [TransferConfig ] = None ,
669
+ force : bool = False ,
670
+ size_only : bool = False ,
661
671
suppress_errors : bool = False ,
662
672
** kwargs ,
663
673
) -> List [S3TransferResponse ]:
674
+ """Process a list of S3 transfer requests
675
+
676
+ Args:
677
+ transfer_config (Optional[TransferConfig]): transfer config.
678
+ Defaults to None.
679
+ force (bool): Whether to force the transfer.
680
+ Defaults to False.
681
+ size_only (bool): Whether to only check size when transferring.
682
+ Defaults to False.
683
+ suppress_errors (bool): Whether to suppress errors.
684
+ Defaults to False.
685
+
686
+ Returns:
687
+ List[S3TransferResponse]: List of transfer responses
688
+ """
664
689
transfer_responses = []
665
690
666
691
for request in transfer_requests :
@@ -671,7 +696,8 @@ def process_transfer_requests(
671
696
destination_path = request .destination_path ,
672
697
extra_args = request .extra_args ,
673
698
transfer_config = transfer_config ,
674
- force = request .force ,
699
+ force = force ,
700
+ size_only = size_only ,
675
701
** kwargs ,
676
702
)
677
703
elif isinstance (request , S3UploadRequest ):
@@ -680,7 +706,8 @@ def process_transfer_requests(
680
706
s3_path = request .destination_path ,
681
707
extra_args = request .extra_args ,
682
708
transfer_config = transfer_config ,
683
- force = request .force ,
709
+ force = force ,
710
+ size_only = size_only ,
684
711
** kwargs ,
685
712
)
686
713
elif isinstance (request , S3DownloadRequest ):
@@ -697,7 +724,8 @@ def process_transfer_requests(
697
724
s3_path = request .source_path ,
698
725
local_path = request .destination_path ,
699
726
transfer_config = transfer_config ,
700
- force = request .force ,
727
+ force = force ,
728
+ size_only = size_only ,
701
729
** kwargs ,
702
730
)
703
731
transfer_responses .append (S3TransferResponse (request , False ))
@@ -716,7 +744,12 @@ def process_transfer_requests(
716
744
copy_s3_path = sync_paths
717
745
718
746
719
- @retry (ClientError , [lambda ex : client_error_code_check (ex , "SlowDown" )])
747
+ client_error_code_check__SlowDown : Callable [[Exception ], bool ] = lambda ex : isinstance (
748
+ ex , ClientError
749
+ ) and client_error_code_check (ex , "SlowDown" )
750
+
751
+
752
+ @retry (ClientError , [client_error_code_check__SlowDown ])
720
753
def copy_s3_object (
721
754
source_path : S3URI ,
722
755
destination_path : S3URI ,
@@ -890,7 +923,7 @@ def list_s3_paths(
890
923
s3 = get_s3_client (** kwargs )
891
924
892
925
def match_results (value : str , patterns : List [Pattern ]) -> List [bool ]:
893
- return [_ .match (value ) for _ in patterns ]
926
+ return [_ .match (value ) is not None for _ in patterns ]
894
927
895
928
paginator = s3 .get_paginator ("list_objects_v2" )
896
929
@@ -1013,6 +1046,7 @@ def should_sync(
1013
1046
dest_local_path , multipart_chunk_size_bytes , multipart_threshold_bytes
1014
1047
)
1015
1048
else :
1049
+ logger .warning (f"Destination path { destination_path } does not exist as a file or object." )
1016
1050
return True
1017
1051
1018
1052
if isinstance (source_path , S3URI ) and is_object (source_path ):
@@ -1156,7 +1190,7 @@ def update_s3_storage_class(
1156
1190
print (
1157
1191
f"debug: current storage class: { s3_obj .storage_class } , target: { target_storage_class } "
1158
1192
)
1159
- current_storage_class = S3StorageClass .from_boto_s3_obj (s3_obj )
1193
+ current_storage_class = S3StorageClass .from_boto_s3_obj (s3_obj ) # type: ignore[arg-type]
1160
1194
# Current storage class matches target: No-op
1161
1195
if current_storage_class == target_storage_class :
1162
1196
continue
0 commit comments