rclone-api 1.0.12__py2.py3-none-any.whl → 1.0.13__py2.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/dir.py CHANGED
@@ -8,6 +8,10 @@ from rclone_api.rpath import RPath
8
8
  class Dir:
9
9
  """Remote file dataclass."""
10
10
 
11
+ @property
12
+ def remote(self) -> Remote:
13
+ return self.path.remote
14
+
11
15
  def __init__(self, path: RPath | Remote) -> None:
12
16
  """Initialize Dir with either an RPath or Remote.
13
17
 
@@ -17,6 +21,7 @@ class Dir:
17
21
  if isinstance(path, Remote):
18
22
  # Need to create an RPath for the Remote's root
19
23
  self.path = RPath(
24
+ remote=path,
20
25
  path=str(path),
21
26
  name=str(path),
22
27
  size=0,
@@ -32,7 +37,8 @@ class Dir:
32
37
  def ls(self, max_depth: int = 0) -> DirListing:
33
38
  """List files and directories in the given path."""
34
39
  assert self.path.rclone is not None
35
- return self.path.rclone.ls(self.path.path, max_depth=max_depth)
40
+ dir = Dir(self.path)
41
+ return self.path.rclone.ls(dir, max_depth=max_depth)
36
42
 
37
43
  def walk(self, max_depth: int = -1) -> Generator[DirListing, None, None]:
38
44
  """List files and directories in the given path."""
rclone_api/file.py CHANGED
@@ -1,5 +1,3 @@
1
- import json
2
-
3
1
  from rclone_api.rpath import RPath
4
2
 
5
3
 
@@ -31,5 +29,4 @@ class File:
31
29
  return result.stdout
32
30
 
33
31
  def __str__(self) -> str:
34
- out = self.path.to_json()
35
- return json.dumps(out)
32
+ return str(self.path)
rclone_api/rclone.py CHANGED
@@ -1,90 +1,97 @@
1
- """
2
- Unit test file.
3
- """
4
-
5
- import subprocess
6
- from pathlib import Path
7
- from typing import Generator
8
-
9
- from rclone_api import Dir
10
- from rclone_api.dir_listing import DirListing
11
- from rclone_api.remote import Remote
12
- from rclone_api.rpath import RPath
13
- from rclone_api.types import Config, RcloneExec
14
- from rclone_api.util import get_rclone_exe
15
- from rclone_api.walk import walk
16
-
17
-
18
- class Rclone:
19
- def __init__(
20
- self, rclone_conf: Path | Config, rclone_exe: Path | None = None
21
- ) -> None:
22
- if isinstance(rclone_conf, Path):
23
- if not rclone_conf.exists():
24
- raise ValueError(f"Rclone config file not found: {rclone_conf}")
25
- self._exec = RcloneExec(rclone_conf, get_rclone_exe(rclone_exe))
26
-
27
- def _run(self, cmd: list[str]) -> subprocess.CompletedProcess:
28
- return self._exec.execute(cmd)
29
-
30
- def ls(self, path: str | Remote, max_depth: int = 0) -> DirListing:
31
- """List files in the given path.
32
-
33
- Args:
34
- path: Remote path or Remote object to list
35
- max_depth: Maximum recursion depth (0 means no recursion)
36
-
37
- Returns:
38
- List of File objects found at the path
39
- """
40
- cmd = ["lsjson"]
41
- if max_depth > 0:
42
- cmd.extend(["--recursive", "--max-depth", str(max_depth)])
43
- cmd.append(str(path))
44
-
45
- cp = self._run(cmd)
46
- text = cp.stdout
47
- paths: list[RPath] = RPath.from_json_str(text)
48
- for o in paths:
49
- o.set_rclone(self)
50
- return DirListing(paths)
51
-
52
- def listremotes(self) -> list[Remote]:
53
- cmd = ["listremotes"]
54
- cp = self._run(cmd)
55
- text: str = cp.stdout
56
- tmp = text.splitlines()
57
- tmp = [t.strip() for t in tmp]
58
- # strip out ":" from the end
59
- tmp = [t.replace(":", "") for t in tmp]
60
- out = [Remote(name=t, rclone=self) for t in tmp]
61
- return out
62
-
63
- def walk(
64
- self, path: str | Remote, max_depth: int = -1
65
- ) -> Generator[DirListing, None, None]:
66
- """Walk through the given path recursively.
67
-
68
- Args:
69
- path: Remote path or Remote object to walk through
70
- max_depth: Maximum depth to traverse (-1 for unlimited)
71
-
72
- Yields:
73
- DirListing: Directory listing for each directory encountered
74
- """
75
- if isinstance(path, str):
76
- # Create a Remote object for the path
77
- rpath = RPath(
78
- path=path,
79
- name=path,
80
- size=0,
81
- mime_type="inode/directory",
82
- mod_time="",
83
- is_dir=True,
84
- )
85
- rpath.set_rclone(self)
86
- dir_obj = Dir(rpath)
87
- else:
88
- dir_obj = Dir(path)
89
-
90
- yield from walk(dir_obj, max_depth=max_depth)
1
+ """
2
+ Unit test file.
3
+ """
4
+
5
+ import subprocess
6
+ from pathlib import Path
7
+ from typing import Generator
8
+
9
+ from rclone_api import Dir
10
+ from rclone_api.dir_listing import DirListing
11
+ from rclone_api.remote import Remote
12
+ from rclone_api.rpath import RPath
13
+ from rclone_api.types import Config, RcloneExec
14
+ from rclone_api.util import get_rclone_exe
15
+ from rclone_api.walk import walk
16
+
17
+
18
+ class Rclone:
19
+ def __init__(
20
+ self, rclone_conf: Path | Config, rclone_exe: Path | None = None
21
+ ) -> None:
22
+ if isinstance(rclone_conf, Path):
23
+ if not rclone_conf.exists():
24
+ raise ValueError(f"Rclone config file not found: {rclone_conf}")
25
+ self._exec = RcloneExec(rclone_conf, get_rclone_exe(rclone_exe))
26
+
27
+ def _run(self, cmd: list[str]) -> subprocess.CompletedProcess:
28
+ return self._exec.execute(cmd)
29
+
30
+ def ls(self, path: Dir | Remote | str, max_depth: int | None = None) -> DirListing:
31
+ """List files in the given path.
32
+
33
+ Args:
34
+ path: Remote path or Remote object to list
35
+ max_depth: Maximum recursion depth (0 means no recursion)
36
+
37
+ Returns:
38
+ List of File objects found at the path
39
+ """
40
+ cmd = ["lsjson"]
41
+ if max_depth is not None:
42
+ cmd.append("--recursive")
43
+ if max_depth > -1:
44
+ cmd.append("--max-depth")
45
+ cmd.append(str(max_depth))
46
+ cmd.append(str(path))
47
+ remote = path.remote if isinstance(path, Dir) else path
48
+ assert isinstance(remote, Remote)
49
+
50
+ cp = self._run(cmd)
51
+ text = cp.stdout
52
+ paths: list[RPath] = RPath.from_json_str(text, remote)
53
+ for o in paths:
54
+ o.set_rclone(self)
55
+ return DirListing(paths)
56
+
57
+ def listremotes(self) -> list[Remote]:
58
+ cmd = ["listremotes"]
59
+ cp = self._run(cmd)
60
+ text: str = cp.stdout
61
+ tmp = text.splitlines()
62
+ tmp = [t.strip() for t in tmp]
63
+ # strip out ":" from the end
64
+ tmp = [t.replace(":", "") for t in tmp]
65
+ out = [Remote(name=t, rclone=self) for t in tmp]
66
+ return out
67
+
68
+ def walk(
69
+ self, path: Dir | Remote, max_depth: int = -1
70
+ ) -> Generator[DirListing, None, None]:
71
+ """Walk through the given path recursively.
72
+
73
+ Args:
74
+ path: Remote path or Remote object to walk through
75
+ max_depth: Maximum depth to traverse (-1 for unlimited)
76
+
77
+ Yields:
78
+ DirListing: Directory listing for each directory encountered
79
+ """
80
+ if isinstance(path, Dir):
81
+ # Create a Remote object for the path
82
+ remote = path.remote
83
+ rpath = RPath(
84
+ remote=remote,
85
+ path=path.path.path,
86
+ name=path.path.name,
87
+ size=0,
88
+ mime_type="inode/directory",
89
+ mod_time="",
90
+ is_dir=True,
91
+ )
92
+ rpath.set_rclone(self)
93
+ dir_obj = Dir(rpath)
94
+ else:
95
+ dir_obj = Dir(path)
96
+
97
+ yield from walk(dir_obj, max_depth=max_depth)
rclone_api/rpath.py CHANGED
@@ -1,12 +1,15 @@
1
1
  import json
2
2
  from typing import Any
3
3
 
4
+ from rclone_api.remote import Remote
5
+
4
6
 
5
7
  class RPath:
6
8
  """Remote file dataclass."""
7
9
 
8
10
  def __init__(
9
11
  self,
12
+ remote: Remote,
10
13
  path: str,
11
14
  name: str,
12
15
  size: int,
@@ -16,6 +19,10 @@ class RPath:
16
19
  ) -> None:
17
20
  from rclone_api.rclone import Rclone
18
21
 
22
+ if "dst:" in path:
23
+ raise ValueError(f"Invalid path: {path}")
24
+
25
+ self.remote = remote
19
26
  self.path = path
20
27
  self.name = name
21
28
  self.size = size
@@ -32,9 +39,10 @@ class RPath:
32
39
  self.rclone = rclone
33
40
 
34
41
  @staticmethod
35
- def from_dict(data: dict) -> "RPath":
42
+ def from_dict(data: dict, remote: Remote) -> "RPath":
36
43
  """Create a File from a dictionary."""
37
44
  return RPath(
45
+ remote,
38
46
  data["Path"],
39
47
  data["Name"],
40
48
  data["Size"],
@@ -45,21 +53,21 @@ class RPath:
45
53
  )
46
54
 
47
55
  @staticmethod
48
- def from_array(data: list[dict]) -> list["RPath"]:
56
+ def from_array(data: list[dict], remote: Remote) -> list["RPath"]:
49
57
  """Create a File from a dictionary."""
50
58
  out: list[RPath] = []
51
59
  for d in data:
52
- file: RPath = RPath.from_dict(d)
60
+ file: RPath = RPath.from_dict(d, remote)
53
61
  out.append(file)
54
62
  return out
55
63
 
56
64
  @staticmethod
57
- def from_json_str(json_str: str) -> list["RPath"]:
65
+ def from_json_str(json_str: str, remote: Remote) -> list["RPath"]:
58
66
  """Create a File from a JSON string."""
59
67
  json_obj = json.loads(json_str)
60
68
  if isinstance(json_obj, dict):
61
- return [RPath.from_dict(json_obj)]
62
- return RPath.from_array(json_obj)
69
+ return [RPath.from_dict(json_obj, remote)]
70
+ return RPath.from_array(json_obj, remote)
63
71
 
64
72
  def to_json(self) -> dict:
65
73
  return {
@@ -73,5 +81,4 @@ class RPath:
73
81
  }
74
82
 
75
83
  def __str__(self) -> str:
76
- out = self.to_json()
77
- return json.dumps(out)
84
+ return f"{self.remote.name}:{self.path}"
rclone_api/util.py CHANGED
@@ -1,10 +1,61 @@
1
+ import os
1
2
  import shutil
2
3
  import subprocess
3
4
  from pathlib import Path
4
5
  from tempfile import TemporaryDirectory
6
+ from typing import Any
5
7
 
8
+ from rclone_api.dir import Dir
9
+ from rclone_api.remote import Remote
10
+ from rclone_api.rpath import RPath
6
11
  from rclone_api.types import Config
7
12
 
13
+ # from .rclone import Rclone
14
+
15
+
16
+ def to_path(item: Dir | Remote | str, rclone: Any) -> RPath:
17
+ from rclone_api.rclone import Rclone
18
+
19
+ assert isinstance(rclone, Rclone)
20
+ # if str then it will be remote:path
21
+ if isinstance(item, str):
22
+ # return RPath(item)
23
+ # remote_name: str = item.split(":")[0]
24
+ parts = item.split(":")
25
+ remote_name = parts[0]
26
+ path = ":".join(parts[1:])
27
+ remote = Remote(name=remote_name, rclone=rclone)
28
+ return RPath(
29
+ remote=remote,
30
+ path=path,
31
+ name="",
32
+ size=0,
33
+ mime_type="",
34
+ mod_time="",
35
+ is_dir=True,
36
+ )
37
+ elif isinstance(item, Dir):
38
+ return item.path
39
+ elif isinstance(item, Remote):
40
+ return RPath(
41
+ remote=item,
42
+ path=str(item),
43
+ name=str(item),
44
+ size=0,
45
+ mime_type="inode/directory",
46
+ mod_time="",
47
+ is_dir=True,
48
+ )
49
+ else:
50
+ raise ValueError(f"Invalid type for item: {type(item)}")
51
+
52
+
53
+ def _get_verbose(verbose: bool | None) -> bool:
54
+ if verbose is not None:
55
+ return verbose
56
+ # get it from the environment
57
+ return bool(int(os.getenv("RCLONE_API_VERBOSE", "0")))
58
+
8
59
 
9
60
  def get_rclone_exe(rclone_exe: Path | None) -> Path:
10
61
  if rclone_exe is None:
@@ -20,10 +71,11 @@ def rclone_execute(
20
71
  cmd: list[str],
21
72
  rclone_conf: Path | Config,
22
73
  rclone_exe: Path,
23
- verbose: bool = False,
74
+ verbose: bool | None = None,
24
75
  ) -> subprocess.CompletedProcess:
25
- print(subprocess.list2cmdline(cmd))
26
76
  tempdir: TemporaryDirectory | None = None
77
+ verbose = _get_verbose(verbose)
78
+ assert verbose is not None
27
79
 
28
80
  try:
29
81
  if isinstance(rclone_conf, Config):
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.2
2
+ Name: rclone_api
3
+ Version: 1.0.13
4
+ Summary: rclone api in python
5
+ Home-page: https://github.com/zackees/rclone-api
6
+ Maintainer: Zachary Vorhies
7
+ License: BSD 3-Clause License
8
+ Keywords: template-python-cmd
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: python-dotenv>=1.0.0
14
+ Dynamic: home-page
15
+ Dynamic: maintainer
16
+
17
+ # rclone-api
18
+
19
+ [![Linting](https://github.com/zackees/rclone-api/actions/workflows/lint.yml/badge.svg)](https://github.com/zackees/rclone-api/actions/workflows/lint.yml)
20
+ [![MacOS_Tests](https://github.com/zackees/rclone-api/actions/workflows/push_macos.yml/badge.svg)](https://github.com/zackees/rclone-api/actions/workflows/push_macos.yml)
21
+ [![Ubuntu_Tests](https://github.com/zackees/rclone-api/actions/workflows/push_ubuntu.yml/badge.svg)](https://github.com/zackees/rclone-api/actions/workflows/push_ubuntu.yml)
22
+ [![Win_Tests](https://github.com/zackees/rclone-api/actions/workflows/push_win.yml/badge.svg)](https://github.com/zackees/rclone-api/actions/workflows/push_win.yml)
23
+
24
+ Api version of rclone. It's well tested. It's just released so this readme is a little to be desired.
25
+
26
+ To develop software, run `. ./activate`
27
+
28
+ # Windows
29
+
30
+ This environment requires you to use `git-bash`.
31
+
32
+ # Linting
33
+
34
+ Run `./lint`
@@ -1,18 +1,18 @@
1
1
  rclone_api/__init__.py,sha256=YH7KQaPwUiJWJiRf0NRKD7XHhMXsxWdXDjt9WLSwdjA,265
2
2
  rclone_api/cli.py,sha256=dibfAZIh0kXWsBbfp3onKLjyZXo54mTzDjUdzJlDlWo,231
3
3
  rclone_api/config.py,sha256=UujjDNcpwgipgdyFPMhC3zikvlsrurUvvZiwXm5NlPg,471
4
- rclone_api/dir.py,sha256=rd40egerhoKGAdIKfeGh_P70fSDzMo-EiTl0euABGOU,1497
4
+ rclone_api/dir.py,sha256=tu0-Yy1s3O1MVY7Nkb6NOh6t9dXJ9DQvqOZVlWIexrI,1629
5
5
  rclone_api/dir_listing.py,sha256=NWleKHCCRW7_eh9JfRwE6r3QbjmiHD5ZEGQcd2vm4uY,458
6
- rclone_api/file.py,sha256=409neYPfCUKQX2w7Uw7_D0wR2PtH42srNe9u_nnOLxM,925
7
- rclone_api/rclone.py,sha256=EUsLW5qcipI5RzhpHUd0PQqQow43m2uKJmNgVR8ZBuU,2859
6
+ rclone_api/file.py,sha256=nJwJT7v2KwY_8g7UB3Y7O6pFfHn3nri9dJ3GS-cN3EE,874
7
+ rclone_api/rclone.py,sha256=upMqUxYKC3LCjHlhI66_IdOD1t5PKo7V64sSdw0vAlk,3074
8
8
  rclone_api/remote.py,sha256=c9hlRKBCg1BFB9MCINaQIoCg10qyAkeqiS4brl8ce-8,343
9
- rclone_api/rpath.py,sha256=_k59z-O75hAhpPyUSH4glPEoiYtIS3RUQb7ltU9Ianw,2009
9
+ rclone_api/rpath.py,sha256=QHD5zDjDIkivs3kCRYtTL8mP-DspXIvBVYWHSf_Y6Rg,2263
10
10
  rclone_api/types.py,sha256=Yp15HrjwZonSQhE323R0WP7fA4NWqKjAfM7z3OwHpWI,518
11
- rclone_api/util.py,sha256=EXnijLLdFHqwoZvHrZdqeM8r6T7ad9-pN7qBN1b0I_g,1465
11
+ rclone_api/util.py,sha256=xYUj0B9W5HDauTHh7Z8cnEQsTEuXvRcVNLtk3ZanlGM,2894
12
12
  rclone_api/walk.py,sha256=3GKnu9P5aPNiftfoi52U7wo1wixZxwxdqqS0_IlMGCE,2816
13
13
  rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
14
- rclone_api-1.0.12.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
15
- rclone_api-1.0.12.dist-info/METADATA,sha256=fkbaFAbZssh_WIKBJs-M1VNNUf3o3YKcEo3wIYDGO8o,1245
16
- rclone_api-1.0.12.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
17
- rclone_api-1.0.12.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
18
- rclone_api-1.0.12.dist-info/RECORD,,
14
+ rclone_api-1.0.13.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
15
+ rclone_api-1.0.13.dist-info/METADATA,sha256=yEL4GNzAc-CwJt-rJVmDAl08L13RqytSSs1ZQR4KMA0,1375
16
+ rclone_api-1.0.13.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
17
+ rclone_api-1.0.13.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
18
+ rclone_api-1.0.13.dist-info/RECORD,,
@@ -1,36 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: rclone_api
3
- Version: 1.0.12
4
- Summary: rclone api in python
5
- Home-page: https://github.com/zackees/rclone-api
6
- Maintainer: Zachary Vorhies
7
- License: BSD 3-Clause License
8
- Keywords: template-python-cmd
9
- Classifier: Programming Language :: Python :: 3
10
- Requires-Python: >=3.7
11
- Description-Content-Type: text/markdown
12
- License-File: LICENSE
13
- Dynamic: home-page
14
- Dynamic: maintainer
15
-
16
- # template-python-cmd
17
- A template for quickly making a python lib that has a command line program attached
18
-
19
- [![Linting](../../actions/workflows/lint.yml/badge.svg)](../../actions/workflows/lint.yml)
20
-
21
- [![MacOS_Tests](../../actions/workflows/push_macos.yml/badge.svg)](../../actions/workflows/push_macos.yml)
22
- [![Ubuntu_Tests](../../actions/workflows/push_ubuntu.yml/badge.svg)](../../actions/workflows/push_ubuntu.yml)
23
- [![Win_Tests](../../actions/workflows/push_win.yml/badge.svg)](../../actions/workflows/push_win.yml)
24
-
25
- Replace `template-python-cmd` and `template_python_cmd` with your command. Run tox until it's
26
- correct.
27
-
28
- To develop software, run `. ./activate.sh`
29
-
30
- # Windows
31
-
32
- This environment requires you to use `git-bash`.
33
-
34
- # Linting
35
-
36
- Run `./lint.sh` to find linting errors using `pylint`, `flake8` and `mypy`.