rclone-api 1.0.26__tar.gz → 1.0.28__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. {rclone_api-1.0.26 → rclone_api-1.0.28}/PKG-INFO +3 -3
  2. {rclone_api-1.0.26 → rclone_api-1.0.28}/README.md +2 -2
  3. {rclone_api-1.0.26 → rclone_api-1.0.28}/pyproject.toml +1 -1
  4. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/__init__.py +3 -0
  5. rclone_api-1.0.28/src/rclone_api/diff.py +119 -0
  6. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/dir_listing.py +16 -0
  7. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/exec.py +2 -1
  8. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/process.py +8 -1
  9. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/rclone.py +24 -2
  10. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api.egg-info/PKG-INFO +3 -3
  11. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api.egg-info/SOURCES.txt +2 -0
  12. rclone_api-1.0.28/tests/test_diff.py +87 -0
  13. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_mount_s3.py +3 -0
  14. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_mount_webdav.py +3 -0
  15. {rclone_api-1.0.26 → rclone_api-1.0.28}/.aiderignore +0 -0
  16. {rclone_api-1.0.26 → rclone_api-1.0.28}/.github/workflows/lint.yml +0 -0
  17. {rclone_api-1.0.26 → rclone_api-1.0.28}/.github/workflows/push_macos.yml +0 -0
  18. {rclone_api-1.0.26 → rclone_api-1.0.28}/.github/workflows/push_ubuntu.yml +0 -0
  19. {rclone_api-1.0.26 → rclone_api-1.0.28}/.github/workflows/push_win.yml +0 -0
  20. {rclone_api-1.0.26 → rclone_api-1.0.28}/.gitignore +0 -0
  21. {rclone_api-1.0.26 → rclone_api-1.0.28}/.pylintrc +0 -0
  22. {rclone_api-1.0.26 → rclone_api-1.0.28}/.vscode/launch.json +0 -0
  23. {rclone_api-1.0.26 → rclone_api-1.0.28}/.vscode/settings.json +0 -0
  24. {rclone_api-1.0.26 → rclone_api-1.0.28}/.vscode/tasks.json +0 -0
  25. {rclone_api-1.0.26 → rclone_api-1.0.28}/LICENSE +0 -0
  26. {rclone_api-1.0.26 → rclone_api-1.0.28}/MANIFEST.in +0 -0
  27. {rclone_api-1.0.26 → rclone_api-1.0.28}/clean +0 -0
  28. {rclone_api-1.0.26 → rclone_api-1.0.28}/install +0 -0
  29. {rclone_api-1.0.26 → rclone_api-1.0.28}/lint +0 -0
  30. {rclone_api-1.0.26 → rclone_api-1.0.28}/requirements.testing.txt +0 -0
  31. {rclone_api-1.0.26 → rclone_api-1.0.28}/setup.cfg +0 -0
  32. {rclone_api-1.0.26 → rclone_api-1.0.28}/setup.py +0 -0
  33. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/assets/example.txt +0 -0
  34. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/cli.py +0 -0
  35. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/cmd/list_files.py +0 -0
  36. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/config.py +0 -0
  37. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/convert.py +0 -0
  38. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/dir.py +0 -0
  39. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/file.py +0 -0
  40. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/filelist.py +0 -0
  41. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/remote.py +0 -0
  42. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/rpath.py +0 -0
  43. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/util.py +0 -0
  44. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api/walk.py +0 -0
  45. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  46. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api.egg-info/entry_points.txt +0 -0
  47. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api.egg-info/requires.txt +0 -0
  48. {rclone_api-1.0.26 → rclone_api-1.0.28}/src/rclone_api.egg-info/top_level.txt +0 -0
  49. {rclone_api-1.0.26 → rclone_api-1.0.28}/test +0 -0
  50. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_cmd_list_files.py +0 -0
  51. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_copy.py +0 -0
  52. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_is_synced.py +0 -0
  53. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_ls.py +0 -0
  54. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_mount.py +0 -0
  55. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_obscure.py +0 -0
  56. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_remotes.py +0 -0
  57. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_serve_webdav.py +0 -0
  58. {rclone_api-1.0.26 → rclone_api-1.0.28}/tests/test_walk.py +0 -0
  59. {rclone_api-1.0.26 → rclone_api-1.0.28}/tox.ini +0 -0
  60. {rclone_api-1.0.26 → rclone_api-1.0.28}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.26
