rclone-api 1.5.52__py3-none-any.whl → 1.5.53__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,318 +1,330 @@
1
- import abc
2
- import logging
3
- import shutil
4
- import warnings
5
- from pathlib import Path
6
-
7
- from rclone_api.config import Config
8
-
9
- logger = logging.getLogger(__name__)
10
-
11
-
12
- class FS(abc.ABC):
13
- def __init__(self) -> None:
14
- pass
15
-
16
- @abc.abstractmethod
17
- def copy(self, src: Path | str, dst: Path | str) -> None:
18
- pass
19
-
20
- @abc.abstractmethod
21
- def read_bytes(self, path: Path | str) -> bytes:
22
- pass
23
-
24
- @abc.abstractmethod
25
- def exists(self, path: Path | str) -> bool:
26
- pass
27
-
28
- @abc.abstractmethod
29
- def write_binary(self, path: Path | str, data: bytes) -> None:
30
- pass
31
-
32
- @abc.abstractmethod
33
- def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
34
- pass
35
-
36
- @abc.abstractmethod
37
- def ls(self, path: Path | str) -> tuple[list[str], list[str]]:
38
- """First is files and second is directories."""
39
- pass
40
-
41
- @abc.abstractmethod
42
- def cwd(self) -> "FSPath":
43
- pass
44
-
45
- @abc.abstractmethod
46
- def get_path(self, path: str) -> "FSPath":
47
- pass
48
-
49
- @abc.abstractmethod
50
- def dispose(self) -> None:
51
- pass
52
-
53
-
54
- class RealFS(FS):
55
-
56
- @staticmethod
57
- def from_path(path: Path | str) -> "FSPath":
58
- path_str = Path(path).as_posix()
59
- return FSPath(RealFS(), path_str)
60
-
61
- def __init__(self) -> None:
62
- super().__init__()
63
-
64
- def ls(self, path: Path | str) -> tuple[list[str], list[str]]:
65
- files_and_dirs = [str(p) for p in Path(path).iterdir()]
66
- files = [f for f in files_and_dirs if Path(f).is_file()]
67
- dirs = [d for d in files_and_dirs if Path(d).is_dir()]
68
- return files, dirs
69
-
70
- def cwd(self) -> "FSPath":
71
- return RealFS.from_path(Path.cwd())
72
-
73
- def copy(self, src: Path | str, dst: Path | str) -> None:
74
- shutil.copy(str(src), str(dst))
75
-
76
- def read_bytes(self, path: Path | str) -> bytes:
77
- with open(path, "rb") as f:
78
- return f.read()
79
-
80
- def write_binary(self, path: Path | str, data: bytes) -> None:
81
- with open(path, "wb") as f:
82
- f.write(data)
83
-
84
- def exists(self, path: Path | str) -> bool:
85
- return Path(path).exists()
86
-
87
- def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
88
- Path(path).mkdir(parents=parents, exist_ok=exist_ok)
89
-
90
- def get_path(self, path: str) -> "FSPath":
91
- return FSPath(self, path)
92
-
93
- def dispose(self) -> None:
94
- pass
95
-
96
-
97
- class RemoteFS(FS):
98
-
99
- @staticmethod
100
- def from_rclone_config(
101
- src: str, rclone_conf: Path | Config | str | dict | None
102
- ) -> "RemoteFS":
103
- if isinstance(rclone_conf, str) or isinstance(rclone_conf, dict):
104
- rclone_conf = Config(text=rclone_conf)
105
- return RemoteFS(rclone_conf, src)
106
-
107
- def __init__(self, rclone_conf: Path | Config | None, src: str) -> None:
108
- from rclone_api import HttpServer, Rclone
109
-
110
- super().__init__()
111
- self.src = src
112
- self.shutdown = False
113
- self.server: HttpServer | None = None
114
- if rclone_conf is None:
115
- from rclone_api.config import find_conf_file
116
-
117
- rclone_conf = find_conf_file()
118
- if rclone_conf is None:
119
- raise FileNotFoundError("rclone.conf not found")
120
- self.rclone_conf = rclone_conf
121
- self.rclone: Rclone = Rclone(rclone_conf)
122
- self.server = self.rclone.serve_http(src=src)
123
-
124
- def root(self) -> "FSPath":
125
- return FSPath(self, self.src)
126
-
127
- def cwd(self) -> "FSPath":
128
- return self.root()
129
-
130
- def _to_str(self, path: Path | str) -> str:
131
- if isinstance(path, Path):
132
- return path.as_posix()
133
- return path
134
-
135
- def _to_remote_path(self, path: str | Path) -> str:
136
- return Path(path).relative_to(self.src).as_posix()
137
-
138
- def copy(self, src: Path | str, dst: Path | str) -> None:
139
- from rclone_api.completed_process import CompletedProcess
140
-
141
- src = src if isinstance(src, Path) else Path(src)
142
- if not src.is_file():
143
- raise FileNotFoundError(f"File not found: {src}")
144
- dst = self._to_remote_path(dst)
145
-
146
- is_s3 = self.rclone.is_s3(dst)
147
- if is_s3:
148
- filesize = src.stat().st_size
149
- if filesize < 512 * 1024 * 1024:
150
- logger.info(f"S3 OPTIMIZED: Copying {src} -> {dst}")
151
- err = self.rclone.copy_file_s3(src, dst)
152
- if isinstance(err, Exception):
153
- raise FileNotFoundError(
154
- f"File not found: {src}, specified by {err}"
155
- )
156
- return
157
- # Fallback.
158
- logging.info(f"Copying {src} -> {dst}")
159
- src_path = src.as_posix()
160
- cp: CompletedProcess = self.rclone.copy(src_path, dst)
161
- if cp.returncode != 0:
162
- raise FileNotFoundError(f"File not found: {src}, specified by {cp.stderr}")
163
-
164
- def read_bytes(self, path: Path | str) -> bytes:
165
- path = self._to_str(path)
166
- err = self.rclone.read_bytes(path)
167
- if isinstance(err, Exception):
168
- raise FileNotFoundError(f"File not found: {path}")
169
- return err
170
-
171
- def write_binary(self, path: Path | str, data: bytes) -> None:
172
- path = self._to_str(path)
173
- self.rclone.write_bytes(data, path) # Already optimized for s3.
174
-
175
- def exists(self, path: Path | str) -> bool:
176
- from rclone_api.http_server import HttpServer
177
-
178
- assert isinstance(self.server, HttpServer)
179
- path = self._to_str(path)
180
- dst_rel = self._to_remote_path(path)
181
- return self.server.exists(dst_rel)
182
-
183
- def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
184
- # Ignore mkdir for remote backend, it will be made when file is written.
185
- import warnings
186
-
187
- warnings.warn("mkdir is not supported for remote backend", stacklevel=2)
188
- return None
189
-
190
- def is_dir(self, path: Path | str) -> bool:
191
- from rclone_api.http_server import HttpServer
192
-
193
- assert isinstance(self.server, HttpServer)
194
- path = self._to_remote_path(path)
195
- err = self.server.list(path)
196
- return isinstance(err, list)
197
-
198
- def is_file(self, path: Path | str) -> bool:
199
- from rclone_api.http_server import HttpServer
200
-
201
- assert isinstance(self.server, HttpServer)
202
- path = self._to_remote_path(path)
203
- err = self.server.list(path)
204
- # Make faster.
205
- return isinstance(err, Exception) and self.exists(path)
206
-
207
- def ls(self, path: Path | str) -> tuple[list[str], list[str]]:
208
- from rclone_api.http_server import HttpServer
209
-
210
- assert isinstance(self.server, HttpServer)
211
- path = self._to_remote_path(path)
212
- err = self.server.list(path)
213
- if isinstance(err, Exception):
214
- raise FileNotFoundError(f"File not found: {path}, because of {err}")
215
- return err
216
-
217
- def get_path(self, path: str) -> "FSPath":
218
- return FSPath(self, path)
219
-
220
- def dispose(self) -> None:
221
- if self.shutdown or not self.server:
222
- return
223
- self.shutdown = True
224
- self.server.shutdown()
225
-
226
- def __del__(self) -> None:
227
- self.dispose()
228
-
229
-
230
- class FSPath:
231
- def __init__(self, fs: FS, path: str) -> None:
232
- self.fs: FS = fs
233
- self.path: str = path
234
- self.fs_holder: FS | None = None
235
-
236
- def set_owner(self) -> None:
237
- self.fs_holder = self.fs
238
-
239
- def is_real_fs(self) -> bool:
240
- return isinstance(self.fs, RealFS)
241
-
242
- def read_text(self) -> str:
243
- data = self.read_bytes()
244
- return data.decode("utf-8")
245
-
246
- def read_bytes(self) -> bytes:
247
- data: bytes | None = None
248
- try:
249
- data = self.fs.read_bytes(self.path)
250
- return data
251
- except Exception as e:
252
- raise FileNotFoundError(f"File not found: {self.path}, because of {e}")
253
-
254
- def exists(self) -> bool:
255
- return self.fs.exists(self.path)
256
-
257
- def __str__(self) -> str:
258
- return self.path
259
-
260
- def __repr__(self) -> str:
261
- return f"FSPath({self.path})"
262
-
263
- def __enter__(self) -> "FSPath":
264
- if self.fs_holder is not None:
265
- warnings.warn("This operation is reserved for the cwd returned by FS")
266
- return self
267
-
268
- def __exit__(self, exc_type, exc_value, traceback) -> None:
269
- if self.fs_holder is not None:
270
- self.fs_holder.dispose()
271
- self.fs_holder = None
272
-
273
- def mkdir(self, parents=True, exist_ok=True) -> None:
274
- self.fs.mkdir(self.path, parents=parents, exist_ok=exist_ok)
275
-
276
- def write_text(self, data: str, encoding: str | None = None) -> None:
277
- if encoding is None:
278
- encoding = "utf-8"
279
- self.write_bytes(data.encode(encoding))
280
-
281
- def write_bytes(self, data: bytes) -> None:
282
- self.fs.write_binary(self.path, data)
283
-
284
- def rmtree(self, ignore_errors=False) -> None:
285
- assert self.exists(), f"Path does not exist: {self.path}"
286
- # check fs is RealFS
287
- assert isinstance(self.fs, RealFS)
288
- shutil.rmtree(self.path, ignore_errors=ignore_errors)
289
-
290
- def lspaths(self) -> "tuple[list[FSPath], list[FSPath]]":
291
- filenames, dirnames = self.ls()
292
- fpaths: list[FSPath] = [self / name for name in filenames]
293
- dpaths: list[FSPath] = [self / name for name in dirnames]
294
- return fpaths, dpaths
295
-
296
- def ls(self) -> tuple[list[str], list[str]]:
297
- filenames: list[str]
298
- dirnames: list[str]
299
- filenames, dirnames = self.fs.ls(self.path)
300
- return filenames, dirnames
301
-
302
- @property
303
- def name(self) -> str:
304
- return Path(self.path).name
305
-
306
- @property
307
- def parent(self) -> "FSPath":
308
- parent_path = Path(self.path).parent
309
- parent_str = parent_path.as_posix()
310
- return FSPath(self.fs, parent_str)
311
-
312
- def __truediv__(self, other: str) -> "FSPath":
313
- new_path = Path(self.path) / other
314
- return FSPath(self.fs, new_path.as_posix())
315
-
316
- # hashable
317
- def __hash__(self) -> int:
318
- return hash(f"{repr(self.fs)}:{self.path}")
1
+ import abc
2
+ import logging
3
+ import shutil
4
+ import warnings
5
+ from pathlib import Path
6
+ from typing import Generator
7
+
8
+ from rclone_api.config import Config
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class FS(abc.ABC):
14
+ def __init__(self) -> None:
15
+ pass
16
+
17
+ @abc.abstractmethod
18
+ def copy(self, src: Path | str, dst: Path | str) -> None:
19
+ pass
20
+
21
+ @abc.abstractmethod
22
+ def read_bytes(self, path: Path | str) -> bytes:
23
+ pass
24
+
25
+ @abc.abstractmethod
26
+ def exists(self, path: Path | str) -> bool:
27
+ pass
28
+
29
+ @abc.abstractmethod
30
+ def write_binary(self, path: Path | str, data: bytes) -> None:
31
+ pass
32
+
33
+ @abc.abstractmethod
34
+ def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
35
+ pass
36
+
37
+ @abc.abstractmethod
38
+ def ls(self, path: Path | str) -> tuple[list[str], list[str]]:
39
+ """First is files and second is directories."""
40
+ pass
41
+
42
+ @abc.abstractmethod
43
+ def cwd(self) -> "FSPath":
44
+ pass
45
+
46
+ @abc.abstractmethod
47
+ def get_path(self, path: str) -> "FSPath":
48
+ pass
49
+
50
+ @abc.abstractmethod
51
+ def dispose(self) -> None:
52
+ pass
53
+
54
+
55
+ class RealFS(FS):
56
+
57
+ @staticmethod
58
+ def from_path(path: Path | str) -> "FSPath":
59
+ path_str = Path(path).as_posix()
60
+ return FSPath(RealFS(), path_str)
61
+
62
+ def __init__(self) -> None:
63
+ super().__init__()
64
+
65
+ def ls(self, path: Path | str) -> tuple[list[str], list[str]]:
66
+ files_and_dirs = [str(p) for p in Path(path).iterdir()]
67
+ files = [f for f in files_and_dirs if Path(f).is_file()]
68
+ dirs = [d for d in files_and_dirs if Path(d).is_dir()]
69
+ return files, dirs
70
+
71
+ def cwd(self) -> "FSPath":
72
+ return RealFS.from_path(Path.cwd())
73
+
74
+ def copy(self, src: Path | str, dst: Path | str) -> None:
75
+ shutil.copy(str(src), str(dst))
76
+
77
+ def read_bytes(self, path: Path | str) -> bytes:
78
+ with open(path, "rb") as f:
79
+ return f.read()
80
+
81
+ def write_binary(self, path: Path | str, data: bytes) -> None:
82
+ with open(path, "wb") as f:
83
+ f.write(data)
84
+
85
+ def exists(self, path: Path | str) -> bool:
86
+ return Path(path).exists()
87
+
88
+ def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
89
+ Path(path).mkdir(parents=parents, exist_ok=exist_ok)
90
+
91
+ def get_path(self, path: str) -> "FSPath":
92
+ return FSPath(self, path)
93
+
94
+ def dispose(self) -> None:
95
+ pass
96
+
97
+
98
+ class RemoteFS(FS):
99
+
100
+ @staticmethod
101
+ def from_rclone_config(
102
+ src: str, rclone_conf: Path | Config | str | dict | None
103
+ ) -> "RemoteFS":
104
+ if isinstance(rclone_conf, str) or isinstance(rclone_conf, dict):
105
+ rclone_conf = Config(text=rclone_conf)
106
+ return RemoteFS(rclone_conf, src)
107
+
108
+ def __init__(self, rclone_conf: Path | Config | None, src: str) -> None:
109
+ from rclone_api import HttpServer, Rclone
110
+
111
+ super().__init__()
112
+ self.src = src
113
+ self.shutdown = False
114
+ self.server: HttpServer | None = None
115
+ if rclone_conf is None:
116
+ from rclone_api.config import find_conf_file
117
+
118
+ rclone_conf = find_conf_file()
119
+ if rclone_conf is None:
120
+ raise FileNotFoundError("rclone.conf not found")
121
+ self.rclone_conf = rclone_conf
122
+ self.rclone: Rclone = Rclone(rclone_conf)
123
+ self.server = self.rclone.serve_http(src=src)
124
+
125
+ def root(self) -> "FSPath":
126
+ return FSPath(self, self.src)
127
+
128
+ def cwd(self) -> "FSPath":
129
+ return self.root()
130
+
131
+ def _to_str(self, path: Path | str) -> str:
132
+ if isinstance(path, Path):
133
+ return path.as_posix()
134
+ return path
135
+
136
+ def _to_remote_path(self, path: str | Path) -> str:
137
+ return Path(path).relative_to(self.src).as_posix()
138
+
139
+ def copy(self, src: Path | str, dst: Path | str) -> None:
140
+ from rclone_api.completed_process import CompletedProcess
141
+
142
+ src = src if isinstance(src, Path) else Path(src)
143
+ if not src.is_file():
144
+ raise FileNotFoundError(f"File not found: {src}")
145
+ dst = self._to_remote_path(dst)
146
+
147
+ is_s3 = self.rclone.is_s3(dst)
148
+ if is_s3:
149
+ filesize = src.stat().st_size
150
+ if filesize < 1024 * 1024 * 1024: # 1GB
151
+ logger.info(f"S3 OPTIMIZED: Copying {src} -> {dst}")
152
+ err = self.rclone.copy_file_s3(src, dst)
153
+ if isinstance(err, Exception):
154
+ raise FileNotFoundError(
155
+ f"File not found: {src}, specified by {err}"
156
+ )
157
+ return
158
+ # Fallback.
159
+ logging.info(f"Copying {src} -> {dst}")
160
+ src_path = src.as_posix()
161
+ cp: CompletedProcess = self.rclone.copy(src_path, dst)
162
+ if cp.returncode != 0:
163
+ raise FileNotFoundError(f"File not found: {src}, specified by {cp.stderr}")
164
+
165
+ def read_bytes(self, path: Path | str) -> bytes:
166
+ path = self._to_str(path)
167
+ err = self.rclone.read_bytes(path)
168
+ if isinstance(err, Exception):
169
+ raise FileNotFoundError(f"File not found: {path}")
170
+ return err
171
+
172
+ def write_binary(self, path: Path | str, data: bytes) -> None:
173
+ path = self._to_str(path)
174
+ self.rclone.write_bytes(data, path) # Already optimized for s3.
175
+
176
+ def exists(self, path: Path | str) -> bool:
177
+ from rclone_api.http_server import HttpServer
178
+
179
+ assert isinstance(self.server, HttpServer)
180
+ path = self._to_str(path)
181
+ dst_rel = self._to_remote_path(path)
182
+ return self.server.exists(dst_rel)
183
+
184
+ def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
185
+ # Ignore mkdir for remote backend, it will be made when file is written.
186
+ import warnings
187
+
188
+ warnings.warn("mkdir is not supported for remote backend", stacklevel=2)
189
+ return None
190
+
191
+ def is_dir(self, path: Path | str) -> bool:
192
+ from rclone_api.http_server import HttpServer
193
+
194
+ assert isinstance(self.server, HttpServer)
195
+ path = self._to_remote_path(path)
196
+ err = self.server.list(path)
197
+ return isinstance(err, list)
198
+
199
+ def is_file(self, path: Path | str) -> bool:
200
+ from rclone_api.http_server import HttpServer
201
+
202
+ assert isinstance(self.server, HttpServer)
203
+ path = self._to_remote_path(path)
204
+ err = self.server.list(path)
205
+ # Make faster.
206
+ return isinstance(err, Exception) and self.exists(path)
207
+
208
+ def ls(self, path: Path | str) -> tuple[list[str], list[str]]:
209
+ from rclone_api.http_server import HttpServer
210
+
211
+ assert isinstance(self.server, HttpServer)
212
+ path = self._to_remote_path(path)
213
+ err = self.server.list(path)
214
+ if isinstance(err, Exception):
215
+ raise FileNotFoundError(f"File not found: {path}, because of {err}")
216
+ return err
217
+
218
+ def get_path(self, path: str) -> "FSPath":
219
+ return FSPath(self, path)
220
+
221
+ def dispose(self) -> None:
222
+ if self.shutdown or not self.server:
223
+ return
224
+ self.shutdown = True
225
+ self.server.shutdown()
226
+
227
+ def __del__(self) -> None:
228
+ self.dispose()
229
+
230
+
231
+ class FSPath:
232
+ def __init__(self, fs: FS, path: str) -> None:
233
+ self.fs: FS = fs
234
+ self.path: str = path
235
+ self.fs_holder: FS | None = None
236
+
237
+ def set_owner(self) -> None:
238
+ self.fs_holder = self.fs
239
+
240
+ def is_real_fs(self) -> bool:
241
+ return isinstance(self.fs, RealFS)
242
+
243
+ def read_text(self) -> str:
244
+ data = self.read_bytes()
245
+ return data.decode("utf-8")
246
+
247
+ def read_bytes(self) -> bytes:
248
+ data: bytes | None = None
249
+ try:
250
+ data = self.fs.read_bytes(self.path)
251
+ return data
252
+ except Exception as e:
253
+ raise FileNotFoundError(f"File not found: {self.path}, because of {e}")
254
+
255
+ def exists(self) -> bool:
256
+ return self.fs.exists(self.path)
257
+
258
+ def __str__(self) -> str:
259
+ return self.path
260
+
261
+ def __repr__(self) -> str:
262
+ return f"FSPath({self.path})"
263
+
264
+ def __enter__(self) -> "FSPath":
265
+ if self.fs_holder is not None:
266
+ warnings.warn("This operation is reserved for the cwd returned by FS")
267
+ return self
268
+
269
+ def __exit__(self, exc_type, exc_value, traceback) -> None:
270
+ if self.fs_holder is not None:
271
+ self.fs_holder.dispose()
272
+ self.fs_holder = None
273
+
274
+ def mkdir(self, parents=True, exist_ok=True) -> None:
275
+ self.fs.mkdir(self.path, parents=parents, exist_ok=exist_ok)
276
+
277
+ def os_walk(
278
+ self,
279
+ ) -> "Generator[tuple[FSPath, list[str], list[str]], None, None]":
280
+ from rclone_api.fs.os_walk import os_walk
281
+
282
+ return os_walk(self)
283
+
284
+ def relative_to(self, other: "FSPath") -> "FSPath":
285
+ p = Path(self.path).relative_to(other.path)
286
+ return FSPath(self.fs, p.as_posix())
287
+
288
+ def write_text(self, data: str, encoding: str | None = None) -> None:
289
+ if encoding is None:
290
+ encoding = "utf-8"
291
+ self.write_bytes(data.encode(encoding))
292
+
293
+ def write_bytes(self, data: bytes) -> None:
294
+ self.fs.write_binary(self.path, data)
295
+
296
+ def rmtree(self, ignore_errors=False) -> None:
297
+ assert self.exists(), f"Path does not exist: {self.path}"
298
+ # check fs is RealFS
299
+ assert isinstance(self.fs, RealFS)
300
+ shutil.rmtree(self.path, ignore_errors=ignore_errors)
301
+
302
+ def lspaths(self) -> "tuple[list[FSPath], list[FSPath]]":
303
+ filenames, dirnames = self.ls()
304
+ fpaths: list[FSPath] = [self / name for name in filenames]
305
+ dpaths: list[FSPath] = [self / name for name in dirnames]
306
+ return fpaths, dpaths
307
+
308
+ def ls(self) -> tuple[list[str], list[str]]:
309
+ filenames: list[str]
310
+ dirnames: list[str]
311
+ filenames, dirnames = self.fs.ls(self.path)
312
+ return filenames, dirnames
313
+
314
+ @property
315
+ def name(self) -> str:
316
+ return Path(self.path).name
317
+
318
+ @property
319
+ def parent(self) -> "FSPath":
320
+ parent_path = Path(self.path).parent
321
+ parent_str = parent_path.as_posix()
322
+ return FSPath(self.fs, parent_str)
323
+
324
+ def __truediv__(self, other: str) -> "FSPath":
325
+ new_path = Path(self.path) / other
326
+ return FSPath(self.fs, new_path.as_posix())
327
+
328
+ # hashable
329
+ def __hash__(self) -> int:
330
+ return hash(f"{repr(self.fs)}:{self.path}")
@@ -0,0 +1,24 @@
1
+ from typing import Generator
2
+
3
+ from rclone_api.fs.filesystem import FSPath, logger
4
+
5
+
6
+ def os_walk(
7
+ self: FSPath,
8
+ ) -> Generator[tuple[FSPath, list[str], list[str]], None, None]:
9
+ root_path = self
10
+ stack: list[str] = [self.path]
11
+
12
+ while stack:
13
+ current_dir = root_path / stack.pop()
14
+ try:
15
+ filenames, dirnames = current_dir.ls()
16
+ except Exception as e:
17
+ logger.warning(f"Unable to list directory {current_dir}: {e}")
18
+ continue
19
+
20
+ yield current_dir, dirnames, filenames
21
+
22
+ # Add subdirectories to stack for further traversal
23
+ for dirname in reversed(dirnames):
24
+ stack.append((current_dir / dirname).path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rclone_api
3
- Version: 1.5.52
3
+ Version: 1.5.53
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -40,7 +40,8 @@ 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=KgaLqk6OCePcWWtPgh9NDf3dMJzYpHdhQspvzgQ0r1s,9919
43
+ rclone_api/fs/filesystem.py,sha256=QHPqU4NxIH5rowg-h44E26yqPwPYwy_pkhZFEP9GSio,10623
44
+ rclone_api/fs/os_walk.py,sha256=usNCSGCXiP50Ijx9uTxGb8MuZPqFazzQ-746R7KsbP4,722
44
45
  rclone_api/s3/api.py,sha256=HpheMOGHcCc0CyNdv0zvB0S92g312urjRdssRrkdpb8,4162
45
46
  rclone_api/s3/basic_ops.py,sha256=hK3366xhVEzEcjz9Gk_8lFx6MRceAk72cax6mUrr6ko,2104
46
47
  rclone_api/s3/chunk_task.py,sha256=waEYe-iYQ1_BR3NCS4BrzVrK9UANvH1EcbXx2I6Z_NM,6839
@@ -55,9 +56,9 @@ rclone_api/s3/multipart/upload_parts_inline.py,sha256=V7syKjFyVIe4U9Ahl5XgqVTzt9
55
56
  rclone_api/s3/multipart/upload_parts_resumable.py,sha256=6-nlMclS8jyVvMvFbQDcZOX9MY1WbCcKA_s9bwuYxnk,9793
56
57
  rclone_api/s3/multipart/upload_parts_server_side_merge.py,sha256=Fp2pdrs5dONQI9LkfNolgAGj1-Z2V1SsRd0r0sreuXI,18040
57
58
  rclone_api/s3/multipart/upload_state.py,sha256=f-Aq2NqtAaMUMhYitlICSNIxCKurWAl2gDEUVizLIqw,6019
58
- rclone_api-1.5.52.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
59
- rclone_api-1.5.52.dist-info/METADATA,sha256=pzUkl7zLuD22M8z-gOpbEkACDpT0tZ6r62N3hJ-LwMc,37305
60
- rclone_api-1.5.52.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
61
- rclone_api-1.5.52.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
62
- rclone_api-1.5.52.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
63
- rclone_api-1.5.52.dist-info/RECORD,,
59
+ rclone_api-1.5.53.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
60
+ rclone_api-1.5.53.dist-info/METADATA,sha256=rzx89Tj1CGG-VXhWzrGGuLy72NEf0BZ7IeW-BMqBmZA,37305
61
+ rclone_api-1.5.53.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
62
+ rclone_api-1.5.53.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
63
+ rclone_api-1.5.53.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
64
+ rclone_api-1.5.53.dist-info/RECORD,,