rclone-api 1.0.21__tar.gz → 1.0.23__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {rclone_api-1.0.21 → rclone_api-1.0.23}/PKG-INFO +1 -1
- {rclone_api-1.0.21 → rclone_api-1.0.23}/pyproject.toml +4 -1
- rclone_api-1.0.23/src/rclone_api/cmd/list_files.py +27 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/rclone.py +3 -8
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/util.py +15 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api.egg-info/PKG-INFO +1 -1
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api.egg-info/SOURCES.txt +3 -0
- rclone_api-1.0.23/src/rclone_api.egg-info/entry_points.txt +2 -0
- rclone_api-1.0.23/tests/test_cmd_list_files.py +83 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.aiderignore +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.github/workflows/lint.yml +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.github/workflows/push_macos.yml +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.github/workflows/push_ubuntu.yml +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.github/workflows/push_win.yml +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.gitignore +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.pylintrc +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.vscode/launch.json +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.vscode/settings.json +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/.vscode/tasks.json +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/LICENSE +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/MANIFEST.in +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/README.md +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/clean +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/install +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/lint +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/requirements.testing.txt +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/setup.cfg +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/setup.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/__init__.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/assets/example.txt +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/cli.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/config.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/convert.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/dir.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/dir_listing.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/exec.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/file.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/filelist.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/process.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/remote.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/rpath.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api/walk.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api.egg-info/dependency_links.txt +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api.egg-info/requires.txt +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/src/rclone_api.egg-info/top_level.txt +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/test +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tests/test_copy.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tests/test_is_synced.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tests/test_ls.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tests/test_mount.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tests/test_mount_webdav.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tests/test_obscure.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tests/test_remotes.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tests/test_serve_webdav.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tests/test_walk.py +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/tox.ini +0 -0
- {rclone_api-1.0.21 → rclone_api-1.0.23}/upload_package.sh +0 -0
@@ -15,7 +15,7 @@ dependencies = [
|
|
15
15
|
"python-dotenv>=1.0.0",
|
16
16
|
]
|
17
17
|
# Change this with the version number bump.
|
18
|
-
version = "1.0.
|
18
|
+
version = "1.0.23"
|
19
19
|
|
20
20
|
[tool.setuptools]
|
21
21
|
package-dir = {"" = "src"}
|
@@ -43,3 +43,6 @@ profile = "black"
|
|
43
43
|
[tool.mypy]
|
44
44
|
ignore_missing_imports = true
|
45
45
|
disable_error_code = ["import-untyped"]
|
46
|
+
|
47
|
+
[project.scripts]
|
48
|
+
rclone-api-listfiles = "rclone_api.cmd.list_files:main"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import argparse
|
2
|
+
from pathlib import Path
|
3
|
+
|
4
|
+
from rclone_api import Rclone
|
5
|
+
|
6
|
+
|
7
|
+
def list_files(rclone: Rclone, path: str):
|
8
|
+
"""List files in a remote path."""
|
9
|
+
for dirlisting in rclone.walk(path):
|
10
|
+
for file in dirlisting.files:
|
11
|
+
print(file.path)
|
12
|
+
|
13
|
+
|
14
|
+
def _parse_args() -> argparse.Namespace:
|
15
|
+
parser = argparse.ArgumentParser(description="List files in a remote path.")
|
16
|
+
parser.add_argument("--config", help="Path to rclone config file", required=True)
|
17
|
+
parser.add_argument("path", help="Remote path to list")
|
18
|
+
return parser.parse_args()
|
19
|
+
|
20
|
+
|
21
|
+
def main() -> int:
|
22
|
+
"""Main entry point."""
|
23
|
+
args = _parse_args()
|
24
|
+
path = args.path
|
25
|
+
rclone = Rclone(Path(args.config))
|
26
|
+
list_files(rclone, path)
|
27
|
+
return 0
|
@@ -19,7 +19,7 @@ from rclone_api.file import File
|
|
19
19
|
from rclone_api.process import Process
|
20
20
|
from rclone_api.remote import Remote
|
21
21
|
from rclone_api.rpath import RPath
|
22
|
-
from rclone_api.util import get_rclone_exe, to_path
|
22
|
+
from rclone_api.util import get_rclone_exe, to_path, wait_for_mount
|
23
23
|
from rclone_api.walk import walk
|
24
24
|
|
25
25
|
|
@@ -291,9 +291,7 @@ class Rclone:
|
|
291
291
|
if other_cmds:
|
292
292
|
cmd_list += other_cmds
|
293
293
|
proc = self._launch_process(cmd_list)
|
294
|
-
|
295
|
-
if proc.poll() is not None:
|
296
|
-
raise ValueError("Mount process failed to start")
|
294
|
+
wait_for_mount(outdir, proc)
|
297
295
|
return proc
|
298
296
|
|
299
297
|
def mount_webdav(
|
@@ -330,10 +328,7 @@ class Rclone:
|
|
330
328
|
if other_cmds:
|
331
329
|
cmd_list += other_cmds
|
332
330
|
proc = self._launch_process(cmd_list)
|
333
|
-
|
334
|
-
time.sleep(2)
|
335
|
-
if proc.poll() is not None:
|
336
|
-
raise ValueError("Mount process failed to start")
|
331
|
+
wait_for_mount(outdir, proc)
|
337
332
|
return proc
|
338
333
|
|
339
334
|
def serve_webdav(
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import shutil
|
3
3
|
import subprocess
|
4
|
+
import time
|
4
5
|
from pathlib import Path
|
5
6
|
from tempfile import TemporaryDirectory
|
6
7
|
from typing import Any
|
@@ -112,3 +113,17 @@ def rclone_execute(
|
|
112
113
|
tempdir.cleanup()
|
113
114
|
except Exception as e:
|
114
115
|
print(f"Error cleaning up tempdir: {e}")
|
116
|
+
|
117
|
+
|
118
|
+
def wait_for_mount(path: Path, mount_process: Any, timeout: int = 60) -> None:
|
119
|
+
from rclone_api.process import Process
|
120
|
+
|
121
|
+
assert isinstance(mount_process, Process)
|
122
|
+
expire_time = time.time() + timeout
|
123
|
+
while time.time() < expire_time:
|
124
|
+
rtn = mount_process.poll()
|
125
|
+
if rtn is not None:
|
126
|
+
raise subprocess.CalledProcessError(rtn, mount_process.cmd)
|
127
|
+
if path.exists():
|
128
|
+
return
|
129
|
+
raise TimeoutError(f"Path {path} did not exist after {timeout} seconds")
|
@@ -38,9 +38,12 @@ src/rclone_api/walk.py
|
|
38
38
|
src/rclone_api.egg-info/PKG-INFO
|
39
39
|
src/rclone_api.egg-info/SOURCES.txt
|
40
40
|
src/rclone_api.egg-info/dependency_links.txt
|
41
|
+
src/rclone_api.egg-info/entry_points.txt
|
41
42
|
src/rclone_api.egg-info/requires.txt
|
42
43
|
src/rclone_api.egg-info/top_level.txt
|
43
44
|
src/rclone_api/assets/example.txt
|
45
|
+
src/rclone_api/cmd/list_files.py
|
46
|
+
tests/test_cmd_list_files.py
|
44
47
|
tests/test_copy.py
|
45
48
|
tests/test_is_synced.py
|
46
49
|
tests/test_ls.py
|
@@ -0,0 +1,83 @@
|
|
1
|
+
"""
|
2
|
+
Unit test file.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import os
|
6
|
+
import unittest
|
7
|
+
|
8
|
+
from dotenv import load_dotenv
|
9
|
+
|
10
|
+
from rclone_api import Config, Rclone, Remote
|
11
|
+
from rclone_api.cmd.list_files import list_files
|
12
|
+
|
13
|
+
load_dotenv()
|
14
|
+
|
15
|
+
BUCKET_NAME = os.getenv("BUCKET_NAME") # Default if not in .env
|
16
|
+
|
17
|
+
|
18
|
+
def _generate_rclone_config() -> Config:
|
19
|
+
|
20
|
+
# BUCKET_NAME = os.getenv("BUCKET_NAME", "TorrentBooks") # Default if not in .env
|
21
|
+
|
22
|
+
# Load additional environment variables
|
23
|
+
BUCKET_KEY_SECRET = os.getenv("BUCKET_KEY_SECRET")
|
24
|
+
BUCKET_KEY_PUBLIC = os.getenv("BUCKET_KEY_PUBLIC")
|
25
|
+
# BUCKET_URL = os.getenv("BUCKET_URL")
|
26
|
+
BUCKET_URL = "sfo3.digitaloceanspaces.com"
|
27
|
+
|
28
|
+
config_text = f"""
|
29
|
+
[dst]
|
30
|
+
type = s3
|
31
|
+
provider = DigitalOcean
|
32
|
+
access_key_id = {BUCKET_KEY_PUBLIC}
|
33
|
+
secret_access_key = {BUCKET_KEY_SECRET}
|
34
|
+
endpoint = {BUCKET_URL}
|
35
|
+
bucket = {BUCKET_NAME}
|
36
|
+
"""
|
37
|
+
|
38
|
+
out = Config(config_text)
|
39
|
+
return out
|
40
|
+
|
41
|
+
|
42
|
+
class RcloneLsTests(unittest.TestCase):
|
43
|
+
"""Test rclone functionality."""
|
44
|
+
|
45
|
+
def setUp(self) -> None:
|
46
|
+
"""Check if all required environment variables are set before running tests."""
|
47
|
+
required_vars = [
|
48
|
+
"BUCKET_NAME",
|
49
|
+
"BUCKET_KEY_SECRET",
|
50
|
+
"BUCKET_KEY_PUBLIC",
|
51
|
+
"BUCKET_URL",
|
52
|
+
]
|
53
|
+
missing = [var for var in required_vars if not os.getenv(var)]
|
54
|
+
if missing:
|
55
|
+
self.skipTest(
|
56
|
+
f"Missing required environment variables: {', '.join(missing)}"
|
57
|
+
)
|
58
|
+
os.environ["RCLONE_API_VERBOSE"] = "1"
|
59
|
+
|
60
|
+
def test_list_remotes(self) -> None:
|
61
|
+
rclone = Rclone(_generate_rclone_config())
|
62
|
+
|
63
|
+
remotes: list[Remote] = rclone.listremotes()
|
64
|
+
self.assertGreater(len(remotes), 0)
|
65
|
+
for remote in remotes:
|
66
|
+
self.assertIsInstance(remote, Remote)
|
67
|
+
print(remote)
|
68
|
+
print("done")
|
69
|
+
|
70
|
+
def test_cmd_list_files(self) -> None:
|
71
|
+
"""Test listing the root directory of the bucket.
|
72
|
+
|
73
|
+
Verifies that we can:
|
74
|
+
1. Connect to the bucket
|
75
|
+
2. List its contents
|
76
|
+
3. Get both directories and files as proper types
|
77
|
+
"""
|
78
|
+
rclone = Rclone(_generate_rclone_config())
|
79
|
+
list_files(rclone, f"dst:{BUCKET_NAME}")
|
80
|
+
|
81
|
+
|
82
|
+
if __name__ == "__main__":
|
83
|
+
unittest.main()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|