rclone-api 1.1.44__tar.gz → 1.1.46__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.44 → rclone_api-1.1.46}/PKG-INFO +1 -1
- {rclone_api-1.1.44 → rclone_api-1.1.46}/pyproject.toml +1 -1
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/mount.py +20 -1
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/profile/mount_copy_bytes.py +15 -5
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/rclone.py +50 -28
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api.egg-info/PKG-INFO +1 -1
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.aiderignore +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.github/workflows/lint.yml +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.github/workflows/push_macos.yml +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.github/workflows/push_ubuntu.yml +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.github/workflows/push_win.yml +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.gitignore +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.pylintrc +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.vscode/launch.json +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.vscode/settings.json +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/.vscode/tasks.json +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/LICENSE +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/MANIFEST.in +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/README.md +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/clean +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/install +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/lint +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/requirements.testing.txt +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/setup.cfg +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/setup.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/__init__.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/assets/example.txt +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/cli.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/cmd/copy_large_s3.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/cmd/list_files.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/completed_process.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/config.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/convert.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/deprecated.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/diff.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/dir.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/dir_listing.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/exec.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/experimental/flags.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/experimental/flags_base.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/file.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/filelist.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/group_files.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/process.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/remote.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/rpath.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/s3/api.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/s3/basic_ops.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/s3/chunk_file.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/s3/chunk_types.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/s3/create.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/s3/types.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/s3/upload_file_multipart.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/scan_missing_folders.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/types.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/util.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api/walk.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api.egg-info/SOURCES.txt +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api.egg-info/dependency_links.txt +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api.egg-info/entry_points.txt +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api.egg-info/requires.txt +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/src/rclone_api.egg-info/top_level.txt +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/test +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/archive/test_paramiko.py.disabled +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_cmd_list_files.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_copy.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_copy_bytes.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_copy_file_resumable_s3.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_copy_files.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_diff.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_group_files.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_is_synced.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_ls.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_mount.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_mount_s3.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_obscure.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_rclone_config.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_remote_control.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_remotes.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_s3.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_scan_missing_folders.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_size_files.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_size_suffix.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tests/test_walk.py +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/tox.ini +0 -0
- {rclone_api-1.1.44 → rclone_api-1.1.46}/upload_package.sh +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import platform
|
|
3
|
+
import shutil
|
|
3
4
|
import subprocess
|
|
4
5
|
import time
|
|
5
6
|
import warnings
|
|
@@ -19,6 +20,8 @@ class Mount:
|
|
|
19
20
|
mount_path: Path
|
|
20
21
|
process: Process
|
|
21
22
|
read_only: bool
|
|
23
|
+
cache_dir: Path | None = None
|
|
24
|
+
cache_dir_delete_on_exit: bool | None = None
|
|
22
25
|
_closed: bool = False
|
|
23
26
|
|
|
24
27
|
def __post_init__(self):
|
|
@@ -31,7 +34,15 @@ class Mount:
|
|
|
31
34
|
if self._closed:
|
|
32
35
|
return
|
|
33
36
|
self._closed = True
|
|
34
|
-
clean_mount(self, verbose=False)
|
|
37
|
+
clean_mount(self, verbose=False, wait=wait)
|
|
38
|
+
if self.cache_dir and self.cache_dir_delete_on_exit:
|
|
39
|
+
_cache_dir_delete_on_exit(self.cache_dir)
|
|
40
|
+
|
|
41
|
+
def __enter__(self) -> "Mount":
|
|
42
|
+
return self
|
|
43
|
+
|
|
44
|
+
def __exit__(self, exc_type, exc_value, traceback) -> None:
|
|
45
|
+
self.close(wait=True)
|
|
35
46
|
|
|
36
47
|
def __del__(self):
|
|
37
48
|
self.close(wait=False)
|
|
@@ -173,3 +184,11 @@ def clean_mount(mount: Mount | Path, verbose: bool = False, wait=True) -> None:
|
|
|
173
184
|
else:
|
|
174
185
|
if verbose:
|
|
175
186
|
print(f"{mount_path} successfully cleaned up.")
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _cache_dir_delete_on_exit(cache_dir: Path) -> None:
|
|
190
|
+
if cache_dir.exists():
|
|
191
|
+
try:
|
|
192
|
+
shutil.rmtree(cache_dir)
|
|
193
|
+
except Exception as e:
|
|
194
|
+
warnings.warn(f"Error removing cache directory {cache_dir}: {e}")
|
|
@@ -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
|
|
|
@@ -852,30 +852,35 @@ class Rclone:
|
|
|
852
852
|
if direct_io:
|
|
853
853
|
other_args += ["--direct-io"]
|
|
854
854
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
with open(
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
855
|
+
with TemporaryDirectory() as tmpdir:
|
|
856
|
+
cache_dir = Path(tmpdir) / "cache"
|
|
857
|
+
other_args += ["--cache-dir", str(cache_dir.absolute())]
|
|
858
|
+
try:
|
|
859
|
+
# use scoped mount to do the read, then write the bytes to the destination
|
|
860
|
+
with self.scoped_mount(
|
|
861
|
+
src_parent_path,
|
|
862
|
+
tmp_mnt,
|
|
863
|
+
use_links=True,
|
|
864
|
+
verbose=mount_log is not None,
|
|
865
|
+
vfs_cache_mode="minimal",
|
|
866
|
+
other_args=other_args,
|
|
867
|
+
log=mount_log,
|
|
868
|
+
cache_dir=cache_dir,
|
|
869
|
+
cache_dir_delete_on_exit=True,
|
|
870
|
+
):
|
|
871
|
+
src_file_mnt = tmp_mnt / src_file
|
|
872
|
+
with open(src_file_mnt, "rb") as f:
|
|
873
|
+
f.seek(offset)
|
|
874
|
+
data = f.read(length)
|
|
875
|
+
if outfile is None:
|
|
876
|
+
return data
|
|
877
|
+
with open(outfile, "wb") as out:
|
|
878
|
+
out.write(data)
|
|
879
|
+
del data
|
|
880
|
+
return bytes(0)
|
|
881
|
+
|
|
882
|
+
except Exception as e:
|
|
883
|
+
return e
|
|
879
884
|
|
|
880
885
|
def copy_dir(
|
|
881
886
|
self, src: str | Dir, dst: str | Dir, args: list[str] | None = None
|
|
@@ -909,6 +914,8 @@ class Rclone:
|
|
|
909
914
|
use_links: bool | None = None,
|
|
910
915
|
vfs_cache_mode: str | None = None,
|
|
911
916
|
verbose: bool | None = None,
|
|
917
|
+
cache_dir: Path | None = None,
|
|
918
|
+
cache_dir_delete_on_exit: bool | None = None,
|
|
912
919
|
log: Path | None = None,
|
|
913
920
|
other_args: list[str] | None = None,
|
|
914
921
|
) -> Mount:
|
|
@@ -931,6 +938,7 @@ class Rclone:
|
|
|
931
938
|
vfs_cache_mode = vfs_cache_mode or "full"
|
|
932
939
|
clean_mount(outdir, verbose=verbose)
|
|
933
940
|
prepare_mount(outdir, verbose=verbose)
|
|
941
|
+
debug_fuse = log is not None
|
|
934
942
|
src_str = convert_to_str(src)
|
|
935
943
|
cmd_list: list[str] = ["mount", src_str, str(outdir)]
|
|
936
944
|
if not allow_writes:
|
|
@@ -940,13 +948,24 @@ class Rclone:
|
|
|
940
948
|
if vfs_cache_mode:
|
|
941
949
|
cmd_list.append("--vfs-cache-mode")
|
|
942
950
|
cmd_list.append(vfs_cache_mode)
|
|
951
|
+
if cache_dir:
|
|
952
|
+
cmd_list.append("--cache-dir")
|
|
953
|
+
cmd_list.append(str(cache_dir.absolute()))
|
|
954
|
+
if debug_fuse:
|
|
955
|
+
cmd_list.append("--debug-fuse")
|
|
943
956
|
if verbose:
|
|
944
957
|
cmd_list.append("-vvvv")
|
|
945
958
|
if other_args:
|
|
946
959
|
cmd_list += other_args
|
|
947
960
|
proc = self._launch_process(cmd_list, log=log)
|
|
948
|
-
mount_read_only =
|
|
949
|
-
mount: Mount = Mount(
|
|
961
|
+
mount_read_only = not allow_writes
|
|
962
|
+
mount: Mount = Mount(
|
|
963
|
+
mount_path=outdir,
|
|
964
|
+
process=proc,
|
|
965
|
+
read_only=mount_read_only,
|
|
966
|
+
cache_dir=cache_dir,
|
|
967
|
+
cache_dir_delete_on_exit=cache_dir_delete_on_exit,
|
|
968
|
+
)
|
|
950
969
|
return mount
|
|
951
970
|
|
|
952
971
|
@contextmanager
|
|
@@ -959,11 +978,12 @@ class Rclone:
|
|
|
959
978
|
vfs_cache_mode: str | None = None,
|
|
960
979
|
verbose: bool | None = None,
|
|
961
980
|
log: Path | None = None,
|
|
981
|
+
cache_dir: Path | None = None,
|
|
982
|
+
cache_dir_delete_on_exit: bool | None = None,
|
|
962
983
|
other_args: list[str] | None = None,
|
|
963
984
|
) -> Generator[Mount, None, None]:
|
|
964
985
|
"""Like mount, but can be used in a context manager."""
|
|
965
986
|
error_happened = False
|
|
966
|
-
verbose = get_verbose(verbose)
|
|
967
987
|
mount: Mount = self.mount(
|
|
968
988
|
src,
|
|
969
989
|
outdir,
|
|
@@ -971,6 +991,8 @@ class Rclone:
|
|
|
971
991
|
use_links=use_links,
|
|
972
992
|
vfs_cache_mode=vfs_cache_mode,
|
|
973
993
|
verbose=verbose,
|
|
994
|
+
cache_dir=cache_dir,
|
|
995
|
+
cache_dir_delete_on_exit=cache_dir_delete_on_exit,
|
|
974
996
|
log=log,
|
|
975
997
|
other_args=other_args,
|
|
976
998
|
)
|
|
@@ -982,7 +1004,7 @@ class Rclone:
|
|
|
982
1004
|
warnings.warn(f"Error in scoped_mount: {e}\n\nStack Trace:\n{stack_trace}")
|
|
983
1005
|
raise
|
|
984
1006
|
finally:
|
|
985
|
-
if not error_happened:
|
|
1007
|
+
if not error_happened or (not allow_writes):
|
|
986
1008
|
mount.close()
|
|
987
1009
|
|
|
988
1010
|
# Settings optimized for s3.
|
|
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
|
|
File without changes
|
|
File without changes
|