@@ -146,7 +146,7 @@ def download2stream(self, path: Union[str, FsNode], fp, **kwargs) -> None:
146146 :param path: path to download file.
147147 :param fp: filename (string), pathlib.Path object or a file object.
148148 The object must implement the ``file.write`` method and be able to write binary data.
149- :param kwargs: **chunk_size** an int value specifying chunk size to write. Default = **4Mb **
149+ :param kwargs: **chunk_size** an int value specifying chunk size to write. Default = **5Mb **
150150 """
151151 path = path .user_path if isinstance (path , FsNode ) else path
152152 if isinstance (fp , (str , Path )):
@@ -179,7 +179,7 @@ def download_directory_as_zip(
179179 result_path ,
180180 "wb" ,
181181 ) as fp :
182- for data_chunk in response .iter_raw (chunk_size = kwargs .get ("chunk_size" , 4 * 1024 * 1024 )):
182+ for data_chunk in response .iter_raw (chunk_size = kwargs .get ("chunk_size" , 5 * 1024 * 1024 )):
183183 fp .write (data_chunk )
184184 return Path (result_path )
185185
@@ -201,14 +201,15 @@ def upload_stream(self, path: Union[str, FsNode], fp, **kwargs) -> FsNode:
201201 :param path: file's upload path.
202202 :param fp: filename (string), pathlib.Path object or a file object.
203203 The object must implement the ``file.read`` method providing data with str or bytes type.
204- :param kwargs: **chunk_size** an int value specifying chunk size to read. Default = **4Mb **
204+ :param kwargs: **chunk_size** an int value specifying chunk size to read. Default = **5Mb **
205205 """
206206 path = path .user_path if isinstance (path , FsNode ) else path
207+ chunk_size = kwargs .get ("chunk_size" , 5 * 1024 * 1024 )
207208 if isinstance (fp , (str , Path )):
208209 with builtins .open (fp , "rb" ) as f :
209- return self .__upload_stream (path , f , ** kwargs )
210+ return self .__upload_stream (path , f , chunk_size )
210211 elif hasattr (fp , "read" ):
211- return self .__upload_stream (path , fp , ** kwargs )
212+ return self .__upload_stream (path , fp , chunk_size )
212213 else :
213214 raise TypeError ("`fp` must be a path to file or an object with `read` method." )
214215
@@ -688,36 +689,48 @@ def __download2stream(self, path: str, fp, **kwargs) -> None:
688689 ) as response : # type: ignore
689690 self ._session .response_headers = response .headers
690691 check_error (response .status_code , f"download_stream: user={ self ._session .user } , path={ path } " )
691- for data_chunk in response .iter_raw (chunk_size = kwargs .get ("chunk_size" , 4 * 1024 * 1024 )):
692+ for data_chunk in response .iter_raw (chunk_size = kwargs .get ("chunk_size" , 5 * 1024 * 1024 )):
692693 fp .write (data_chunk )
693694
694- def __upload_stream (self , path : str , fp , ** kwargs ) -> FsNode :
695- _dav_path = self ._dav_get_obj_path (self ._session .user , random_string (64 ), root_path = "/uploads" )
696- response = self ._session .dav ("MKCOL" , _dav_path )
695+ def __upload_stream (self , path : str , fp , chunk_size : int ) -> FsNode :
696+ _dav_path = self ._dav_get_obj_path (self ._session .user , "nc-py-api-" + random_string (56 ), root_path = "/uploads" )
697+ _v2 = bool (self ._session .cfg .options .upload_chunk_v2 and chunk_size >= 5 * 1024 * 1024 )
698+ full_path = self ._dav_get_obj_path (self ._session .user , path )
699+ headers = {"Destination" : self ._session .cfg .dav_endpoint + full_path }
700+ if _v2 :
701+ response = self ._session .dav ("MKCOL" , _dav_path , headers = headers )
702+ else :
703+ response = self ._session .dav ("MKCOL" , _dav_path )
697704 check_error (response .status_code )
698705 try :
699- chunk_size = kwargs .get ("chunk_size" , 4 * 1024 * 1024 )
700- start_bytes = end_bytes = 0
706+ start_bytes = end_bytes = chunk_number = 0
701707 while True :
702708 piece = fp .read (chunk_size )
703709 if not piece :
704710 break
705711 end_bytes = start_bytes + len (piece )
706- _filename = str (start_bytes ).rjust (15 , "0" ) + "-" + str (end_bytes ).rjust (15 , "0" )
707- response = self ._session .dav ("PUT" , _dav_path + "/" + _filename , data = piece )
712+ if _v2 :
713+ response = self ._session .dav (
714+ "PUT" , _dav_path + "/" + str (chunk_number ), data = piece , headers = headers
715+ )
716+ else :
717+ _filename = str (start_bytes ).rjust (15 , "0" ) + "-" + str (end_bytes ).rjust (15 , "0" )
718+ response = self ._session .dav ("PUT" , _dav_path + "/" + _filename , data = piece )
708719 check_error (
709- response .status_code , f"upload_stream: user={ self ._session .user } , path={ path } , cur_size={ end_bytes } "
720+ response .status_code ,
721+ f"upload_stream(v={ _v2 } ): user={ self ._session .user } , path={ path } , cur_size={ end_bytes } " ,
710722 )
711723 start_bytes = end_bytes
712- full_path = self . _dav_get_obj_path ( self . _session . user , path )
713- headers = { "Destination" : self . _session . cfg . dav_endpoint + full_path }
724+ chunk_number += 1
725+
714726 response = self ._session .dav (
715727 "MOVE" ,
716728 _dav_path + "/.file" ,
717729 headers = headers ,
718730 )
719731 check_error (
720- response .status_code , f"upload_stream: user={ self ._session .user } , path={ path } , total_size={ end_bytes } "
732+ response .status_code ,
733+ f"upload_stream(v={ _v2 } ): user={ self ._session .user } , path={ path } , total_size={ end_bytes } " ,
721734 )
722735 return FsNode (full_path .strip ("/" ), ** self .__get_etag_fileid_from_response (response ))
723736 finally :
0 commit comments