@@ -217,9 +217,7 @@ def deliver_binary(
217217 Args:
218218 binary: The binary file to save.
219219 delivery_key: The unique key that was used to deliver the file.
220- save_path: The location to save the file to. If None,
221- the default "downloads" directory will be used. When
222- running via web, only the file name will be used.
220+ save_path: The location to save the file to.
223221 open_method: *web only* Whether to open the file in the browser or
224222 to prompt the user to download it. When running via a standard
225223 (non-web) terminal, this is ignored.
@@ -230,29 +228,52 @@ def deliver_binary(
230228 mime_type: *web only* The MIME type of the file. This will be used to
231229 set the `Content-Type` header in the HTTP response.
232230 """
231+
232+ def save_file_thread (binary : BinaryIO | TextIO , mode : str ) -> None :
233+ try :
234+ with open (save_path , mode ) as destination_file :
235+ read = binary .read
236+ write = destination_file .write
237+ chunk_size = 1024 * 64
238+ while True :
239+ data = read (chunk_size )
240+ if not data :
241+ # No data left to read - delivery is complete.
242+ self ._delivery_complete (delivery_key , save_path )
243+ break
244+ write (data )
245+ except Exception as error :
246+ # If any exception occurs during the delivery, pass
247+ # it on to the app via a DeliveryFailed event.
248+ self ._delivery_failed (delivery_key , exception = error )
249+ finally :
250+ if not binary .closed :
251+ binary .close ()
252+
233253 if isinstance (binary , BinaryIO ):
234254 mode = "wb"
235255 else :
236256 mode = "w"
237257
238- def save_file_thread ():
239- with open (save_path , mode ) as destination_file :
240- read = binary .read
241- write = destination_file .write
242- chunk_size = 1024 * 64
243- while True :
244- data = read (chunk_size )
245- if not data :
246- break
247- write (data )
248- binary .close ()
249- self ._app .call_from_thread (
250- self ._delivery_complete , delivery_key = delivery_key
251- )
252-
253- thread = threading .Thread (target = save_file_thread )
258+ thread = threading .Thread (target = save_file_thread , args = (binary , mode ))
254259 thread .start ()
255260
256- def _delivery_complete (self , delivery_key : str ) -> None :
257- """Called when a file has been delivered."""
258- self ._app .post_message (events .DeliveryComplete (delivery_key ))
261+ def _delivery_complete (self , delivery_key : str , save_path : Path | None ) -> None :
262+ """Called when a file has been delivered successfully.
263+
264+ Delivers a DeliveryComplete event to the app.
265+ """
266+ self ._app .call_from_thread (
267+ self ._app .post_message ,
268+ events .DeliveryComplete (key = delivery_key , path = save_path ),
269+ )
270+
271+ def _delivery_failed (self , delivery_key : str , exception : BaseException ) -> None :
272+ """Called when a file delivery fails.
273+
274+ Delivers a DeliveryFailed event to the app.
275+ """
276+ self ._app .call_from_thread (
277+ self ._app .post_message ,
278+ events .DeliveryFailed (key = delivery_key , exception = exception ),
279+ )
0 commit comments