rclone-api 1.5.14__py3-none-any.whl → 1.5.17__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/filesystem.py +34 -1
- rclone_api/http_server.py +38 -0
- {rclone_api-1.5.14.dist-info → rclone_api-1.5.17.dist-info}/METADATA +2 -1
- {rclone_api-1.5.14.dist-info → rclone_api-1.5.17.dist-info}/RECORD +8 -8
- {rclone_api-1.5.14.dist-info → rclone_api-1.5.17.dist-info}/WHEEL +0 -0
- {rclone_api-1.5.14.dist-info → rclone_api-1.5.17.dist-info}/entry_points.txt +0 -0
- {rclone_api-1.5.14.dist-info → rclone_api-1.5.17.dist-info}/licenses/LICENSE +0 -0
- {rclone_api-1.5.14.dist-info → rclone_api-1.5.17.dist-info}/top_level.txt +0 -0
rclone_api/filesystem.py
CHANGED
@@ -27,6 +27,10 @@ class FileSystem(abc.ABC):
|
|
27
27
|
def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
|
28
28
|
pass
|
29
29
|
|
30
|
+
@abc.abstractmethod
|
31
|
+
def ls(self, path: Path | str) -> list[str]:
|
32
|
+
pass
|
33
|
+
|
30
34
|
@abc.abstractmethod
|
31
35
|
def get_path(self, path: str) -> "FSPath":
|
32
36
|
pass
|
@@ -51,6 +55,9 @@ class RealFileSystem(FileSystem):
|
|
51
55
|
def __init__(self) -> None:
|
52
56
|
super().__init__()
|
53
57
|
|
58
|
+
def ls(self, path: Path | str) -> list[str]:
|
59
|
+
return [str(p) for p in Path(path).iterdir()]
|
60
|
+
|
54
61
|
def copy(self, src: Path | str, dest: Path | str) -> None:
|
55
62
|
shutil.copy(str(src), str(dest))
|
56
63
|
|
@@ -110,6 +117,24 @@ class RemoteFileSystem(FileSystem):
|
|
110
117
|
def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
|
111
118
|
raise NotImplementedError("RemoteFileSystem does not support mkdir")
|
112
119
|
|
120
|
+
def is_dir(self, path: Path | str) -> bool:
|
121
|
+
path = self._to_str(path)
|
122
|
+
err = self.server.list(path)
|
123
|
+
return isinstance(err, list)
|
124
|
+
|
125
|
+
def is_file(self, path: Path | str) -> bool:
|
126
|
+
path = self._to_str(path)
|
127
|
+
err = self.server.list(path)
|
128
|
+
# Make faster.
|
129
|
+
return isinstance(err, Exception) and self.exists(path)
|
130
|
+
|
131
|
+
def ls(self, path: Path | str) -> list[str]:
|
132
|
+
path = self._to_str(path)
|
133
|
+
err = self.server.list(path)
|
134
|
+
if isinstance(err, Exception):
|
135
|
+
raise FileNotFoundError(f"File not found: {path}, because of {err}")
|
136
|
+
return err
|
137
|
+
|
113
138
|
def get_path(self, path: str) -> "FSPath":
|
114
139
|
return FSPath(self, path)
|
115
140
|
|
@@ -125,8 +150,8 @@ class RemoteFileSystem(FileSystem):
|
|
125
150
|
|
126
151
|
class FSPath:
|
127
152
|
def __init__(self, fs: FileSystem, path: str) -> None:
|
128
|
-
self.path = path
|
129
153
|
self.fs = fs
|
154
|
+
self.path = path
|
130
155
|
|
131
156
|
def read_text(self) -> str:
|
132
157
|
return self.fs.read_text(self.path)
|
@@ -155,6 +180,10 @@ class FSPath:
|
|
155
180
|
assert isinstance(self.fs, RealFileSystem)
|
156
181
|
shutil.rmtree(self.path, ignore_errors=ignore_errors)
|
157
182
|
|
183
|
+
def ls(self) -> "list[FSPath]":
|
184
|
+
names: list[str] = self.fs.ls(self.path)
|
185
|
+
return [self / name for name in names]
|
186
|
+
|
158
187
|
@property
|
159
188
|
def name(self) -> str:
|
160
189
|
return Path(self.path).name
|
@@ -168,3 +197,7 @@ class FSPath:
|
|
168
197
|
def __truediv__(self, other: str) -> "FSPath":
|
169
198
|
new_path = Path(self.path) / other
|
170
199
|
return FSPath(self.fs, new_path.as_posix())
|
200
|
+
|
201
|
+
# hashable
|
202
|
+
def __hash__(self) -> int:
|
203
|
+
return hash(f"{repr(self.fs)}:{self.path}")
|
rclone_api/http_server.py
CHANGED
@@ -11,6 +11,7 @@ from threading import Semaphore
|
|
11
11
|
from typing import Any
|
12
12
|
|
13
13
|
import httpx
|
14
|
+
from bs4 import BeautifulSoup
|
14
15
|
|
15
16
|
from rclone_api.file_part import FilePart
|
16
17
|
from rclone_api.process import Process
|
@@ -23,6 +24,25 @@ _PUT_WARNED = False
|
|
23
24
|
_range = range
|
24
25
|
|
25
26
|
|
27
|
+
def _parse_files(html: str) -> list[str]:
|
28
|
+
soup = BeautifulSoup(html, "html.parser")
|
29
|
+
files = []
|
30
|
+
# Find each table row with class "file"
|
31
|
+
for tr in soup.find_all("tr", class_="file"):
|
32
|
+
name_span = tr.find("span", class_="name") # type: ignore
|
33
|
+
if not name_span:
|
34
|
+
continue
|
35
|
+
a_tag = name_span.find("a") # type: ignore
|
36
|
+
if not a_tag:
|
37
|
+
continue
|
38
|
+
# Get the text from the <a> tag
|
39
|
+
file_name = a_tag.get_text(strip=True) # type: ignore
|
40
|
+
# Skip directories (they end with a slash)
|
41
|
+
if not file_name.endswith("/"):
|
42
|
+
files.append(file_name)
|
43
|
+
return files
|
44
|
+
|
45
|
+
|
26
46
|
class HttpServer:
|
27
47
|
"""HTTP server configuration."""
|
28
48
|
|
@@ -103,6 +123,24 @@ class HttpServer:
|
|
103
123
|
warnings.warn(f"Failed to remove {path} from {self.url}: {e}")
|
104
124
|
return e
|
105
125
|
|
126
|
+
# curl "http://localhost:5572/?list"
|
127
|
+
|
128
|
+
def list(self, path: str) -> list[str] | Exception:
|
129
|
+
"""List files on the server."""
|
130
|
+
|
131
|
+
try:
|
132
|
+
assert self.process is not None
|
133
|
+
url = self.url
|
134
|
+
if path:
|
135
|
+
url += f"/{path}"
|
136
|
+
url += "/?list"
|
137
|
+
response = httpx.get(url)
|
138
|
+
response.raise_for_status()
|
139
|
+
return _parse_files(response.content.decode())
|
140
|
+
except Exception as e:
|
141
|
+
warnings.warn(f"Failed to list files on {self.url}: {e}")
|
142
|
+
return e
|
143
|
+
|
106
144
|
def download(
|
107
145
|
self, path: str, dst: Path, range: Range | None = None
|
108
146
|
) -> Path | Exception:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: rclone_api
|
3
|
-
Version: 1.5.
|
3
|
+
Version: 1.5.17
|
4
4
|
Summary: rclone api in python
|
5
5
|
Home-page: https://github.com/zackees/rclone-api
|
6
6
|
License: BSD 3-Clause License
|
@@ -19,6 +19,7 @@ Requires-Dist: psycopg2-binary>=2.9.10
|
|
19
19
|
Requires-Dist: httpx>=0.28.1
|
20
20
|
Requires-Dist: download>=0.3.5
|
21
21
|
Requires-Dist: appdirs>=1.4.4
|
22
|
+
Requires-Dist: beautifulsoup4>=4.13.3
|
22
23
|
Dynamic: home-page
|
23
24
|
Dynamic: license-file
|
24
25
|
|
@@ -13,9 +13,9 @@ rclone_api/file_item.py,sha256=cH-AQYsxedhNPp4c8NHY1ad4Z7St4yf_VGbmiGD59no,1770
|
|
13
13
|
rclone_api/file_part.py,sha256=i6ByS5_sae8Eba-4imBVTxd-xKC8ExWy7NR8QGr0ors,6155
|
14
14
|
rclone_api/file_stream.py,sha256=_W3qnwCuigqA0hzXl2q5pAxSZDRaUSwet4BkT0lpnzs,1431
|
15
15
|
rclone_api/filelist.py,sha256=xbiusvNgaB_b_kQOZoHMJJxn6TWGtPrWd2J042BI28o,767
|
16
|
-
rclone_api/filesystem.py,sha256=
|
16
|
+
rclone_api/filesystem.py,sha256=QPERBMxrTWNaWMxuHu5QnbRLF5eoSYDODNpjhD8K694,6008
|
17
17
|
rclone_api/group_files.py,sha256=H92xPW9lQnbNw5KbtZCl00bD6iRh9yRbCuxku4j_3dg,8036
|
18
|
-
rclone_api/http_server.py,sha256=
|
18
|
+
rclone_api/http_server.py,sha256=ZdL-rGaq0zIjcaIiRIbPBQ4OIWZ7dCu71aq0nRlKtY4,11686
|
19
19
|
rclone_api/install.py,sha256=Xb1BRn8rQcSpSd4dzmvIOELP2zM2DytUeIZ6jzv738A,2893
|
20
20
|
rclone_api/log.py,sha256=VZHM7pNSXip2ZLBKMP7M1u-rp_F7zoafFDuR8CPUoKI,1271
|
21
21
|
rclone_api/mount.py,sha256=LZqEhuKZunbWVqmsOIqkkCotaxWJpdFRS1InXveoU5E,1428
|
@@ -54,9 +54,9 @@ rclone_api/s3/multipart/upload_parts_inline.py,sha256=V7syKjFyVIe4U9Ahl5XgqVTzt9
|
|
54
54
|
rclone_api/s3/multipart/upload_parts_resumable.py,sha256=6-nlMclS8jyVvMvFbQDcZOX9MY1WbCcKA_s9bwuYxnk,9793
|
55
55
|
rclone_api/s3/multipart/upload_parts_server_side_merge.py,sha256=Fp2pdrs5dONQI9LkfNolgAGj1-Z2V1SsRd0r0sreuXI,18040
|
56
56
|
rclone_api/s3/multipart/upload_state.py,sha256=f-Aq2NqtAaMUMhYitlICSNIxCKurWAl2gDEUVizLIqw,6019
|
57
|
-
rclone_api-1.5.
|
58
|
-
rclone_api-1.5.
|
59
|
-
rclone_api-1.5.
|
60
|
-
rclone_api-1.5.
|
61
|
-
rclone_api-1.5.
|
62
|
-
rclone_api-1.5.
|
57
|
+
rclone_api-1.5.17.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
58
|
+
rclone_api-1.5.17.dist-info/METADATA,sha256=BkNxUxGH2-ZTFkBL2vfpCEf03jm8IVizA0uuzDh6gDQ,32696
|
59
|
+
rclone_api-1.5.17.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
60
|
+
rclone_api-1.5.17.dist-info/entry_points.txt,sha256=fJteOlYVwgX3UbNuL9jJ0zUTuX2O79JFAeNgK7Sw7EQ,255
|
61
|
+
rclone_api-1.5.17.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
|
62
|
+
rclone_api-1.5.17.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|