rclone-api 1.0.39__py2.py3-none-any.whl → 1.0.41__py2.py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
rclone_api/rclone.py CHANGED
@@ -5,6 +5,7 @@ Unit test file.
5
5
  import subprocess
6
6
  import time
7
7
  import warnings
8
+ from concurrent.futures import Future, ThreadPoolExecutor
8
9
  from enum import Enum
9
10
  from fnmatch import fnmatch
10
11
  from pathlib import Path
@@ -23,9 +24,17 @@ from rclone_api.file import File
23
24
  from rclone_api.process import Process
24
25
  from rclone_api.remote import Remote
25
26
  from rclone_api.rpath import RPath
26
- from rclone_api.util import get_rclone_exe, partition_files, to_path, wait_for_mount
27
+ from rclone_api.util import (
28
+ get_rclone_exe,
29
+ get_verbose,
30
+ partition_files,
31
+ to_path,
32
+ wait_for_mount,
33
+ )
27
34
  from rclone_api.walk import walk
28
35
 
36
+ EXECUTOR = ThreadPoolExecutor(16)
37
+
29
38
 
30
39
  class ModTimeStrategy(Enum):
31
40
  USE_SERVER_MODTIME = "use-server-modtime"
@@ -197,7 +206,7 @@ class Rclone:
197
206
  cmd_list: list[str] = ["copyto", src, dst]
198
207
  self._run(cmd_list)
199
208
 
200
- def copyfiles(self, files: str | File | list[str] | list[File]) -> None:
209
+ def copyfiles(self, files: str | File | list[str] | list[File], check=True) -> None:
201
210
  """Copy multiple files from source to destination.
202
211
 
203
212
  Warning - slow.
@@ -212,28 +221,39 @@ class Rclone:
212
221
  datalists: dict[str, list[str]] = partition_files(payload)
213
222
  out: subprocess.CompletedProcess | None = None
214
223
 
224
+ futures: list[Future] = []
225
+
215
226
  for remote, files in datalists.items():
216
- with TemporaryDirectory() as tmpdir:
217
- include_files_txt = Path(tmpdir) / "include_files.txt"
218
- include_files_txt.write_text("\n".join(files), encoding="utf-8")
219
-
220
- # print(include_files_txt)
221
- cmd_list: list[str] = [
222
- "delete",
223
- remote,
224
- "--files-from",
225
- str(include_files_txt),
226
- "--checkers",
227
- "1000",
228
- "--transfers",
229
- "1000",
230
- ]
231
- out = self._run(cmd_list)
232
- if out.returncode != 0:
233
- print(out)
234
- raise ValueError(f"Error deleting files: {out.stderr}")
235
227
 
236
- assert out is not None
228
+ def _task(files=files) -> subprocess.CompletedProcess:
229
+ with TemporaryDirectory() as tmpdir:
230
+ include_files_txt = Path(tmpdir) / "include_files.txt"
231
+ include_files_txt.write_text("\n".join(files), encoding="utf-8")
232
+
233
+ # print(include_files_txt)
234
+ cmd_list: list[str] = [
235
+ "delete",
236
+ remote,
237
+ "--files-from",
238
+ str(include_files_txt),
239
+ "--checkers",
240
+ "1000",
241
+ "--transfers",
242
+ "1000",
243
+ ]
244
+ out = self._run(cmd_list)
245
+ return out
246
+
247
+ fut: Future = EXECUTOR.submit(_task)
248
+ futures.append(fut)
249
+ for fut in futures:
250
+ out = fut.result()
251
+ assert out is not None
252
+ if out.returncode != 0:
253
+ if check:
254
+ raise ValueError(f"Error deleting files: {out.stderr}")
255
+ else:
256
+ warnings.warn(f"Error deleting files: {out.stderr}")
237
257
 
238
258
  def copy(self, src: Dir | str, dst: Dir | str) -> CompletedProcess:
239
259
  """Copy files from source to destination.
@@ -263,6 +283,7 @@ class Rclone:
263
283
  files: str | File | list[str] | list[File],
264
284
  check=True,
265
285
  rmdirs=False,
286
+ verbose: bool | None = None,
266
287
  other_args: list[str] | None = None,
267
288
  ) -> CompletedProcess:
268
289
  """Delete a directory"""
@@ -277,40 +298,52 @@ class Rclone:
277
298
  return CompletedProcess.from_subprocess(cp)
278
299
 
279
300
  datalists: dict[str, list[str]] = partition_files(payload)
280
- out: subprocess.CompletedProcess | None = None
281
-
282
301
  completed_processes: list[subprocess.CompletedProcess] = []
302
+ verbose = get_verbose(verbose)
303
+
304
+ futures: list[Future] = []
283
305
 
284
306
  for remote, files in datalists.items():
285
- with TemporaryDirectory() as tmpdir:
286
- include_files_txt = Path(tmpdir) / "include_files.txt"
287
- include_files_txt.write_text("\n".join(files), encoding="utf-8")
288
-
289
- # print(include_files_txt)
290
- cmd_list: list[str] = [
291
- "delete",
292
- remote,
293
- "--files-from",
294
- str(include_files_txt),
295
- "--checkers",
296
- "1000",
297
- "--transfers",
298
- "1000",
299
- ]
300
- if rmdirs:
301
- cmd_list.append("--rmdirs")
302
- if other_args:
303
- cmd_list += other_args
304
- out = self._run(cmd_list)
305
- completed_processes.append(out)
307
+
308
+ def _task(files=files, check=check) -> subprocess.CompletedProcess:
309
+ with TemporaryDirectory() as tmpdir:
310
+ include_files_txt = Path(tmpdir) / "include_files.txt"
311
+ include_files_txt.write_text("\n".join(files), encoding="utf-8")
312
+
313
+ # print(include_files_txt)
314
+ cmd_list: list[str] = [
315
+ "delete",
316
+ remote,
317
+ "--files-from",
318
+ str(include_files_txt),
319
+ "--checkers",
320
+ "1000",
321
+ "--transfers",
322
+ "1000",
323
+ ]
324
+ if verbose:
325
+ cmd_list.append("-vvvv")
326
+ if rmdirs:
327
+ cmd_list.append("--rmdirs")
328
+ if other_args:
329
+ cmd_list += other_args
330
+ out = self._run(cmd_list, check=check)
306
331
  if out.returncode != 0:
