rclone-api 1.1.84__tar.gz → 1.1.86__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.84 → rclone_api-1.1.86}/PKG-INFO +1 -1
- {rclone_api-1.1.84 → rclone_api-1.1.86}/pyproject.toml +1 -1
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/mount.py +19 -12
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/profile/mount_copy_bytes.py +22 -5
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/rclone.py +2 -1
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/types.py +8 -9
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api.egg-info/PKG-INFO +1 -1
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.aiderignore +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.github/workflows/lint.yml +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.github/workflows/push_macos.yml +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.github/workflows/push_ubuntu.yml +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.github/workflows/push_win.yml +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.gitignore +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.pylintrc +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.vscode/launch.json +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.vscode/settings.json +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/.vscode/tasks.json +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/LICENSE +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/MANIFEST.in +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/README.md +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/clean +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/install +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/lint +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/requirements.testing.txt +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/setup.cfg +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/setup.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/__init__.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/assets/example.txt +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/cli.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/cmd/copy_large_s3.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/cmd/list_files.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/completed_process.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/config.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/convert.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/deprecated.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/diff.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/dir.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/dir_listing.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/exec.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/experimental/flags.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/experimental/flags_base.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/file.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/filelist.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/group_files.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/process.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/remote.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/rpath.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/s3/api.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/s3/basic_ops.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/s3/chunk_file.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/s3/chunk_types.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/s3/create.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/s3/types.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/s3/upload_file_multipart.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/scan_missing_folders.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/util.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api/walk.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api.egg-info/SOURCES.txt +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api.egg-info/dependency_links.txt +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api.egg-info/entry_points.txt +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api.egg-info/requires.txt +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/src/rclone_api.egg-info/top_level.txt +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/test +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/archive/test_paramiko.py.disabled +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_cmd_list_files.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_copy.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_copy_bytes.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_copy_file_resumable_s3.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_copy_files.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_diff.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_group_files.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_is_synced.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_ls.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_mount.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_mount_s3.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_obscure.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_rclone_config.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_remote_control.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_remotes.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_s3.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_scan_missing_folders.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_size_files.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_size_suffix.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tests/test_walk.py +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/tox.ini +0 -0
- {rclone_api-1.1.84 → rclone_api-1.1.86}/upload_package.sh +0 -0
|
@@ -313,7 +313,7 @@ class MultiMountFileChunker:
|
|
|
313
313
|
for mount in self.mounts_processing:
|
|
314
314
|
executor.submit(lambda: mount.close())
|
|
315
315
|
|
|
316
|
-
def fetch(self, offset: int, size: int) -> bytes | Exception:
|
|
316
|
+
def fetch(self, offset: int, size: int) -> Future[bytes | Exception]:
|
|
317
317
|
if self.verbose:
|
|
318
318
|
print(f"Fetching data range: offset={offset}, size={size}")
|
|
319
319
|
try:
|
|
@@ -325,7 +325,10 @@ class MultiMountFileChunker:
|
|
|
325
325
|
assert offset >= 0, f"Invalid offset: {offset}"
|
|
326
326
|
except AssertionError as e:
|
|
327
327
|
warnings.warn(f"Invalid chunk request: {e}")
|
|
328
|
-
return ValueError(e)
|
|
328
|
+
# return ValueError(e)
|
|
329
|
+
# return self.executor.submit(lambda: Exception(e))
|
|
330
|
+
err = Exception(e)
|
|
331
|
+
return self.executor.submit(lambda: err)
|
|
329
332
|
|
|
330
333
|
chunks: list[tuple[int, int]] = []
|
|
331
334
|
start = offset
|
|
@@ -375,15 +378,19 @@ class MultiMountFileChunker:
|
|
|
375
378
|
fut = self.executor.submit(task)
|
|
376
379
|
futures.append(fut)
|
|
377
380
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
381
|
+
def combine(futs: list[Future[bytes | Exception]]) -> bytes | Exception:
|
|
382
|
+
finished_list: list[bytes | Exception] = [f.result() for f in futs]
|
|
383
|
+
bytes_list = [f for f in finished_list if isinstance(f, bytes)]
|
|
384
|
+
if len(bytes_list) != len(finished_list):
|
|
385
|
+
exceptions = [f for f in finished_list if isinstance(f, Exception)]
|
|
386
|
+
return Exception(f"Error fetching file chunk: {exceptions}")
|
|
387
|
+
return b"".join(bytes_list)
|
|
388
|
+
|
|
389
|
+
if len(futures) == 1:
|
|
390
|
+
return futures[0]
|
|
391
|
+
fut = self.executor.submit(combine, futures)
|
|
392
|
+
return fut
|
|
387
393
|
except Exception as e:
|
|
388
394
|
warnings.warn(f"Error fetching file chunk: {e}")
|
|
389
|
-
|
|
395
|
+
err = Exception(e)
|
|
396
|
+
return self.executor.submit(lambda: err)
|
|
@@ -6,6 +6,7 @@ import argparse
|
|
|
6
6
|
import os
|
|
7
7
|
import shutil
|
|
8
8
|
import time
|
|
9
|
+
from concurrent.futures import Future
|
|
9
10
|
from dataclasses import dataclass
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
|
|
@@ -117,8 +118,8 @@ def _run_profile(
|
|
|
117
118
|
print("#" * 80)
|
|
118
119
|
print(f"# Started test download of {SizeSuffix(size)} with {transfers} transfers")
|
|
119
120
|
print("#" * 80)
|
|
120
|
-
|
|
121
|
-
chunk_size = size
|
|
121
|
+
|
|
122
|
+
chunk_size = size
|
|
122
123
|
|
|
123
124
|
filechunker: MultiMountFileChunker = rclone.get_multi_mount_file_chunker(
|
|
124
125
|
src=src_file,
|
|
@@ -127,10 +128,11 @@ def _run_profile(
|
|
|
127
128
|
direct_io=direct_io,
|
|
128
129
|
mount_log=mount_log,
|
|
129
130
|
)
|
|
131
|
+
for i in range(num):
|
|
132
|
+
bytes_or_err = filechunker.fetch(offset.as_int(), size.as_int()).result()
|
|
130
133
|
|
|
131
|
-
bytes_or_err = filechunker.fetch(offset.as_int(), size.as_int())
|
|
132
|
-
|
|
133
134
|
start = time.time()
|
|
135
|
+
net_io_start = psutil.net_io_counters()
|
|
134
136
|
|
|
135
137
|
# bytes_or_err: bytes | Exception = rclone.copy_bytes(
|
|
136
138
|
# src=src_file,
|
|
@@ -142,7 +144,22 @@ def _run_profile(
|
|
|
142
144
|
# mount_log=mount_log,
|
|
143
145
|
# )
|
|
144
146
|
|
|
145
|
-
bytes_or_err = filechunker.fetch(
|
|
147
|
+
# bytes_or_err = filechunker.fetch(
|
|
148
|
+
# (offset + SizeSuffix("1G")).as_int(), size.as_int()
|
|
149
|
+
# )
|
|
150
|
+
|
|
151
|
+
offset = SizeSuffix("1G")
|
|
152
|
+
|
|
153
|
+
futures: list[Future[bytes | Exception]] = []
|
|
154
|
+
for i in range(num):
|
|
155
|
+
offset = SizeSuffix(i * chunk_size.as_int()) + offset
|
|
156
|
+
future = filechunker.fetch(offset.as_int(), size.as_int())
|
|
157
|
+
futures.append(future)
|
|
158
|
+
|
|
159
|
+
for future in futures:
|
|
160
|
+
bytes_or_err = future.result()
|
|
161
|
+
if isinstance(bytes_or_err, Exception):
|
|
162
|
+
assert False, f"Error: {bytes_or_err}"
|
|
146
163
|
|
|
147
164
|
diff = time.time() - start
|
|
148
165
|
net_io_end = psutil.net_io_counters()
|
|
@@ -993,7 +993,8 @@ class Rclone:
|
|
|
993
993
|
direct_io=direct_io,
|
|
994
994
|
)
|
|
995
995
|
try:
|
|
996
|
-
|
|
996
|
+
fut = filechunker.fetch(offset, length)
|
|
997
|
+
data = fut.result()
|
|
997
998
|
if isinstance(data, Exception):
|
|
998
999
|
warnings.warn(f"Error copying bytes: {data}")
|
|
999
1000
|
raise data
|
|
@@ -178,40 +178,39 @@ class SizeSuffix:
|
|
|
178
178
|
raise ZeroDivisionError("Division by zero is undefined")
|
|
179
179
|
# Use floor division to maintain integer arithmetic.
|
|
180
180
|
return SizeSuffix(self._size // other_int._size)
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
def __eq__(self, other: object) -> bool:
|
|
183
183
|
if not isinstance(other, SizeSuffix):
|
|
184
184
|
return False
|
|
185
185
|
return self._size == other._size
|
|
186
|
-
|
|
186
|
+
|
|
187
187
|
def __ne__(self, other: object) -> bool:
|
|
188
188
|
if not isinstance(other, SizeSuffix):
|
|
189
189
|
return True
|
|
190
190
|
return self._size != other._size
|
|
191
|
-
|
|
191
|
+
|
|
192
192
|
def __lt__(self, other: object) -> bool:
|
|
193
193
|
if not isinstance(other, SizeSuffix):
|
|
194
194
|
return False
|
|
195
195
|
return self._size < other._size
|
|
196
|
-
|
|
196
|
+
|
|
197
197
|
def __le__(self, other: object) -> bool:
|
|
198
198
|
if not isinstance(other, SizeSuffix):
|
|
199
199
|
return False
|
|
200
200
|
return self._size <= other._size
|
|
201
|
-
|
|
201
|
+
|
|
202
202
|
def __gt__(self, other: object) -> bool:
|
|
203
203
|
if not isinstance(other, SizeSuffix):
|
|
204
204
|
return False
|
|
205
205
|
return self._size > other._size
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
def __ge__(self, other: object) -> bool:
|
|
208
208
|
if not isinstance(other, SizeSuffix):
|
|
209
209
|
return False
|
|
210
210
|
return self._size >= other._size
|
|
211
|
-
|
|
211
|
+
|
|
212
212
|
def __hash__(self) -> int:
|
|
213
213
|
return hash(self._size)
|
|
214
|
-
|
|
214
|
+
|
|
215
215
|
def __int__(self) -> int:
|
|
216
216
|
return self._size
|
|
217
|
-
|
|
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
|