1313
1414from .encryption .setting import EncryptionSetting , EncryptionSettingFactory
1515from .encryption .types import EncryptionMode
16- from .exception import BucketIdNotFound , FileNotPresent , FileOrBucketNotFound , UnexpectedCloudBehaviour , UnrecognizedBucketType
16+ from .exception import BucketIdNotFound , CopySourceTooBig , FileNotPresent , FileOrBucketNotFound , UnexpectedCloudBehaviour , UnrecognizedBucketType
1717from .file_lock import (
1818 BucketRetentionSetting ,
1919 FileLockConfiguration ,
@@ -550,6 +550,8 @@ def create_file(
550550 encryption : Optional [EncryptionSetting ] = None ,
551551 file_retention : Optional [FileRetentionSetting ] = None ,
552552 legal_hold : Optional [LegalHold ] = None ,
553+ min_part_size = None ,
554+ max_part_size = None ,
553555 ):
554556 """
555557 Creates a new file in this bucket using an iterable (list, tuple etc) of remote or local sources.
@@ -574,6 +576,8 @@ def create_file(
574576 :param b2sdk.v2.EncryptionSetting encryption: encryption settings (``None`` if unknown)
575577 :param b2sdk.v2.FileRetentionSetting file_retention: file retention setting
576578 :param bool legal_hold: legal hold setting
579+ :param int min_part_size: lower limit of part size for the transfer planner, in bytes
580+ :param int max_part_size: upper limit of part size for the transfer planner, in bytes
577581 """
578582 return self ._create_file (
579583 self .api .services .emerger .emerge ,
@@ -587,6 +591,8 @@ def create_file(
587591 encryption = encryption ,
588592 file_retention = file_retention ,
589593 legal_hold = legal_hold ,
594+ min_part_size = min_part_size ,
595+ max_part_size = max_part_size ,
590596 )
591597
592598 def create_file_stream (
@@ -601,6 +607,8 @@ def create_file_stream(
601607 encryption : Optional [EncryptionSetting ] = None ,
602608 file_retention : Optional [FileRetentionSetting ] = None ,
603609 legal_hold : Optional [LegalHold ] = None ,
610+ min_part_size = None ,
611+ max_part_size = None ,
604612 ):
605613 """
606614 Creates a new file in this bucket using a stream of multiple remote or local sources.
@@ -627,6 +635,8 @@ def create_file_stream(
627635 :param b2sdk.v2.EncryptionSetting encryption: encryption settings (``None`` if unknown)
628636 :param b2sdk.v2.FileRetentionSetting file_retention: file retention setting
629637 :param bool legal_hold: legal hold setting
638+ :param int min_part_size: lower limit of part size for the transfer planner, in bytes
639+ :param int max_part_size: upper limit of part size for the transfer planner, in bytes
630640 """
631641 return self ._create_file (
632642 self .api .services .emerger .emerge_stream ,
@@ -640,6 +650,8 @@ def create_file_stream(
640650 encryption = encryption ,
641651 file_retention = file_retention ,
642652 legal_hold = legal_hold ,
653+ min_part_size = min_part_size ,
654+ max_part_size = max_part_size ,
643655 )
644656
645657 def _create_file (
@@ -655,6 +667,8 @@ def _create_file(
655667 encryption : Optional [EncryptionSetting ] = None ,
656668 file_retention : Optional [FileRetentionSetting ] = None ,
657669 legal_hold : Optional [LegalHold ] = None ,
670+ min_part_size = None ,
671+ max_part_size = None ,
658672 ):
659673 validate_b2_file_name (file_name )
660674 progress_listener = progress_listener or DoNothingProgressListener ()
@@ -671,6 +685,8 @@ def _create_file(
671685 encryption = encryption ,
672686 file_retention = file_retention ,
673687 legal_hold = legal_hold ,
688+ min_part_size = min_part_size ,
689+ max_part_size = max_part_size ,
674690 )
675691
676692 def concatenate (
@@ -685,6 +701,8 @@ def concatenate(
685701 encryption : Optional [EncryptionSetting ] = None ,
686702 file_retention : Optional [FileRetentionSetting ] = None ,
687703 legal_hold : Optional [LegalHold ] = None ,
704+ min_part_size = None ,
705+ max_part_size = None ,
688706 ):
689707 """
690708 Creates a new file in this bucket by concatenating multiple remote or local sources.
@@ -706,6 +724,8 @@ def concatenate(
706724 :param b2sdk.v2.EncryptionSetting encryption: encryption settings (``None`` if unknown)
707725 :param b2sdk.v2.FileRetentionSetting file_retention: file retention setting
708726 :param bool legal_hold: legal hold setting
727+ :param int min_part_size: lower limit of part size for the transfer planner, in bytes
728+ :param int max_part_size: upper limit of part size for the transfer planner, in bytes
709729 """
710730 return self .create_file (
711731 WriteIntent .wrap_sources_iterator (outbound_sources ),
@@ -718,6 +738,8 @@ def concatenate(
718738 encryption = encryption ,
719739 file_retention = file_retention ,
720740 legal_hold = legal_hold ,
741+ min_part_size = min_part_size ,
742+ max_part_size = max_part_size ,
721743 )
722744
723745 def concatenate_stream (
@@ -806,6 +828,8 @@ def copy(
806828 source_content_type : Optional [str ] = None ,
807829 file_retention : Optional [FileRetentionSetting ] = None ,
808830 legal_hold : Optional [LegalHold ] = None ,
831+ min_part_size = None ,
832+ max_part_size = None ,
809833 ):
810834 """
811835 Creates a new file in this bucket by (server-side) copying from an existing file.
@@ -831,6 +855,8 @@ def copy(
831855 :param str,None source_content_type: source file's content type, useful when copying files with SSE-C
832856 :param b2sdk.v2.FileRetentionSetting file_retention: file retention setting for the new file.
833857 :param bool legal_hold: legal hold setting for the new file.
858+ :param int min_part_size: lower limit of part size for the transfer planner, in bytes
859+ :param int max_part_size: upper limit of part size for the transfer planner, in bytes
834860 """
835861
836862 copy_source = CopySource (
@@ -844,30 +870,38 @@ def copy(
844870 if not length :
845871 # TODO: it feels like this should be checked on lower level - eg. RawApi
846872 validate_b2_file_name (new_file_name )
847- progress_listener = progress_listener or DoNothingProgressListener ()
848- return self .api .services .copy_manager .copy_file (
849- copy_source ,
850- new_file_name ,
851- content_type = content_type ,
852- file_info = file_info ,
853- destination_bucket_id = self .id_ ,
854- progress_listener = progress_listener ,
855- destination_encryption = destination_encryption ,
856- source_encryption = source_encryption ,
857- file_retention = file_retention ,
858- legal_hold = legal_hold ,
859- ).result ()
860- else :
861- return self .create_file (
862- [WriteIntent (copy_source )],
863- new_file_name ,
864- content_type = content_type ,
865- file_info = file_info ,
866- progress_listener = progress_listener ,
867- encryption = destination_encryption ,
868- file_retention = file_retention ,
869- legal_hold = legal_hold ,
870- )
873+ try :
874+ progress_listener = progress_listener or DoNothingProgressListener ()
875+ return self .api .services .copy_manager .copy_file (
876+ copy_source ,
877+ new_file_name ,
878+ content_type = content_type ,
879+ file_info = file_info ,
880+ destination_bucket_id = self .id_ ,
881+ progress_listener = progress_listener ,
882+ destination_encryption = destination_encryption ,
883+ source_encryption = source_encryption ,
884+ file_retention = file_retention ,
885+ legal_hold = legal_hold ,
886+ ).result ()
887+ except CopySourceTooBig as e :
888+ copy_source .length = e .size
889+ progress_listener = DoNothingProgressListener ()
890+ logger .warning (
891+ 'a copy of large object of unknown size is upgraded to the large file interface. No progress report will be provided.'
892+ )
893+ return self .create_file (
894+ [WriteIntent (copy_source )],
895+ new_file_name ,
896+ content_type = content_type ,
897+ file_info = file_info ,
898+ progress_listener = progress_listener ,
899+ encryption = destination_encryption ,
900+ file_retention = file_retention ,
901+ legal_hold = legal_hold ,
902+ min_part_size = min_part_size ,
903+ max_part_size = max_part_size ,
904+ )
871905
872906 def delete_file_version (self , file_id , file_name ):
873907 """
0 commit comments