rclone-api 1.5.60__py3-none-any.whl → 1.5.63__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rclone_api/__init__.py +35 -35
- rclone_api/config.py +4 -2
- rclone_api/exec.py +1 -1
- rclone_api/process.py +7 -10
- rclone_api/rclone_impl.py +11 -7
- rclone_api/util.py +5 -5
- {rclone_api-1.5.60.dist-info → rclone_api-1.5.63.dist-info}/METADATA +1 -1
- {rclone_api-1.5.60.dist-info → rclone_api-1.5.63.dist-info}/RECORD +12 -12
- {rclone_api-1.5.60.dist-info → rclone_api-1.5.63.dist-info}/WHEEL +0 -0
- {rclone_api-1.5.60.dist-info → rclone_api-1.5.63.dist-info}/entry_points.txt +0 -0
- {rclone_api-1.5.60.dist-info → rclone_api-1.5.63.dist-info}/licenses/LICENSE +0 -0
- {rclone_api-1.5.60.dist-info → rclone_api-1.5.63.dist-info}/top_level.txt +0 -0
rclone_api/__init__.py
CHANGED
@@ -469,6 +469,41 @@ class Rclone:
|
|
469
469
|
"""
|
470
470
|
return self.impl.is_s3(dst=dst)
|
471
471
|
|
472
|
+
def copy_file_s3_resumable(
|
473
|
+
self,
|
474
|
+
src: str, # src:/Bucket/path/myfile.large.zst
|
475
|
+
dst: str, # dst:/Bucket/path/myfile.large.zst
|
476
|
+
part_infos: list[PartInfo] | None = None,
|
477
|
+
upload_threads: int = 8, # Number of reader and writer threads to use
|
478
|
+
merge_threads: int = 4, # Number of threads to use for merging the parts
|
479
|
+
) -> Exception | None:
|
480
|
+
"""
|
481
|
+
Copy a large file to S3 with resumable upload capability.
|
482
|
+
|
483
|
+
This method splits the file into parts for parallel upload and can
|
484
|
+
resume interrupted transfers using a custom algorithm in python.
|
485
|
+
|
486
|
+
Particularly useful for very large files where network interruptions
|
487
|
+
are likely.
|
488
|
+
|
489
|
+
Args:
|
490
|
+
src: Source file path (format: remote:bucket/path/file)
|
491
|
+
dst: Destination file path (format: remote:bucket/path/file)
|
492
|
+
part_infos: Optional list of part information for resuming uploads
|
493
|
+
upload_threads: Number of parallel upload threads
|
494
|
+
merge_threads: Number of threads for merging uploaded parts
|
495
|
+
|
496
|
+
Returns:
|
497
|
+
None if successful, Exception if an error occurred
|
498
|
+
"""
|
499
|
+
return self.impl.copy_file_s3_resumable(
|
500
|
+
src=src,
|
501
|
+
dst=dst,
|
502
|
+
part_infos=part_infos,
|
503
|
+
upload_threads=upload_threads,
|
504
|
+
merge_threads=merge_threads,
|
505
|
+
)
|
506
|
+
|
472
507
|
def copy_to(
|
473
508
|
self,
|
474
509
|
src: File | str,
|
@@ -831,41 +866,6 @@ class Rclone:
|
|
831
866
|
"""
|
832
867
|
return self.impl.copy_remote(src=src, dst=dst, args=args)
|
833
868
|
|
834
|
-
def copy_file_s3_resumable(
|
835
|
-
self,
|
836
|
-
src: str, # src:/Bucket/path/myfile.large.zst
|
837
|
-
dst: str, # dst:/Bucket/path/myfile.large.zst
|
838
|
-
part_infos: list[PartInfo] | None = None,
|
839
|
-
upload_threads: int = 8, # Number of reader and writer threads to use
|
840
|
-
merge_threads: int = 4, # Number of threads to use for merging the parts
|
841
|
-
) -> Exception | None:
|
842
|
-
"""
|
843
|
-
Copy a large file to S3 with resumable upload capability.
|
844
|
-
|
845
|
-
This method splits the file into parts for parallel upload and can
|
846
|
-
resume interrupted transfers using a custom algorithm in python.
|
847
|
-
|
848
|
-
Particularly useful for very large files where network interruptions
|
849
|
-
are likely.
|
850
|
-
|
851
|
-
Args:
|
852
|
-
src: Source file path (format: remote:bucket/path/file)
|
853
|
-
dst: Destination file path (format: remote:bucket/path/file)
|
854
|
-
part_infos: Optional list of part information for resuming uploads
|
855
|
-
upload_threads: Number of parallel upload threads
|
856
|
-
merge_threads: Number of threads for merging uploaded parts
|
857
|
-
|
858
|
-
Returns:
|
859
|
-
None if successful, Exception if an error occurred
|
860
|
-
"""
|
861
|
-
return self.impl.copy_file_s3_resumable(
|
862
|
-
src=src,
|
863
|
-
dst=dst,
|
864
|
-
part_infos=part_infos,
|
865
|
-
upload_threads=upload_threads,
|
866
|
-
merge_threads=merge_threads,
|
867
|
-
)
|
868
|
-
|
869
869
|
def mount(
|
870
870
|
self,
|
871
871
|
src: Remote | Dir | str,
|
rclone_api/config.py
CHANGED
@@ -52,9 +52,11 @@ class Config:
|
|
52
52
|
"""Rclone configuration dataclass."""
|
53
53
|
|
54
54
|
# text: str
|
55
|
-
def __init__(self, text: str | dict) -> None:
|
55
|
+
def __init__(self, text: str | dict | None) -> None:
|
56
56
|
self.text: str
|
57
|
-
if
|
57
|
+
if text is None:
|
58
|
+
self.text = ""
|
59
|
+
elif isinstance(text, dict):
|
58
60
|
self.text = _json_to_rclone_config_str_or_raise(text)
|
59
61
|
else:
|
60
62
|
self.text = text
|
rclone_api/exec.py
CHANGED
rclone_api/process.py
CHANGED
@@ -15,7 +15,7 @@ from rclone_api.util import clear_temp_config_file, get_verbose, make_temp_confi
|
|
15
15
|
@dataclass
|
16
16
|
class ProcessArgs:
|
17
17
|
cmd: list[str]
|
18
|
-
rclone_conf: Path | Config
|
18
|
+
rclone_conf: Path | Config | None
|
19
19
|
rclone_exe: Path
|
20
20
|
cmd_list: list[str]
|
21
21
|
verbose: bool | None = None
|
@@ -32,7 +32,7 @@ class Process:
|
|
32
32
|
self.log = args.log
|
33
33
|
self.cleaned_up = False
|
34
34
|
self.tempfile: Path | None = None
|
35
|
-
|
35
|
+
rclone_conf: Path | None = None
|
36
36
|
verbose = get_verbose(args.verbose)
|
37
37
|
# Create a temporary config file if needed.
|
38
38
|
if isinstance(args.rclone_conf, Config):
|
@@ -41,15 +41,12 @@ class Process:
|
|
41
41
|
rclone_conf = self.tempfile
|
42
42
|
else:
|
43
43
|
rclone_conf = args.rclone_conf
|
44
|
-
|
45
|
-
assert rclone_conf.exists(), f"rclone config not found: {rclone_conf}"
|
46
|
-
|
44
|
+
# assert rclone_conf.exists(), f"rclone config not found: {rclone_conf}"
|
47
45
|
# Build the command.
|
48
|
-
self.cmd = (
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
)
|
46
|
+
self.cmd = [str(args.rclone_exe.resolve())]
|
47
|
+
if rclone_conf:
|
48
|
+
self.cmd += ["--config", str(rclone_conf.resolve())]
|
49
|
+
self.cmd += args.cmd_list
|
53
50
|
if self.args.log:
|
54
51
|
self.args.log.parent.mkdir(parents=True, exist_ok=True)
|
55
52
|
self.cmd += ["--log-file", str(self.args.log)]
|
rclone_api/rclone_impl.py
CHANGED
@@ -67,8 +67,10 @@ def rclone_verbose(verbose: bool | None) -> bool:
|
|
67
67
|
return bool(int(os.getenv("RCLONE_API_VERBOSE", "0")))
|
68
68
|
|
69
69
|
|
70
|
-
def _to_rclone_conf(config: Config | Path) -> Config:
|
71
|
-
if
|
70
|
+
def _to_rclone_conf(config: Config | Path | None) -> Config:
|
71
|
+
if config is None:
|
72
|
+
return Config(None)
|
73
|
+
elif isinstance(config, Path):
|
72
74
|
content = config.read_text(encoding="utf-8")
|
73
75
|
return Config(content)
|
74
76
|
else:
|
@@ -100,13 +102,17 @@ class RcloneImpl:
|
|
100
102
|
if isinstance(rclone_conf, Path):
|
101
103
|
if not rclone_conf.exists():
|
102
104
|
raise ValueError(f"Rclone config file not found: {rclone_conf}")
|
105
|
+
rclone_exe = get_rclone_exe(rclone_exe)
|
106
|
+
# Not fully constructed version of ._exec, which can be used to find a config file from default paths.
|
107
|
+
self._exec = RcloneExec(None, get_rclone_exe(rclone_exe))
|
103
108
|
if rclone_conf is None:
|
104
109
|
from rclone_api.config import find_conf_file
|
105
110
|
|
106
111
|
maybe_path = find_conf_file(self)
|
107
112
|
if not isinstance(maybe_path, Path):
|
108
|
-
|
113
|
+
warnings.warn("Rclone config file not found")
|
109
114
|
rclone_conf = _to_rclone_conf(maybe_path)
|
115
|
+
# replace self._exec with one that has the config
|
110
116
|
self._exec = RcloneExec(rclone_conf, get_rclone_exe(rclone_exe))
|
111
117
|
self.config: Config = _to_rclone_conf(rclone_conf)
|
112
118
|
|
@@ -1334,9 +1340,6 @@ class RcloneImpl:
|
|
1334
1340
|
if obscure:
|
1335
1341
|
cmd_list.append("--obscure")
|
1336
1342
|
|
1337
|
-
if no_obscure:
|
1338
|
-
cmd_list.append("--no-obscure")
|
1339
|
-
|
1340
1343
|
try:
|
1341
1344
|
cp = self._run(cmd_list, capture=True, check=True)
|
1342
1345
|
stdout: str | bytes = cp.stdout
|
@@ -1360,7 +1363,8 @@ class RcloneImpl:
|
|
1360
1363
|
verbose = get_verbose(verbose)
|
1361
1364
|
check = get_check(check)
|
1362
1365
|
if len(files) < 2:
|
1363
|
-
|
1366
|
+
full_path = f"{src}/{files[0]}"
|
1367
|
+
tmp = self.size_file(full_path)
|
1364
1368
|
if isinstance(tmp, Exception):
|
1365
1369
|
return tmp
|
1366
1370
|
assert isinstance(tmp, SizeSuffix)
|
rclone_api/util.py
CHANGED
@@ -178,7 +178,7 @@ def upgrade_rclone() -> Path:
|
|
178
178
|
|
179
179
|
def rclone_execute(
|
180
180
|
cmd: list[str],
|
181
|
-
rclone_conf: Path | Config,
|
181
|
+
rclone_conf: Path | Config | None,
|
182
182
|
rclone_exe: Path,
|
183
183
|
check: bool,
|
184
184
|
capture: bool | Path | None = None,
|
@@ -202,10 +202,10 @@ def rclone_execute(
|
|
202
202
|
tmpfile.write_text(rclone_conf.text, encoding="utf-8")
|
203
203
|
rclone_conf = tmpfile
|
204
204
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
205
|
+
full_cmd = [str(rclone_exe.resolve())]
|
206
|
+
if rclone_conf:
|
207
|
+
full_cmd += ["--config", str(rclone_conf.resolve())]
|
208
|
+
full_cmd += cmd
|
209
209
|
if verbose:
|
210
210
|
cmd_str = subprocess.list2cmdline(full_cmd)
|
211
211
|
print(f"\nRunning: {cmd_str}")
|
@@ -1,13 +1,13 @@
|
|
1
|
-
rclone_api/__init__.py,sha256=
|
1
|
+
rclone_api/__init__.py,sha256=gIONLifrNkReIlQkpJOk3TTueJ9jrJ2ZdM2scQSUvSY,34885
|
2
2
|
rclone_api/cli.py,sha256=dibfAZIh0kXWsBbfp3onKLjyZXo54mTzDjUdzJlDlWo,231
|
3
3
|
rclone_api/completed_process.py,sha256=_IZ8IWK7DM1_tsbDEkH6wPZ-bbcrgf7A7smls854pmg,1775
|
4
|
-
rclone_api/config.py,sha256=
|
4
|
+
rclone_api/config.py,sha256=URZwMME01f0EZymprCESuZ5dk4IuUSKbHhwIeTHrn7A,6131
|
5
5
|
rclone_api/convert.py,sha256=Mx9Qo7zhkOedJd8LdhPvNGHp8znJzOk4f_2KWnoGc78,1012
|
6
6
|
rclone_api/deprecated.py,sha256=qWKpnZdYcBK7YQZKuVoWWXDwi-uqiAtbjgPcci_efow,590
|
7
7
|
rclone_api/diff.py,sha256=tMoJMAGmLSE6Q_7QhPf6PnCzb840djxMZtDmhc2GlGQ,5227
|
8
8
|
rclone_api/dir.py,sha256=_9o-_5tbWVJkL1Vf_Yb8aiQV3xAqvUq5bk3zoJblvEg,3547
|
9
9
|
rclone_api/dir_listing.py,sha256=bSmd8yZtSeyVaDRw2JPB4bCpbCeDzhoa_pomgdJp44c,1884
|
10
|
-
rclone_api/exec.py,sha256=
|
10
|
+
rclone_api/exec.py,sha256=3x2FOrh_3Ml23sW_5fry3dmlKyHtq3iYKByLeZtbNcg,1090
|
11
11
|
rclone_api/file.py,sha256=JLPqjUcW_YVb4UQjX6FQ7PABJqhchFUXVy1W-X9rJLk,5659
|
12
12
|
rclone_api/file_item.py,sha256=cH-AQYsxedhNPp4c8NHY1ad4Z7St4yf_VGbmiGD59no,1770
|
13
13
|
rclone_api/file_part.py,sha256=i6ByS5_sae8Eba-4imBVTxd-xKC8ExWy7NR8QGr0ors,6155
|
@@ -19,13 +19,13 @@ rclone_api/install.py,sha256=ZDG8QNj1JciS_DSqYnMTECwhJksUPAoqZQxtX804TDk,5679
|
|
19
19
|
rclone_api/log.py,sha256=VZHM7pNSXip2ZLBKMP7M1u-rp_F7zoafFDuR8CPUoKI,1271
|
20
20
|
rclone_api/mount.py,sha256=LZqEhuKZunbWVqmsOIqkkCotaxWJpdFRS1InXveoU5E,1428
|
21
21
|
rclone_api/mount_util.py,sha256=jqhJEVTHV6c6lOOzUYb4FLMbqDMHdz7-QRcdH-IobFc,10154
|
22
|
-
rclone_api/process.py,sha256=
|
23
|
-
rclone_api/rclone_impl.py,sha256=
|
22
|
+
rclone_api/process.py,sha256=V4Ax9AyNdC3m4O6gjWSbIJyCQCMhT-t0f-K8z6xux7Q,5946
|
23
|
+
rclone_api/rclone_impl.py,sha256=PppFWk4qo7gg6p_k3K7am3_6pytsLG6qTAKo6dBT-tI,52649
|
24
24
|
rclone_api/remote.py,sha256=mTgMTQTwxUmbLjTpr-AGTId2ycXKI9mLX5L7PPpDIoc,520
|
25
25
|
rclone_api/rpath.py,sha256=Y1JjQWcie39EgQrq-UtbfDz5yDLCwwfu27W7AQXllSE,2860
|
26
26
|
rclone_api/scan_missing_folders.py,sha256=-8NCwpCaHeHrX-IepCoAEsX1rl8S-GOCxcIhTr_w3gA,4747
|
27
27
|
rclone_api/types.py,sha256=59Rw7NdHw35X6iiWMemO61IzCbrjgfNHUlzY3Dq0wdM,12303
|
28
|
-
rclone_api/util.py,sha256=
|
28
|
+
rclone_api/util.py,sha256=NIWU1YLGWyNhICwXCpmAw0AgCXkOYG6BO6m1mTNQwzY,9559
|
29
29
|
rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
|
30
30
|
rclone_api/cmd/analyze.py,sha256=RHbvk1G5ZUc3qLqlm1AZEyQzd_W_ZjcbCNDvW4YpTKQ,1252
|
31
31
|
rclone_api/cmd/copy_large_s3.py,sha256=E0B7P-JJTuOM7wMZtwQHJCpoLhccJleh0mnMq8ZiSUo,3234
|
@@ -58,9 +58,9 @@ rclone_api/s3/multipart/upload_parts_inline.py,sha256=V7syKjFyVIe4U9Ahl5XgqVTzt9
|
|
58
58
|
rclone_api/s3/multipart/upload_parts_resumable.py,sha256=6-nlMclS8jyVvMvFbQDcZOX9MY1WbCcKA_s9bwuYxnk,9793
|
59
59
|
rclone_api/s3/multipart/upload_parts_server_side_merge.py,sha256=Fp2pdrs5dONQI9LkfNolgAGj1-Z2V1SsRd0r0sreuXI,18040
|
60
60
|
rclone_api/s3/multipart/upload_state.py,sha256=f-Aq2NqtAaMUMhYitlICSNIxCKurWAl2gDEUVizLIqw,6019
|
61
|
-
rclone_api-1.5.
|
62
|
-
rclone_api-1.5.
|
63
|
-
rclone_api-1.5.
|
64
|
-
rclone_api-1.5.
|
65
|
-
rclone_api-1.5.
|
66
|
-
rclone_api-1.5.
|
61
|
+
rclone_api-1.5.63.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
62
|
+
rclone_api-1.5.63.dist-info/METADATA,sha256=9XSnDbl63rF0hMxexBm7t65FmtxbjMyNiIURw5ixrxo,37305
|
63
|
+
rclone_api-1.5.63.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
64
|
+
rclone_api-1.5.63.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
|
65
|
+
rclone_api-1.5.63.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
|
66
|
+
rclone_api-1.5.63.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|