rclone-api 1.5.70__py3-none-any.whl → 1.5.71__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/walk.py +55 -20
- {rclone_api-1.5.70.dist-info → rclone_api-1.5.71.dist-info}/METADATA +1 -1
- {rclone_api-1.5.70.dist-info → rclone_api-1.5.71.dist-info}/RECORD +7 -7
- {rclone_api-1.5.70.dist-info → rclone_api-1.5.71.dist-info}/WHEEL +0 -0
- {rclone_api-1.5.70.dist-info → rclone_api-1.5.71.dist-info}/entry_points.txt +0 -0
- {rclone_api-1.5.70.dist-info → rclone_api-1.5.71.dist-info}/licenses/LICENSE +0 -0
- {rclone_api-1.5.70.dist-info → rclone_api-1.5.71.dist-info}/top_level.txt +0 -0
rclone_api/fs/walk.py
CHANGED
@@ -1,27 +1,62 @@
|
|
1
|
-
|
1
|
+
import os
|
2
|
+
from collections import OrderedDict
|
3
|
+
from concurrent.futures import FIRST_COMPLETED, ThreadPoolExecutor, wait
|
2
4
|
from typing import Generator
|
3
5
|
|
4
6
|
from rclone_api.fs.filesystem import FSPath, logger
|
5
7
|
|
8
|
+
_FS_WALK_THREAD_MAX_BACKLOG = int(os.getenv("FS_WALK_THREAD_MAX_BACKLOG", "16"))
|
9
|
+
# module‐wide executor
|
10
|
+
_executor = ThreadPoolExecutor(max_workers=_FS_WALK_THREAD_MAX_BACKLOG)
|
6
11
|
|
7
|
-
|
12
|
+
|
13
|
+
def _list_dir(path: FSPath):
|
14
|
+
try:
|
15
|
+
filenames, dirnames = path.ls()
|
16
|
+
except Exception as e:
|
17
|
+
logger.warning(f"Unable to list directory {path}: {e}")
|
18
|
+
return None
|
19
|
+
return path, dirnames, filenames
|
20
|
+
|
21
|
+
|
22
|
+
def fs_walk_parallel(
|
8
23
|
self: FSPath,
|
9
24
|
) -> Generator[tuple[FSPath, list[str], list[str]], None, None]:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
"""
|
26
|
+
Parallel version of fs_walk: walks `self` and lists
|
27
|
+
up to 16 directories at once using the global executor,
|
28
|
+
but yields results in the same order tasks were submitted.
|
29
|
+
"""
|
30
|
+
root = self
|
31
|
+
|
32
|
+
# use an OrderedDict to remember submission order
|
33
|
+
futures: OrderedDict = OrderedDict()
|
34
|
+
# submit the root first
|
35
|
+
futures[_executor.submit(_list_dir, root)] = root
|
36
|
+
|
37
|
+
while futures:
|
38
|
+
# wait until at least one of them finishes
|
39
|
+
done, _ = wait(futures.keys(), return_when=FIRST_COMPLETED)
|
40
|
+
|
41
|
+
# iterate through our futures *in submission order*
|
42
|
+
for fut in list(futures.keys()):
|
43
|
+
if fut not in done:
|
44
|
+
continue
|
45
|
+
|
46
|
+
_ = futures.pop(fut) # remove it in order
|
47
|
+
result = fut.result()
|
48
|
+
if result is None:
|
49
|
+
continue # error already logged
|
50
|
+
|
51
|
+
current_dir, dirnames, filenames = result
|
52
|
+
yield current_dir, dirnames, filenames
|
53
|
+
|
54
|
+
# now schedule its children (they go at the end of our OrderedDict)
|
55
|
+
for dirname in dirnames:
|
56
|
+
sub = current_dir / dirname
|
57
|
+
futures[_executor.submit(_list_dir, sub)] = sub
|
58
|
+
|
59
|
+
|
60
|
+
def fs_walk(self: FSPath) -> Generator[tuple[FSPath, list[str], list[str]], None, None]:
|
61
|
+
"""Sequential API, now backed by the global-thread-pool parallel implementation."""
|
62
|
+
yield from fs_walk_parallel(self)
|
@@ -41,7 +41,7 @@ rclone_api/detail/walk.py,sha256=-54NVE8EJcCstwDoaC_UtHm73R2HrZwVwQmsnv55xNU,336
|
|
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
43
|
rclone_api/fs/filesystem.py,sha256=2Ewa5g_842XU-UT4JDkPkq199pjknjoqpTiKtbRRRGk,11964
|
44
|
-
rclone_api/fs/walk.py,sha256=
|
44
|
+
rclone_api/fs/walk.py,sha256=gqxfJqzFSQlLwZ18ttO25SbCCs7Vcz_CtlDgjiqpNZc,2183
|
45
45
|
rclone_api/fs/walk_threaded.py,sha256=zlbooQ7WbteUK1cCjm1Yj66VpDzS8Qm3DcHBSz1Gbjk,1591
|
46
46
|
rclone_api/fs/walk_threaded_walker.py,sha256=xi0QkmmzI35NcaA08FLjGe7ox9tLZcgXtOZCT8nMuWU,718
|
47
47
|
rclone_api/s3/api.py,sha256=HpheMOGHcCc0CyNdv0zvB0S92g312urjRdssRrkdpb8,4162
|
@@ -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=tdOkEfoK9zENaTfgVyTWB5GNqn-IYl-zJn-rJLcoVTo,12388
|
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.71.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
62
|
+
rclone_api-1.5.71.dist-info/METADATA,sha256=qnLOllDyan73gwf8Nb5W5B9vhYnRUP1fRhRrA-5c56Q,37305
|
63
|
+
rclone_api-1.5.71.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
|
64
|
+
rclone_api-1.5.71.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
|
65
|
+
rclone_api-1.5.71.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
|
66
|
+
rclone_api-1.5.71.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|