rclone-api 1.1.43__tar.gz → 1.1.45__tar.gz
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-1.1.43 → rclone_api-1.1.45}/PKG-INFO +1 -1
- {rclone_api-1.1.43 → rclone_api-1.1.45}/pyproject.toml +1 -1
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/mount.py +7 -1
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/profile/mount_copy_bytes.py +15 -5
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/rclone.py +10 -5
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/s3/chunk_file.py +12 -1
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/s3/upload_file_multipart.py +27 -17
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api.egg-info/PKG-INFO +1 -1
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.aiderignore +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.github/workflows/lint.yml +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.github/workflows/push_macos.yml +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.github/workflows/push_ubuntu.yml +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.github/workflows/push_win.yml +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.gitignore +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.pylintrc +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.vscode/launch.json +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.vscode/settings.json +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/.vscode/tasks.json +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/LICENSE +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/MANIFEST.in +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/README.md +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/clean +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/install +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/lint +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/requirements.testing.txt +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/setup.cfg +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/setup.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/__init__.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/assets/example.txt +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/cli.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/cmd/copy_large_s3.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/cmd/list_files.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/completed_process.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/config.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/convert.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/deprecated.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/diff.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/dir.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/dir_listing.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/exec.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/experimental/flags.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/experimental/flags_base.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/file.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/filelist.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/group_files.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/process.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/remote.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/rpath.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/s3/api.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/s3/basic_ops.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/s3/chunk_types.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/s3/create.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/s3/types.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/scan_missing_folders.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/types.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/util.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api/walk.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api.egg-info/SOURCES.txt +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api.egg-info/dependency_links.txt +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api.egg-info/entry_points.txt +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api.egg-info/requires.txt +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/src/rclone_api.egg-info/top_level.txt +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/test +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/archive/test_paramiko.py.disabled +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_cmd_list_files.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_copy.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_copy_bytes.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_copy_file_resumable_s3.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_copy_files.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_diff.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_group_files.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_is_synced.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_ls.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_mount.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_mount_s3.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_obscure.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_rclone_config.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_remote_control.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_remotes.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_s3.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_scan_missing_folders.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_size_files.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_size_suffix.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tests/test_walk.py +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/tox.ini +0 -0
- {rclone_api-1.1.43 → rclone_api-1.1.45}/upload_package.sh +0 -0
|
@@ -31,7 +31,13 @@ class Mount:
|
|
|
31
31
|
if self._closed:
|
|
32
32
|
return
|
|
33
33
|
self._closed = True
|
|
34
|
-
clean_mount(self, verbose=False)
|
|
34
|
+
clean_mount(self, verbose=False, wait=wait)
|
|
35
|
+
|
|
36
|
+
def __enter__(self) -> "Mount":
|
|
37
|
+
return self
|
|
38
|
+
|
|
39
|
+
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
|
40
|
+
self.close(wait=True)
|
|
35
41
|
|
|
36
42
|
def __del__(self):
|
|
37
43
|
self.close(wait=False)
|
|
@@ -3,6 +3,7 @@ Unit test file.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
+
import shutil
|
|
6
7
|
import time
|
|
7
8
|
from dataclasses import dataclass
|
|
8
9
|
from pathlib import Path
|
|
@@ -103,10 +104,11 @@ def _init() -> None:
|
|
|
103
104
|
os.environ["RCLONE_API_VERBOSE"] = "1"
|
|
104
105
|
|
|
105
106
|
|
|
106
|
-
def _run_profile(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
def _run_profile(
|
|
108
|
+
rclone: Rclone, src_file: str, transfers: int, size: int, log_dir: Path
|
|
109
|
+
) -> None:
|
|
110
|
+
|
|
111
|
+
mount_log = log_dir / f"mount_{SizeSuffix(size)}_threads_{transfers}.log"
|
|
110
112
|
print("\n\n")
|
|
111
113
|
print("#" * 80)
|
|
112
114
|
print(f"# Started test download of {SizeSuffix(size)} with {transfers} transfers")
|
|
@@ -177,10 +179,18 @@ def test_profile_copy_bytes() -> None:
|
|
|
177
179
|
# sftp mount
|
|
178
180
|
src_file = "src:aa_misc_data/aa_misc_data/world_lending_library_2024_11.tar.zst"
|
|
179
181
|
|
|
182
|
+
mount_root_path = Path("logs") / "mount"
|
|
183
|
+
if mount_root_path.exists():
|
|
184
|
+
shutil.rmtree(mount_root_path)
|
|
185
|
+
|
|
180
186
|
for size in sizes:
|
|
181
187
|
for transfers in transfer_list:
|
|
182
188
|
_run_profile(
|
|
183
|
-
rclone=rclone,
|
|
189
|
+
rclone=rclone,
|
|
190
|
+
src_file=src_file,
|
|
191
|
+
transfers=transfers,
|
|
192
|
+
size=size,
|
|
193
|
+
log_dir=mount_root_path,
|
|
184
194
|
)
|
|
185
195
|
print("done")
|
|
186
196
|
|
|
@@ -832,7 +832,10 @@ class Rclone:
|
|
|
832
832
|
tmp_mnt = Path("tmp_mnt") / random_str(12)
|
|
833
833
|
src_parent_path = Path(src).parent.as_posix()
|
|
834
834
|
src_file = Path(src).name
|
|
835
|
-
other_args: list[str] = [
|
|
835
|
+
other_args: list[str] = [
|
|
836
|
+
"--no-modtime",
|
|
837
|
+
# "--vfs-read-wait", "1s"
|
|
838
|
+
]
|
|
836
839
|
vfs_read_chunk_size = SizeSuffix(length // transfers)
|
|
837
840
|
vfs_read_chunk_size_limit = SizeSuffix(length)
|
|
838
841
|
vfs_read_chunk_streams = transfers
|
|
@@ -924,10 +927,11 @@ class Rclone:
|
|
|
924
927
|
|
|
925
928
|
allow_writes = allow_writes or False
|
|
926
929
|
use_links = use_links or True
|
|
927
|
-
verbose = get_verbose(verbose)
|
|
930
|
+
verbose = get_verbose(verbose) or (log is not None)
|
|
928
931
|
vfs_cache_mode = vfs_cache_mode or "full"
|
|
929
932
|
clean_mount(outdir, verbose=verbose)
|
|
930
933
|
prepare_mount(outdir, verbose=verbose)
|
|
934
|
+
debug_fuse = log is not None
|
|
931
935
|
src_str = convert_to_str(src)
|
|
932
936
|
cmd_list: list[str] = ["mount", src_str, str(outdir)]
|
|
933
937
|
if not allow_writes:
|
|
@@ -937,12 +941,14 @@ class Rclone:
|
|
|
937
941
|
if vfs_cache_mode:
|
|
938
942
|
cmd_list.append("--vfs-cache-mode")
|
|
939
943
|
cmd_list.append(vfs_cache_mode)
|
|
944
|
+
if debug_fuse:
|
|
945
|
+
cmd_list.append("--debug-fuse")
|
|
940
946
|
if verbose:
|
|
941
947
|
cmd_list.append("-vvvv")
|
|
942
948
|
if other_args:
|
|
943
949
|
cmd_list += other_args
|
|
944
950
|
proc = self._launch_process(cmd_list, log=log)
|
|
945
|
-
mount_read_only =
|
|
951
|
+
mount_read_only = not allow_writes
|
|
946
952
|
mount: Mount = Mount(mount_path=outdir, process=proc, read_only=mount_read_only)
|
|
947
953
|
return mount
|
|
948
954
|
|
|
@@ -960,7 +966,6 @@ class Rclone:
|
|
|
960
966
|
) -> Generator[Mount, None, None]:
|
|
961
967
|
"""Like mount, but can be used in a context manager."""
|
|
962
968
|
error_happened = False
|
|
963
|
-
verbose = get_verbose(verbose)
|
|
964
969
|
mount: Mount = self.mount(
|
|
965
970
|
src,
|
|
966
971
|
outdir,
|
|
@@ -979,7 +984,7 @@ class Rclone:
|
|
|
979
984
|
warnings.warn(f"Error in scoped_mount: {e}\n\nStack Trace:\n{stack_trace}")
|
|
980
985
|
raise
|
|
981
986
|
finally:
|
|
982
|
-
if not error_happened:
|
|
987
|
+
if not error_happened or (not allow_writes):
|
|
983
988
|
mount.close()
|
|
984
989
|
|
|
985
990
|
# Settings optimized for s3.
|
|
@@ -2,6 +2,7 @@ import time
|
|
|
2
2
|
import warnings
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from queue import Queue
|
|
5
|
+
from threading import Event
|
|
5
6
|
|
|
6
7
|
from rclone_api.s3.chunk_types import FileChunk, UploadState
|
|
7
8
|
from rclone_api.util import locked_print
|
|
@@ -25,12 +26,16 @@ def _get_file_size(file_path: Path, timeout: int = 60) -> int:
|
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
def file_chunker(
|
|
28
|
-
upload_state: UploadState,
|
|
29
|
+
upload_state: UploadState,
|
|
30
|
+
max_chunks: int | None,
|
|
31
|
+
cancel_signal: Event,
|
|
32
|
+
output: Queue[FileChunk | None],
|
|
29
33
|
) -> None:
|
|
30
34
|
count = 0
|
|
31
35
|
|
|
32
36
|
def should_stop() -> bool:
|
|
33
37
|
nonlocal count
|
|
38
|
+
|
|
34
39
|
if max_chunks is None:
|
|
35
40
|
return False
|
|
36
41
|
if count >= max_chunks:
|
|
@@ -68,6 +73,12 @@ def file_chunker(
|
|
|
68
73
|
return None
|
|
69
74
|
return part_number
|
|
70
75
|
|
|
76
|
+
if cancel_signal.is_set():
|
|
77
|
+
print(
|
|
78
|
+
f"Cancel signal is set for file chunker while processing {file_path}, returning"
|
|
79
|
+
)
|
|
80
|
+
return
|
|
81
|
+
|
|
71
82
|
while not should_stop():
|
|
72
83
|
curr_parth_num = next_part_number()
|
|
73
84
|
if curr_parth_num is None:
|
|
@@ -5,7 +5,7 @@ import warnings
|
|
|
5
5
|
from concurrent.futures import ThreadPoolExecutor
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from queue import Queue
|
|
8
|
-
from threading import Thread
|
|
8
|
+
from threading import Event, Thread
|
|
9
9
|
|
|
10
10
|
from botocore.client import BaseClient
|
|
11
11
|
|
|
@@ -207,16 +207,21 @@ def upload_file_multipart(
|
|
|
207
207
|
upload_info = upload_state.upload_info
|
|
208
208
|
|
|
209
209
|
chunker_errors: Queue[Exception] = Queue()
|
|
210
|
+
cancel_chunker_event = Event()
|
|
210
211
|
|
|
211
212
|
def chunker_task(
|
|
212
213
|
upload_state=upload_state,
|
|
213
214
|
output=filechunks,
|
|
214
215
|
max_chunks=max_chunks_before_suspension,
|
|
216
|
+
cancel_signal=cancel_chunker_event,
|
|
215
217
|
queue_errors=chunker_errors,
|
|
216
218
|
) -> None:
|
|
217
219
|
try:
|
|
218
220
|
file_chunker(
|
|
219
|
-
upload_state=upload_state,
|
|
221
|
+
upload_state=upload_state,
|
|
222
|
+
output=output,
|
|
223
|
+
max_chunks=max_chunks,
|
|
224
|
+
cancel_signal=cancel_signal,
|
|
220
225
|
)
|
|
221
226
|
except Exception as e:
|
|
222
227
|
queue_errors.put(e)
|
|
@@ -228,25 +233,30 @@ def upload_file_multipart(
|
|
|
228
233
|
thread_chunker.start()
|
|
229
234
|
|
|
230
235
|
with ThreadPoolExecutor(max_workers=upload_threads) as executor:
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
236
|
+
try:
|
|
237
|
+
while True:
|
|
238
|
+
file_chunk: FileChunk | None = filechunks.get()
|
|
239
|
+
if file_chunk is None:
|
|
240
|
+
break
|
|
235
241
|
|
|
236
|
-
|
|
237
|
-
|
|
242
|
+
def task(upload_info=upload_info, file_chunk=file_chunk):
|
|
243
|
+
return handle_upload(upload_info, file_chunk)
|
|
238
244
|
|
|
239
|
-
|
|
245
|
+
fut = executor.submit(task)
|
|
240
246
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
247
|
+
def done_cb(fut=fut):
|
|
248
|
+
result = fut.result()
|
|
249
|
+
if isinstance(result, Exception):
|
|
250
|
+
warnings.warn(f"Error uploading part: {result}, skipping")
|
|
251
|
+
return
|
|
252
|
+
# upload_state.finished_parts.put(result)
|
|
253
|
+
upload_state.add_finished(result)
|
|
248
254
|
|
|
249
|
-
|
|
255
|
+
fut.add_done_callback(done_cb)
|
|
256
|
+
except Exception:
|
|
257
|
+
cancel_chunker_event.set()
|
|
258
|
+
executor.shutdown(wait=False, cancel_futures=True)
|
|
259
|
+
raise
|
|
250
260
|
# upload_state.finished_parts.put(None) # Signal the end of the queue
|
|
251
261
|
upload_state.add_finished(None)
|
|
252
262
|
thread_chunker.join()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|