307
332
  if check:
308
333
  completed_processes.append(out)
309
334
  raise ValueError(f"Error deleting files: {out}")
310
335
  else:
311
336
  warnings.warn(f"Error deleting files: {out}")
337
+ return out
338
+
339
+ fut: Future = EXECUTOR.submit(_task)
340
+ futures.append(fut)
341
+
342
+ for fut in futures:
343
+ out = fut.result()
344
+ assert out is not None
345
+ completed_processes.append(out)
312
346
 
313
- assert out is not None
314
347
  return CompletedProcess(completed_processes)
315
348
 
316
349
  @deprecated("delete_files")
rclone_api/util.py CHANGED
@@ -132,15 +132,12 @@ def wait_for_mount(path: Path, mount_process: Any, timeout: int = 60) -> None:
132
132
 
133
133
 
134
134
  def partition_files(files: list[str]) -> dict[str, list[str]]:
135
+ """split between filename and parent directory path"""
135
136
  datalists: dict[str, list[str]] = {}
136
137
  for f in files:
137
- remote, path = f.split(":", 1)
138
- if "/" in path:
139
- bucket, path = path.split("/", 1)
140
- remote = f"{remote}:{bucket}"
141
- else:
142
- remote = f"{remote}:"
143
- if remote not in datalists:
144
- datalists[remote] = []
145
- datalists[remote].append(path)
138
+ base = os.path.basename(f)
139
+ parent_path = os.path.dirname(f)
140
+ if parent_path not in datalists:
141
+ datalists[parent_path] = []
142
+ datalists[parent_path].append(base)
146
143
  return datalists
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.39
3
+ Version: 1.0.41
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  Maintainer: Zachary Vorhies
@@ -11,16 +11,16 @@ rclone_api/exec.py,sha256=HWmnU2Jwb-3EttSbAJSaLloYA7YI2mHTzRJ5VEri9aM,941
11
11
  rclone_api/file.py,sha256=D02iHJW1LhfOiM_R_yPHP8_ApnDiYrkuraVcrV8-qkw,1246
12
12
  rclone_api/filelist.py,sha256=xbiusvNgaB_b_kQOZoHMJJxn6TWGtPrWd2J042BI28o,767
13
13
  rclone_api/process.py,sha256=RrMfTe0bndmJ6gBK67ioqNvCstJ8aTC8RlGX1XBLlcw,4191
14
- rclone_api/rclone.py,sha256=dU2MEiMXC6l_QrvnWkSFpJ0sC7xyyNXCIlhEAzw2puA,19909
14
+ rclone_api/rclone.py,sha256=hPR1dV4s-ekruVBbLHpojNvNLreJVdm3tWVOHsSDh2c,20986
15
15
  rclone_api/remote.py,sha256=c9hlRKBCg1BFB9MCINaQIoCg10qyAkeqiS4brl8ce-8,343
16
16
  rclone_api/rpath.py,sha256=8ZA_1wxWtskwcy0I8V2VbjKDmzPkiWd8Q2JQSvh-sYE,2586
17
- rclone_api/util.py,sha256=N1n2Fxt-pU_xKwQdwXM3zAThBHG0zwDQY30s0iQao-0,4374
17
+ rclone_api/util.py,sha256=yUN7afH4PuuUNcrXwdtyDTIluvkNOw-c5v5VPKDXoBM,4325
18
18
  rclone_api/walk.py,sha256=kca0t1GAnF6FLclN01G8NG__Qe-ggodLtAbQSHyVPng,2968
19
19
  rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
20
20
  rclone_api/cmd/list_files.py,sha256=x8FHODEilwKqwdiU1jdkeJbLwOqUkUQuDWPo2u_zpf0,741
21
- rclone_api-1.0.39.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
22
- rclone_api-1.0.39.dist-info/METADATA,sha256=2qM0byVfg7Cj6Rh5uSfYPUyQiv8QNUWMj2j44tS5GX4,4489
23
- rclone_api-1.0.39.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
24
- rclone_api-1.0.39.dist-info/entry_points.txt,sha256=XUoTX3m7CWxdj2VAKhEuO0NMOfX2qf-OcEDFwdyk9ZE,72
25
- rclone_api-1.0.39.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
26
- rclone_api-1.0.39.dist-info/RECORD,,
21
+ rclone_api-1.0.41.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
22
+ rclone_api-1.0.41.dist-info/METADATA,sha256=GnbL4D29d2oXbfexuymEQT9P1-PVEQJtoxxAd8YCa3A,4489
23
+ rclone_api-1.0.41.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
24
+ rclone_api-1.0.41.dist-info/entry_points.txt,sha256=XUoTX3m7CWxdj2VAKhEuO0NMOfX2qf-OcEDFwdyk9ZE,72
25
+ rclone_api-1.0.41.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
26
+ rclone_api-1.0.41.dist-info/RECORD,,