rclone-api 1.5.55__py3-none-any.whl → 1.5.56__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/fs/filesystem.py +13 -2
- rclone_api/fs/walk.py +1 -1
- rclone_api/fs/walk_threaded.py +56 -0
- rclone_api/fs/walk_threaded_walker.py +30 -0
- {rclone_api-1.5.55.dist-info → rclone_api-1.5.56.dist-info}/METADATA +1 -1
- {rclone_api-1.5.55.dist-info → rclone_api-1.5.56.dist-info}/RECORD +10 -8
- {rclone_api-1.5.55.dist-info → rclone_api-1.5.56.dist-info}/WHEEL +0 -0
- {rclone_api-1.5.55.dist-info → rclone_api-1.5.56.dist-info}/entry_points.txt +0 -0
- {rclone_api-1.5.55.dist-info → rclone_api-1.5.56.dist-info}/licenses/LICENSE +0 -0
- {rclone_api-1.5.55.dist-info → rclone_api-1.5.56.dist-info}/top_level.txt +0 -0
rclone_api/fs/filesystem.py
CHANGED
@@ -6,6 +6,7 @@ from pathlib import Path
|
|
6
6
|
from typing import Generator
|
7
7
|
|
8
8
|
from rclone_api.config import Config
|
9
|
+
from rclone_api.fs.walk_threaded_walker import FSWalker
|
9
10
|
|
10
11
|
logger = logging.getLogger(__name__)
|
11
12
|
|
@@ -277,9 +278,19 @@ class FSPath:
|
|
277
278
|
def walk(
|
278
279
|
self,
|
279
280
|
) -> "Generator[tuple[FSPath, list[str], list[str]], None, None]":
|
280
|
-
from rclone_api.fs.walk import
|
281
|
+
from rclone_api.fs.walk import fs_walk
|
281
282
|
|
282
|
-
return
|
283
|
+
return fs_walk(self)
|
284
|
+
|
285
|
+
def walk_begin(self, max_backlog: int = 8) -> FSWalker:
|
286
|
+
"""
|
287
|
+
Threaded walker to hide latency.
|
288
|
+
|
289
|
+
with FSPath.walk_begin() as walker:
|
290
|
+
for root, dirnames, filenames in walker:
|
291
|
+
pass
|
292
|
+
"""
|
293
|
+
return FSWalker(self, max_backlog=max_backlog)
|
283
294
|
|
284
295
|
def relative_to(self, other: "FSPath") -> "FSPath":
|
285
296
|
p = Path(self.path).relative_to(other.path)
|
rclone_api/fs/walk.py
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
from queue import Queue
|
2
|
+
from threading import Event, Thread
|
3
|
+
from typing import Generator, List, Optional, Tuple
|
4
|
+
|
5
|
+
from rclone_api.fs.filesystem import FSPath
|
6
|
+
from rclone_api.fs.walk_threaded_walker import FSWalker
|
7
|
+
|
8
|
+
### API
|
9
|
+
|
10
|
+
|
11
|
+
def os_walk_threaded_begin(self: FSPath, max_backlog: int = 8) -> FSWalker:
|
12
|
+
return FSWalker(self, max_backlog)
|
13
|
+
|
14
|
+
|
15
|
+
### Implementation
|
16
|
+
|
17
|
+
|
18
|
+
class _FSWalkThread:
|
19
|
+
def __init__(self, fspath: FSPath, max_backlog: int = 8):
|
20
|
+
self.fspath = fspath
|
21
|
+
self.result_queue: Queue[Optional[Tuple[FSPath, List[str], List[str]]]] = Queue(
|
22
|
+
maxsize=max_backlog
|
23
|
+
)
|
24
|
+
self.thread = Thread(target=self.worker)
|
25
|
+
self.stop_event = Event()
|
26
|
+
self.start()
|
27
|
+
|
28
|
+
def worker(self):
|
29
|
+
from rclone_api.fs.walk import fs_walk
|
30
|
+
|
31
|
+
for root, dirnames, filenames in fs_walk(self.fspath):
|
32
|
+
if self.stop_event.is_set():
|
33
|
+
break
|
34
|
+
self.result_queue.put((root, dirnames, filenames))
|
35
|
+
self.result_queue.put(None) # Sentinel value to indicate completion
|
36
|
+
|
37
|
+
def start(self):
|
38
|
+
self.thread.start()
|
39
|
+
|
40
|
+
def join(self):
|
41
|
+
self.thread.join()
|
42
|
+
|
43
|
+
def get_results(self) -> Generator[Tuple[FSPath, List[str], List[str]], None, None]:
|
44
|
+
while True:
|
45
|
+
result = self.result_queue.get()
|
46
|
+
if result is None: # Check for sentinel value
|
47
|
+
break
|
48
|
+
yield result
|
49
|
+
|
50
|
+
def __enter__(self):
|
51
|
+
self.start()
|
52
|
+
return self
|
53
|
+
|
54
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
55
|
+
self.stop_event.set()
|
56
|
+
self.join()
|
@@ -0,0 +1,30 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
|
5
|
+
@dataclass
|
6
|
+
class FSWalker:
|
7
|
+
"""Threaded"""
|
8
|
+
|
9
|
+
fspath: Any
|
10
|
+
max_backlog: int
|
11
|
+
|
12
|
+
def __enter__(self):
|
13
|
+
from rclone_api.fs.filesystem import FSPath
|
14
|
+
from rclone_api.fs.walk_threaded import _FSWalkThread
|
15
|
+
|
16
|
+
assert isinstance(
|
17
|
+
self.fspath, FSPath
|
18
|
+
), f"Expected FSPath, got {type(self.fspath)}"
|
19
|
+
self.walker = _FSWalkThread(self.fspath, self.max_backlog)
|
20
|
+
return self
|
21
|
+
|
22
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
23
|
+
self.walker.stop_event.set()
|
24
|
+
self.walker.join()
|
25
|
+
|
26
|
+
def __iter__(self):
|
27
|
+
return self.walk()
|
28
|
+
|
29
|
+
def walk(self):
|
30
|
+
return self.walker.get_results()
|
@@ -40,8 +40,10 @@ rclone_api/detail/copy_file_parts_resumable.py,sha256=RoUWV2eBWEvuuTfsvrz5BhtvX3
|
|
40
40
|
rclone_api/detail/walk.py,sha256=-54NVE8EJcCstwDoaC_UtHm73R2HrZwVwQmsnv55xNU,3369
|
41
41
|
rclone_api/experimental/flags.py,sha256=qCVD--fSTmzlk9hloRLr0q9elzAOFzPsvVpKM3aB1Mk,2739
|
42
42
|
rclone_api/experimental/flags_base.py,sha256=ajU_czkTcAxXYU-SlmiCfHY7aCQGHvpCLqJ-Z8uZLk0,2102
|
43
|
-
rclone_api/fs/filesystem.py,sha256=
|
44
|
-
rclone_api/fs/walk.py,sha256=
|
43
|
+
rclone_api/fs/filesystem.py,sha256=ddOEfyPdQExs7EK_Et5rRVwqpIkthrpOp3sQZcSI2Ls,10984
|
44
|
+
rclone_api/fs/walk.py,sha256=Yqn_SS25gTL0ANWSQxnAdN-ELBO1PMZfYYnyxoGafWA,875
|
45
|
+
rclone_api/fs/walk_threaded.py,sha256=ad9MByUsGq3M0Tnv3yfFAK_FFSVJ23fKWQIrU4aLNUs,1579
|
46
|
+
rclone_api/fs/walk_threaded_walker.py,sha256=gAJfn-oNH3cLNBCyG0gSSsnQsLz0xtOf6twNeH3kbxw,720
|
45
47
|
rclone_api/s3/api.py,sha256=HpheMOGHcCc0CyNdv0zvB0S92g312urjRdssRrkdpb8,4162
|
46
48
|
rclone_api/s3/basic_ops.py,sha256=hK3366xhVEzEcjz9Gk_8lFx6MRceAk72cax6mUrr6ko,2104
|
47
49
|
rclone_api/s3/chunk_task.py,sha256=waEYe-iYQ1_BR3NCS4BrzVrK9UANvH1EcbXx2I6Z_NM,6839
|
@@ -56,9 +58,9 @@ rclone_api/s3/multipart/upload_parts_inline.py,sha256=V7syKjFyVIe4U9Ahl5XgqVTzt9
|
|
56
58
|
rclone_api/s3/multipart/upload_parts_resumable.py,sha256=6-nlMclS8jyVvMvFbQDcZOX9MY1WbCcKA_s9bwuYxnk,9793
|
57
59
|
rclone_api/s3/multipart/upload_parts_server_side_merge.py,sha256=Fp2pdrs5dONQI9LkfNolgAGj1-Z2V1SsRd0r0sreuXI,18040
|
58
60
|
rclone_api/s3/multipart/upload_state.py,sha256=f-Aq2NqtAaMUMhYitlICSNIxCKurWAl2gDEUVizLIqw,6019
|
59
|
-
rclone_api-1.5.
|
60
|
-
rclone_api-1.5.
|
61
|
-
rclone_api-1.5.
|
62
|
-
rclone_api-1.5.
|
63
|
-
rclone_api-1.5.
|
64
|
-
rclone_api-1.5.
|
61
|
+
rclone_api-1.5.56.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
62
|
+
rclone_api-1.5.56.dist-info/METADATA,sha256=6T5a5qEwy0amCkHxvF2omjBfMXD-OPtukKnyICtgFCo,37305
|
63
|
+
rclone_api-1.5.56.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
64
|
+
rclone_api-1.5.56.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
|
65
|
+
rclone_api-1.5.56.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
|
66
|
+
rclone_api-1.5.56.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|