rclone-api 1.5.15__py3-none-any.whl → 1.5.18__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 CHANGED
@@ -2,6 +2,8 @@ import abc
2
2
  import shutil
3
3
  from pathlib import Path
4
4
 
5
+ from rclone_api.config import Config
6
+
5
7
 
6
8
  class FileSystem(abc.ABC):
7
9
  def __init__(self) -> None:
@@ -27,6 +29,14 @@ class FileSystem(abc.ABC):
27
29
  def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
28
30
  pass
29
31
 
32
+ @abc.abstractmethod
33
+ def ls(self, path: Path | str) -> list[str]:
34
+ pass
35
+
36
+ @abc.abstractmethod
37
+ def cwd(self) -> "FSPath":
38
+ pass
39
+
30
40
  @abc.abstractmethod
31
41
  def get_path(self, path: str) -> "FSPath":
32
42
  pass
@@ -41,16 +51,22 @@ class FileSystem(abc.ABC):
41
51
  self.write_binary(path, utf)
42
52
 
43
53
 
44
- class RealFileSystem(FileSystem):
54
+ class RealFS(FileSystem):
45
55
 
46
56
  @staticmethod
47
- def get_real_path(path: Path | str) -> "FSPath":
57
+ def from_path(path: Path | str) -> "FSPath":
48
58
  path_str = Path(path).as_posix()
49
- return FSPath(RealFileSystem(), path_str)
59
+ return FSPath(RealFS(), path_str)
50
60
 
51
61
  def __init__(self) -> None:
52
62
  super().__init__()
53
63
 
64
+ def ls(self, path: Path | str) -> list[str]:
65
+ return [str(p) for p in Path(path).iterdir()]
66
+
67
+ def cwd(self) -> "FSPath":
68
+ return RealFS.from_path(Path.cwd())
69
+
54
70
  def copy(self, src: Path | str, dest: Path | str) -> None:
55
71
  shutil.copy(str(src), str(dest))
56
72
 
@@ -72,8 +88,8 @@ class RealFileSystem(FileSystem):
72
88
  return FSPath(self, path)
73
89
 
74
90
 
75
- class RemoteFileSystem(FileSystem):
76
- def __init__(self, rclone_conf: Path, src: str) -> None:
91
+ class RemoteFS(FileSystem):
92
+ def __init__(self, rclone_conf: Path | Config, src: str) -> None:
77
93
  from rclone_api import HttpServer, Rclone
78
94
 
79
95
  super().__init__()
@@ -82,6 +98,12 @@ class RemoteFileSystem(FileSystem):
82
98
  self.server: HttpServer = self.rclone.serve_http(src=src)
83
99
  self.shutdown = False
84
100
 
101
+ def root(self) -> "FSPath":
102
+ return FSPath(self, "")
103
+
104
+ def cwd(self) -> "FSPath":
105
+ return self.root()
106
+
85
107
  def _to_str(self, path: Path | str) -> str:
86
108
  if isinstance(path, Path):
87
109
  return path.as_posix()
@@ -108,7 +130,25 @@ class RemoteFileSystem(FileSystem):
108
130
  return self.server.exists(path)
109
131
 
110
132
  def mkdir(self, path: str, parents=True, exist_ok=True) -> None:
111
- raise NotImplementedError("RemoteFileSystem does not support mkdir")
133
+ raise NotImplementedError("RemoteFS does not support mkdir")
134
+
135
+ def is_dir(self, path: Path | str) -> bool:
136
+ path = self._to_str(path)
137
+ err = self.server.list(path)
138
+ return isinstance(err, list)
139
+
140
+ def is_file(self, path: Path | str) -> bool:
141
+ path = self._to_str(path)
142
+ err = self.server.list(path)
143
+ # Make faster.
144
+ return isinstance(err, Exception) and self.exists(path)
145
+
146
+ def ls(self, path: Path | str) -> list[str]:
147
+ path = self._to_str(path)
148
+ err = self.server.list(path)
149
+ if isinstance(err, Exception):
150
+ raise FileNotFoundError(f"File not found: {path}, because of {err}")
151
+ return err
112
152
 
113
153
  def get_path(self, path: str) -> "FSPath":
114
154
  return FSPath(self, path)
@@ -151,10 +191,14 @@ class FSPath:
151
191
 
152
192
  def rmtree(self, ignore_errors=False) -> None:
153
193
  assert self.exists(), f"Path does not exist: {self.path}"
