@@ -896,6 +896,52 @@ def _mexists(cls, uris: Iterable[ResourcePath]) -> dict[ResourcePath, bool]:
896
896
results [uri ] = exists
897
897
return results
898
898
899
+ @classmethod
900
+ def mtransfer (
901
+ cls ,
902
+ transfer : str ,
903
+ * from_to : tuple [ResourcePath , ResourcePath ],
904
+ overwrite : bool = False ,
905
+ transaction : TransactionProtocol | None = None ,
906
+ ) -> dict [ResourcePath , bool ]:
907
+ """Transfer many files in bulk.
908
+
909
+ Parameters
910
+ ----------
911
+ transfer : `str`
912
+ Mode to use for transferring the resource. Generically there are
913
+ many standard options: copy, link, symlink, hardlink, relsymlink.
914
+ Not all URIs support all modes.
915
+ *from_to : `tuple` [ `ResourcePath`, `ResourcePath` ]
916
+ The source URI and the target URI.
917
+ overwrite : `bool`, optional
918
+ Allow an existing file to be overwritten. Defaults to `False`.
919
+ transaction : `~lsst.resources.utils.TransactionProtocol`, optional
920
+ A transaction object that can (depending on implementation)
921
+ rollback transfers on error. Not guaranteed to be implemented.
922
+ """
923
+ exists_executor = concurrent .futures .ThreadPoolExecutor (max_workers = MAX_WORKERS )
924
+ future_transfers = {
925
+ exists_executor .submit (
926
+ to_uri .transfer_from ,
927
+ from_uri ,
928
+ transfer = transfer ,
929
+ overwrite = overwrite ,
930
+ transaction = transaction ,
931
+ ): to_uri
932
+ for from_uri , to_uri in from_to
933
+ }
934
+ results : dict [ResourcePath , bool ] = {}
935
+ for future in concurrent .futures .as_completed (future_transfers ):
936
+ to_uri = future_transfers [future ]
937
+ transferred = True
938
+ try :
939
+ future .result ()
940
+ except Exception :
941
+ transferred = False
942
+ results [to_uri ] = transferred
943
+ return results
944
+
899
945
def remove (self ) -> None :
900
946
"""Remove the resource."""
901
947
raise NotImplementedError ()
0 commit comments