rclone-api 1.5.40__py3-none-any.whl → 1.5.42__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.
@@ -1,153 +1,153 @@
1
- import random
2
- import time
3
- from concurrent.futures import ThreadPoolExecutor
4
- from queue import Empty, Queue
5
- from threading import Thread
6
- from typing import Generator
7
-
8
- from rclone_api import Dir
9
- from rclone_api.detail.walk import walk_runner_depth_first
10
- from rclone_api.dir_listing import DirListing
11
- from rclone_api.types import ListingOption, Order
12
-
13
- _MAX_OUT_QUEUE_SIZE = 50
14
-
15
-
16
- def _reorder_inplace(data: list, order: Order) -> None:
17
- if order == Order.NORMAL:
18
- return
19
- elif order == Order.REVERSE:
20
- data.reverse()
21
- return
22
- elif order == Order.RANDOM:
23
- random.shuffle(data)
24
- return
25
- else:
26
- raise ValueError(f"Invalid order: {order}")
27
-
28
-
29
- # ONLY Works from src -> dst diffing.
30
- def _async_diff_dir_walk_task(
31
- src: Dir, dst: Dir, max_depth: int, out_queue: Queue[Dir | None], order: Order
32
- ) -> None:
33
- can_scan_two_deep = max_depth > 1 or max_depth == -1
34
- ls_depth = 2 if can_scan_two_deep else 1
35
- with ThreadPoolExecutor(max_workers=2) as executor:
36
- t1 = executor.submit(
37
- src.ls,
38
- listing_option=ListingOption.DIRS_ONLY,
39
- order=order,
40
- max_depth=ls_depth,
41
- )
42
- t2 = executor.submit(
43
- dst.ls,
44
- listing_option=ListingOption.DIRS_ONLY,
45
- order=order,
46
- max_depth=ls_depth,
47
- )
48
- src_dir_listing: DirListing = t1.result()
49
- dst_dir_listing: DirListing = t2.result()
50
- next_depth = max_depth - ls_depth if max_depth > 0 else max_depth
51
- dst_dirs: list[str] = [d.relative_to(src) for d in dst_dir_listing.dirs]
52
- src_dirs: list[str] = [d.relative_to(dst) for d in src_dir_listing.dirs]
53
- dst_files_set: set[str] = set(dst_dirs)
54
- matching_dirs: list[str] = []
55
- _reorder_inplace(src_dirs, order)
56
- _reorder_inplace(dst_dirs, order)
57
- for i, src_dir in enumerate(src_dirs):
58
- src_dir_dir = src / src_dir
59
- if src_dir not in dst_files_set:
60
- queue_dir_listing: Queue[DirListing | None] = Queue()
61
- if next_depth > 0 or next_depth == -1:
62
- walk_runner_depth_first(
63
- dir=src_dir_dir,
64
- out_queue=queue_dir_listing,
65
- order=order,
66
- max_depth=next_depth,
67
- )
68
- out_queue.put(src)
69
- while dirlisting := queue_dir_listing.get():
70
- if dirlisting is None:
71
- break
72
- # print(f"dirlisting: {dirlisting}")
73
- for d in dirlisting.dirs:
74
- out_queue.put(d)
75
- else:
76
- matching_dirs.append(src_dir)
77
-
78
- for matching_dir in matching_dirs:
79
- # print(f"matching dir: {matching_dir}")
80
- if next_depth > 0 or next_depth == -1:
81
- src_next = src / matching_dir
82
- dst_next = dst / matching_dir
83
- _async_diff_dir_walk_task(
84
- src=src_next,
85
- dst=dst_next,
86
- max_depth=next_depth,
87
- out_queue=out_queue,
88
- order=order,
89
- )
90
-
91
-
92
- def async_diff_dir_walk_task(
93
- src: Dir, dst: Dir, max_depth: int, out_queue: Queue[Dir | None], order: Order
94
- ) -> None:
95
- try:
96
- _async_diff_dir_walk_task(
97
- src=src, dst=dst, max_depth=max_depth, out_queue=out_queue, order=order
98
- )
99
- except Exception:
100
- import _thread
101
-
102
- _thread.interrupt_main()
103
- raise
104
- finally:
105
- out_queue.put(None)
106
-
107
-
108
- def scan_missing_folders(
109
- src: Dir,
110
- dst: Dir,
111
- max_depth: int = -1,
112
- order: Order = Order.NORMAL,
113
- ) -> Generator[Dir, None, None]:
114
- """Walk through the given directory recursively.
115
-
116
- Args:
117
- dir: Directory or Remote to walk through
118
- max_depth: Maximum depth to traverse (-1 for unlimited)
119
-
120
- Yields:
121
- DirListing: Directory listing for each directory encountered
122
- """
123
-
124
- try:
125
- out_queue: Queue[Dir | None] = Queue(maxsize=_MAX_OUT_QUEUE_SIZE)
126
-
127
- def task() -> None:
128
- async_diff_dir_walk_task(
129
- src=src,
130
- dst=dst,
131
- max_depth=max_depth,
132
- out_queue=out_queue,
133
- order=order,
134
- )
135
-
136
- worker = Thread(
137
- target=task,
138
- daemon=True,
139
- )
140
- worker.start()
141
-
142
- while True:
143
- try:
144
- dir = out_queue.get_nowait()
145
- if dir is None:
146
- break
147
- yield dir
148
- except Empty:
149
- time.sleep(0.1)
150
-
151
- worker.join()
152
- except KeyboardInterrupt:
153
- pass
1
+ import random
2
+ import time
3
+ from concurrent.futures import ThreadPoolExecutor
4
+ from queue import Empty, Queue
5
+ from threading import Thread
6
+ from typing import Generator
7
+
8
+ from rclone_api import Dir
9
+ from rclone_api.detail.walk import walk_runner_depth_first
10
+ from rclone_api.dir_listing import DirListing
11
+ from rclone_api.types import ListingOption, Order
12
+
13
+ _MAX_OUT_QUEUE_SIZE = 50
14
+
15
+
16
+ def _reorder_inplace(data: list, order: Order) -> None:
17
+ if order == Order.NORMAL:
18
+ return
19
+ elif order == Order.REVERSE:
20
+ data.reverse()
21
+ return
22
+ elif order == Order.RANDOM:
23
+ random.shuffle(data)
24
+ return
25
+ else:
26
+ raise ValueError(f"Invalid order: {order}")
27
+
28
+
29
+ # ONLY Works from src -> dst diffing.
30
+ def _async_diff_dir_walk_task(
31
+ src: Dir, dst: Dir, max_depth: int, out_queue: Queue[Dir | None], order: Order
32
+ ) -> None:
33
+ can_scan_two_deep = max_depth > 1 or max_depth == -1
34
+ ls_depth = 2 if can_scan_two_deep else 1
35
+ with ThreadPoolExecutor(max_workers=2) as executor:
36
+ t1 = executor.submit(
37
+ src.ls,
38
+ listing_option=ListingOption.DIRS_ONLY,
39
+ order=order,
40
+ max_depth=ls_depth,
41
+ )
42
+ t2 = executor.submit(
43
+ dst.ls,
44
+ listing_option=ListingOption.DIRS_ONLY,
45
+ order=order,
46
+ max_depth=ls_depth,
47
+ )
48
+ src_dir_listing: DirListing = t1.result()
49
+ dst_dir_listing: DirListing = t2.result()
50
+ next_depth = max_depth - ls_depth if max_depth > 0 else max_depth
51
+ dst_dirs: list[str] = [d.relative_to(src) for d in dst_dir_listing.dirs]
52
+ src_dirs: list[str] = [d.relative_to(dst) for d in src_dir_listing.dirs]
53
+ dst_files_set: set[str] = set(dst_dirs)
54
+ matching_dirs: list[str] = []
55
+ _reorder_inplace(src_dirs, order)
56
+ _reorder_inplace(dst_dirs, order)
57
+ for i, src_dir in enumerate(src_dirs):
58
+ src_dir_dir = src / src_dir
59
+ if src_dir not in dst_files_set:
60
+ queue_dir_listing: Queue[DirListing | None] = Queue()
61
+ if next_depth > 0 or next_depth == -1:
62
+ walk_runner_depth_first(
63
+ dir=src_dir_dir,
64
+ out_queue=queue_dir_listing,
65
+ order=order,
66
+ max_depth=next_depth,
67
+ )
68
+ out_queue.put(src)
69
+ while dirlisting := queue_dir_listing.get():
70
+ if dirlisting is None:
71
+ break
72
+ # print(f"dirlisting: {dirlisting}")
73
+ for d in dirlisting.dirs:
74
+ out_queue.put(d)
75
+ else:
76
+ matching_dirs.append(src_dir)
77
+
78
+ for matching_dir in matching_dirs:
79
+ # print(f"matching dir: {matching_dir}")
80
+ if next_depth > 0 or next_depth == -1:
81
+ src_next = src / matching_dir
82
+ dst_next = dst / matching_dir
83
+ _async_diff_dir_walk_task(
84
+ src=src_next,
85
+ dst=dst_next,
86
+ max_depth=next_depth,
87
+ out_queue=out_queue,
88
+ order=order,
89
+ )
90
+
91
+
92
+ def async_diff_dir_walk_task(
93
+ src: Dir, dst: Dir, max_depth: int, out_queue: Queue[Dir | None], order: Order
94
+ ) -> None:
95
+ try:
96
+ _async_diff_dir_walk_task(
97
+ src=src, dst=dst, max_depth=max_depth, out_queue=out_queue, order=order
98
+ )
99
+ except Exception:
100
+ import _thread
101
+
102
+ _thread.interrupt_main()
103
+ raise
104
+ finally:
105
+ out_queue.put(None)
106
+
107
+
108
+ def scan_missing_folders(
109
+ src: Dir,
110
+ dst: Dir,
111
+ max_depth: int = -1,
112
+ order: Order = Order.NORMAL,
113
+ ) -> Generator[Dir, None, None]:
114
+ """Walk through the given directory recursively.
115
+
116
+ Args:
117
+ dir: Directory or Remote to walk through
118
+ max_depth: Maximum depth to traverse (-1 for unlimited)
119
+
120
+ Yields:
121
+ DirListing: Directory listing for each directory encountered
122
+ """
123
+
124
+ try:
125
+ out_queue: Queue[Dir | None] = Queue(maxsize=_MAX_OUT_QUEUE_SIZE)
126
+
127
+ def task() -> None:
128
+ async_diff_dir_walk_task(
129
+ src=src,
130
+ dst=dst,
131
+ max_depth=max_depth,
132
+ out_queue=out_queue,
133
+ order=order,
134
+ )
135
+
136
+ worker = Thread(
137
+ target=task,
138
+ daemon=True,
139
+ )
140
+ worker.start()
141
+
142
+ while True:
143
+ try:
144
+ dir = out_queue.get_nowait()
145
+ if dir is None:
146
+ break
147
+ yield dir
148
+ except Empty:
149
+ time.sleep(0.1)
150
+
151
+ worker.join()
152
+ except KeyboardInterrupt:
153
+ pass