154
- # check fs is RealFileSystem
155
- assert isinstance(self.fs, RealFileSystem)
194
+ # check fs is RealFS
195
+ assert isinstance(self.fs, RealFS)
156
196
  shutil.rmtree(self.path, ignore_errors=ignore_errors)
157
197
 
198
+ def ls(self) -> "list[FSPath]":
199
+ names: list[str] = self.fs.ls(self.path)
200
+ return [self / name for name in names]
201
+
158
202
  @property
159
203
  def name(self) -> str:
160
204
  return Path(self.path).name
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:
rclone_api/rclone_impl.py CHANGED
@@ -26,6 +26,7 @@ from rclone_api.dir_listing import DirListing
26
26
  from rclone_api.exec import RcloneExec
27
27
  from rclone_api.file import File
28
28
  from rclone_api.file_stream import FilesStream
29
+ from rclone_api.filesystem import RemoteFS
29
30
  from rclone_api.group_files import group_files
30
31
  from rclone_api.http_server import HttpServer
31
32
  from rclone_api.mount import Mount
@@ -103,6 +104,9 @@ class RcloneImpl:
103
104
  cmd += other_args
104
105
  return self._launch_process(cmd, capture=False)
105
106
 
107
+ def filesystem(self, src: str) -> RemoteFS:
108
+ return RemoteFS(self.config, src)
109
+
106
110
  def launch_server(
107
111
  self,
108
112
  addr: str,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rclone_api
3
- Version: 1.5.15
3
+ Version: 1.5.18
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,15 +13,15 @@ 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=kXhsa4Zi3cvRJz04BiKTYeDC67sRXDLl83MLkIL1BKU,5059
16
+ rclone_api/filesystem.py,sha256=htF2dF6v-tkiqyTj4BnDm3Ctn5seXZ2tiUFjSrMLOq8,6272
17
17
  rclone_api/group_files.py,sha256=H92xPW9lQnbNw5KbtZCl00bD6iRh9yRbCuxku4j_3dg,8036
18
- rclone_api/http_server.py,sha256=p1_S9VAViVvGif6NA_rxrDgMqnOmPTxJaHQ7B43FK70,10431
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
22
22
  rclone_api/mount_util.py,sha256=jqhJEVTHV6c6lOOzUYb4FLMbqDMHdz7-QRcdH-IobFc,10154
23
23
  rclone_api/process.py,sha256=MeWiN-TrrN0HmtWexBPxGwf84z6f-_E5yaXE-YtLYpY,5879
24
- rclone_api/rclone_impl.py,sha256=STHQ_hT0chyp2yj3Cp-Vd0xXc1Pdpo3p9J3bTQEm0XE,46531
24
+ rclone_api/rclone_impl.py,sha256=qIvd9qcKsdD7l9_d3Thy5nJUD9xX4MAlOMekWb1NPhg,46665
25
25
  rclone_api/remote.py,sha256=mTgMTQTwxUmbLjTpr-AGTId2ycXKI9mLX5L7PPpDIoc,520
26
26
  rclone_api/rpath.py,sha256=Y1JjQWcie39EgQrq-UtbfDz5yDLCwwfu27W7AQXllSE,2860
27
27
  rclone_api/scan_missing_folders.py,sha256=-8NCwpCaHeHrX-IepCoAEsX1rl8S-GOCxcIhTr_w3gA,4747
@@ -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.15.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
58
- rclone_api-1.5.15.dist-info/METADATA,sha256=0yttTQSrSLAcr1BPQVkfojQ4L67pAgvDv6FgvlLZVVU,32657
59
- rclone_api-1.5.15.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
60
- rclone_api-1.5.15.dist-info/entry_points.txt,sha256=fJteOlYVwgX3UbNuL9jJ0zUTuX2O79JFAeNgK7Sw7EQ,255
61
- rclone_api-1.5.15.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
62
- rclone_api-1.5.15.dist-info/RECORD,,
57
+ rclone_api-1.5.18.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
58
+ rclone_api-1.5.18.dist-info/METADATA,sha256=u0TSArQPF3xtUyFdUbZ84vfgNoaZxv3Bx-RklZlvi9g,32696
59
+ rclone_api-1.5.18.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
60
+ rclone_api-1.5.18.dist-info/entry_points.txt,sha256=fJteOlYVwgX3UbNuL9jJ0zUTuX2O79JFAeNgK7Sw7EQ,255
61
+ rclone_api-1.5.18.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
62
+ rclone_api-1.5.18.dist-info/RECORD,,