3
+ Version: 1.0.28
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  Maintainer: Zachary Vorhies
@@ -22,11 +22,11 @@ Dynamic: maintainer
22
22
  [![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)
23
23
  [![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)
24
24
 
25
- Api version of rclone. It's well tested. It's a pretty low level api without the bells and whistles of other apis, but it will get the job done.
25
+ Api version of rclone. It's a pretty low level api without the bells and whistles of other apis, but it will get the job done. Unit tests up the wazoo. S3 Mounts on windows/linux are heavily optimized.
26
26
 
27
27
  You will need to have rclone installed and on your path.
28
28
 
29
- One of the benefits of this api is that it does not use `shell=True`, which can keep `rclone` running in some instances even when try to kill the process.
29
+ One of the benefits of this api is that it does not use 'shell=True' so therefore ctrl-c will work well in gracefully shutting down
30
30
 
31
31
  # Install
32
32
 
@@ -5,11 +5,11 @@
5
5
  [![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)
6
6
  [![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)
7
7
 
8
- Api version of rclone. It's well tested. It's a pretty low level api without the bells and whistles of other apis, but it will get the job done.
8
+ Api version of rclone. It's a pretty low level api without the bells and whistles of other apis, but it will get the job done. Unit tests up the wazoo. S3 Mounts on windows/linux are heavily optimized.
9
9
 
10
10
  You will need to have rclone installed and on your path.
11
11
 
12
- One of the benefits of this api is that it does not use `shell=True`, which can keep `rclone` running in some instances even when try to kill the process.
12
+ One of the benefits of this api is that it does not use 'shell=True' so therefore ctrl-c will work well in gracefully shutting down
13
13
 
14
14
  # Install
15
15
 
@@ -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.26"
18
+ version = "1.0.28"
19
19
 
20
20
  [tool.setuptools]
21
21
  package-dir = {"" = "src"}
@@ -1,4 +1,5 @@
1
1
  from .config import Config
2
+ from .diff import DiffItem, DiffType
2
3
  from .dir import Dir
3
4
  from .dir_listing import DirListing
4
5
  from .file import File
@@ -18,4 +19,6 @@ __all__ = [
18
19
  "DirListing",
19
20
  "FileList",
20
21
  "Process",
22
+ "DiffItem",
23
+ "DiffType",
21
24
  ]
@@ -0,0 +1,119 @@
1
+ from dataclasses import dataclass
2
+ from enum import Enum
3
+ from queue import Queue
4
+ from threading import Thread
5
+ from typing import Generator
6
+
7
+ from rclone_api.process import Process
8
+
9
+
10
+ class DiffType(Enum):
11
+ EQUAL = "="
12
+ MISSING_ON_SRC = (
13
+ "-" # means path was missing on the source, so only in the destination
14
+ )
15
+ MISSING_ON_DST = (
16
+ "+" # means path was missing on the destination, so only in the source
17
+ )
18
+ DIFFERENT = "*" # means path was present in source and destination but different.
19
+ ERROR = "!" # means there was an error
20
+
21
+
22
+ @dataclass
23
+ class DiffItem:
24
+ type: DiffType
25
+ path: str
26
+ src_prefix: str
27
+ dst_prefix: str
28
+
29
+ def __str__(self) -> str:
30
+ return f"{self.type.value} {self.path}"
31
+
32
+ def __repr__(self) -> str:
33
+ return f"{self.type.name} {self.path}"
34
+
35
+
36
+ def _classify_diff(line: str, src_slug: str, dst_slug: str) -> DiffItem | None:
37
+ def _new(type: DiffType, path: str) -> DiffItem:
38
+ return DiffItem(type, path, src_prefix=src_slug, dst_prefix=dst_slug)
39
+
40
+ suffix = line[1:].strip() if len(line) > 0 else ""
41
+ if line.startswith(DiffType.EQUAL.value):
42
+ return _new(DiffType.EQUAL, suffix)
43
+ if line.startswith(DiffType.MISSING_ON_SRC.value):
44
+ return _new(DiffType.MISSING_ON_SRC, suffix)
45
+ if line.startswith(DiffType.MISSING_ON_DST.value):
46
+ # return DiffItem(DiffType.MISSING_ON_DST, f"{src_slug}/{suffix}")
47
+ return _new(DiffType.MISSING_ON_DST, suffix)
48
+ if line.startswith(DiffType.DIFFERENT.value):
49
+ # return DiffItem(DiffType.DIFFERENT, suffix)
50
+ return _new(DiffType.DIFFERENT, suffix)
51
+ if line.startswith(DiffType.ERROR.value):
52
+ # return DiffItem(DiffType.ERROR, suffix)
53
+ return _new(DiffType.ERROR, suffix)
54
+ return None
55
+
56
+
57
+ def _async_diff_stream_from_running_process(
58
+ running_process: Process,
59
+ src_slug: str,
60
+ dst_slug: str,
61
+ output: Queue[DiffItem | None],
62
+ ) -> None:
63
+ count = 0
64
+ first_few_lines: list[str] = []
65
+ try:
66
+ assert running_process.stdout is not None
67
+ n_max = 10
68
+ for line in iter(running_process.stdout.readline, b""):
69
+ try:
70
+ line_str = line.decode("utf-8").strip()
71
+ if len(first_few_lines) < n_max:
72
+ first_few_lines.append(line_str)
73
+ # _classify_line_type
74
+ diff_item: DiffItem | None = _classify_diff(
75
+ line_str, src_slug, dst_slug
76
+ )
77
+ if diff_item is None:
78
+ # Some other output that we don't care about, debug print etc.
79
+ continue
80
+ output.put(diff_item)
81
+ count += 1
82
+ # print(f"unhandled: {line_str}")
83
+ except UnicodeDecodeError:
84
+ print("UnicodeDecodeError")
85
+ continue
86
+ output.put(None)
87
+ print("done")
88
+ except KeyboardInterrupt:
89
+ import _thread
90
+
91
+ print("KeyboardInterrupt")
92
+ output.put(None)
93
+ _thread.interrupt_main()
94
+ if count == 0:
95
+ first_lines_str = "\n".join(first_few_lines)
96
+ raise ValueError(
97
+ f"No output from rclone check, first few lines: {first_lines_str}"
98
+ )
99
+
100
+
101
+ def diff_stream_from_running_process(
102
+ running_process: Process,
103
+ src_slug: str,
104
+ dst_slug: str,
105
+ ) -> Generator[DiffItem, None, None]:
106
+ output: Queue[DiffItem | None] = Queue()
107
+ # process_output_to_diff_stream(running_process, src_slug, dst_slug, output)
108
+ thread = Thread(
109
+ target=_async_diff_stream_from_running_process,
110
+ args=(running_process, src_slug, dst_slug, output),
111
+ daemon=True,
112
+ )
113
+ thread.start()
114
+ while True:
115
+ item = output.get()
116
+ if item is None:
117
+ break
118
+ yield item
119
+ thread.join(timeout=5)
@@ -1,8 +1,22 @@
1
1
  import json
2
+ import warnings
2
3
 
3
4
  from rclone_api.rpath import RPath
4
5
 
5
6
 
7
+ def _dedupe(items: list[RPath]) -> list[RPath]:
8
+ """Remove duplicate items from a list of RPath objects."""
9
+ seen = set()
10
+ unique_items = []
11
+ for item in items:
12
+ if item not in seen:
13
+ seen.add(item)
14
+ unique_items.append(item)
15
+ else:
16
+ warnings.warn(f"Duplicate item found: {item}, filtered out.")
17
+ return unique_items
18
+
19
+
6
20
  class DirListing:
7
21
  """Remote file dataclass."""
8
22
 
@@ -10,6 +24,8 @@ class DirListing:
10
24
  from rclone_api.dir import Dir
11
25
  from rclone_api.file import File
12
26
 
27
+ dirs_and_files = _dedupe(dirs_and_files)
28
+
13
29
  self.dirs: list[Dir] = [Dir(d) for d in dirs_and_files if d.is_dir]
14
30
  self.files: list[File] = [File(f) for f in dirs_and_files if not f.is_dir]
15
31
 
@@ -19,7 +19,7 @@ class RcloneExec:
19
19
 
20
20
  return rclone_execute(cmd, self.rclone_config, self.rclone_exe, check=check)
21
21
 
22
- def launch_process(self, cmd: list[str]) -> Process:
22
+ def launch_process(self, cmd: list[str], capture: bool | None) -> Process:
23
23
  """Launch rclone process."""
24
24
 
25
25
  args: ProcessArgs = ProcessArgs(
@@ -27,6 +27,7 @@ class RcloneExec:
27
27
  rclone_conf=self.rclone_config,
28
28
  rclone_exe=self.rclone_exe,
29
29
  cmd_list=cmd,
30
+ capture_stdout=capture,
30
31
  )
31
32
  process = Process(args)
32
33
  return process
@@ -56,6 +56,7 @@ class ProcessArgs:
56
56
  rclone_exe: Path
57
57
  cmd_list: list[str]
58
58
  verbose: bool | None = None
59
+ capture_stdout: bool | None = None
59
60
 
60
61
 
61
62
  class Process:
@@ -84,7 +85,13 @@ class Process:
84
85
  if verbose:
85
86
  cmd_str = subprocess.list2cmdline(self.cmd)
86
87
  print(f"Running: {cmd_str}")
87
- self.process = subprocess.Popen(self.cmd, shell=False)
88
+ kwargs: dict = {}
89
+ kwargs["shell"] = False
90
+ if args.capture_stdout:
91
+ kwargs["stdout"] = subprocess.PIPE
92
+ kwargs["stderr"] = subprocess.STDOUT
93
+
94
+ self.process = subprocess.Popen(self.cmd, **kwargs) # type: ignore
88
95
 
89
96
  def cleanup(self) -> None:
90
97
  if self.tempdir and self.needs_cleanup:
@@ -14,6 +14,7 @@ from typing import Generator
14
14
  from rclone_api import Dir
15
15
  from rclone_api.config import Config
16
16
  from rclone_api.convert import convert_to_filestr_list, convert_to_str
17
+ from rclone_api.diff import DiffItem, diff_stream_from_running_process
17
18
  from rclone_api.dir_listing import DirListing
18
19
  from rclone_api.exec import RcloneExec
19
20
  from rclone_api.file import File
@@ -41,8 +42,8 @@ class Rclone:
41
42
  def _run(self, cmd: list[str], check: bool = True) -> subprocess.CompletedProcess:
42
43
  return self._exec.execute(cmd, check=check)
43
44
 
44
- def _launch_process(self, cmd: list[str]) -> Process:
45
- return self._exec.launch_process(cmd)
45
+ def _launch_process(self, cmd: list[str], capture: bool | None = None) -> Process:
46
+ return self._exec.launch_process(cmd, capture=capture)
46
47
 
47
48
  def obscure(self, password: str) -> str:
48
49
  """Obscure a password for use in rclone config files."""
@@ -108,6 +109,27 @@ class Rclone:
108
109
  out = [Remote(name=t, rclone=self) for t in tmp]
109
110
  return out
110
111
 
112
+ def diff(self, src: str, dst: str) -> Generator[DiffItem, None, None]:
113
+ """Be extra careful with the src and dst values. If you are off by one
114
+ parent directory, you will get a huge amount of false diffs."""
115
+ cmd = [
116
+ "check",
117
+ src,
118
+ dst,
119
+ "--checkers",
120
+ "1000",
121
+ "--log-level",
122
+ "INFO",
123
+ "--combined",
124
+ "-",
125
+ ]
126
+ proc = self._launch_process(cmd, capture=True)
127
+ item: DiffItem
128
+ for item in diff_stream_from_running_process(proc, src_slug=src, dst_slug=src):
129
+ if item is None:
130
+ break
131
+ yield item
132
+
111
133
  def walk(
112
134
  self, path: Dir | Remote | str, max_depth: int = -1, breadth_first: bool = True
113
135
  ) -> Generator[DirListing, None, None]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.26
3
+ Version: 1.0.28
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  Maintainer: Zachary Vorhies
@@ -22,11 +22,11 @@ Dynamic: maintainer
22
22
  [![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)
23
23
  [![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)
24
24
 
25
- Api version of rclone. It's well tested. It's a pretty low level api without the bells and whistles of other apis, but it will get the job done.
25
+ Api version of rclone. It's a pretty low level api without the bells and whistles of other apis, but it will get the job done. Unit tests up the wazoo. S3 Mounts on windows/linux are heavily optimized.
26
26
 
27
27
  You will need to have rclone installed and on your path.
28
28
 
29
- One of the benefits of this api is that it does not use `shell=True`, which can keep `rclone` running in some instances even when try to kill the process.
29
+ One of the benefits of this api is that it does not use 'shell=True' so therefore ctrl-c will work well in gracefully shutting down
30
30
 
31
31
  # Install
32
32
 
@@ -24,6 +24,7 @@ src/rclone_api/__init__.py
24
24
  src/rclone_api/cli.py
25
25
  src/rclone_api/config.py
26
26
  src/rclone_api/convert.py
27
+ src/rclone_api/diff.py
27
28
  src/rclone_api/dir.py
28
29
  src/rclone_api/dir_listing.py
29
30
  src/rclone_api/exec.py
@@ -45,6 +46,7 @@ src/rclone_api/assets/example.txt
45
46
  src/rclone_api/cmd/list_files.py
46
47
  tests/test_cmd_list_files.py
47
48
  tests/test_copy.py
49
+ tests/test_diff.py
48
50
  tests/test_is_synced.py
49
51
  tests/test_ls.py
50
52
  tests/test_mount.py
@@ -0,0 +1,87 @@
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
11
+ from rclone_api.diff import DiffItem, DiffType
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
+ """
36
+
37
+ out = Config(config_text)
38
+ return out
39
+
40
+
41
+ class RcloneDiffTests(unittest.TestCase):
42
+ """Test rclone functionality."""
43
+
44
+ def setUp(self) -> None:
45
+ """Check if all required environment variables are set before running tests."""
46
+ required_vars = [
47
+ "BUCKET_NAME",
48
+ "BUCKET_KEY_SECRET",
49
+ "BUCKET_KEY_PUBLIC",
50
+ "BUCKET_URL",
51
+ ]
52
+ missing = [var for var in required_vars if not os.getenv(var)]
53
+ if missing:
54
+ self.skipTest(
55
+ f"Missing required environment variables: {', '.join(missing)}"
56
+ )
57
+ os.environ["RCLONE_API_VERBOSE"] = "1"
58
+
59
+ def test_diff(self) -> None:
60
+ """Test copying a single file to remote storage."""
61
+ rclone = Rclone(_generate_rclone_config())
62
+ item: DiffItem
63
+ all: list[DiffItem] = []
64
+ for item in rclone.diff("dst:rclone-api-unit-test", "dst:rclone-api-unit-test"):
65
+ self.assertEqual(
66
+ item.type, DiffType.EQUAL
67
+ ) # should be equal because same repo
68
+ all.append(item)
69
+ self.assertGreater(len(all), 10)
70
+ msg = "\n".join([str(item) for item in all])
71
+ print(msg)
72
+
73
+ all.clear()
74
+ for item in rclone.diff(
75
+ "dst:rclone-api-unit-test/test", "dst:rclone-api-unit-test/test"
76
+ ):
77
+ self.assertEqual(item.type, DiffType.EQUAL)
78
+ print(item)
79
+ all.append(item)
80
+
81
+ msg = "\n".join([str(item) for item in all])
82
+ print(msg)
83
+ print("done")
84
+
85
+
86
+ if __name__ == "__main__":
87
+ unittest.main()
@@ -13,6 +13,8 @@ from rclone_api import Config, Process, Rclone
13
13
 
14
14
  load_dotenv()
15
15
 
16
+ _ENABLED = False
17
+
16
18
 
17
19
  def _generate_rclone_config() -> Config:
18
20
  # Load environment variables
@@ -60,6 +62,7 @@ class RcloneMountS3Tests(unittest.TestCase):
60
62
  os.environ["RCLONE_API_VERBOSE"] = "1"
61
63
  self.rclone = Rclone(_generate_rclone_config())
62
64
 
65
+ @unittest.skipUnless(_ENABLED, "Test is disabled by default")
63
66
  def test_mount(self) -> None:
64
67
  """Test mounting a remote bucket."""
65
68
  remote_path = f"dst:{self.bucket_name}"
@@ -10,6 +10,8 @@ from dotenv import load_dotenv
10
10
 
11
11
  from rclone_api import Config, Process, Rclone, Remote
12
12
 
13
+ _ENABLED = False
14
+
13
15
  load_dotenv()
14
16
 
15
17
  BUCKET_NAME = os.getenv("BUCKET_NAME") # Default if not in .env
@@ -66,6 +68,7 @@ class RcloneMountWebdavTester(unittest.TestCase):
66
68
  )
67
69
  os.environ["RCLONE_API_VERBOSE"] = "1"
68
70
 
71
+ @unittest.skipIf(not _ENABLED, "Test not enabled")
69
72
  def test_serve_webdav_and_mount(self) -> None:
70
73
  """Test basic NFS serve functionality."""
71
74
  port = 8090
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