rclone-api 1.0.66__tar.gz → 1.0.67__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. {rclone_api-1.0.66 → rclone_api-1.0.67}/PKG-INFO +1 -1
  2. {rclone_api-1.0.66 → rclone_api-1.0.67}/pyproject.toml +1 -1
  3. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/__init__.py +2 -1
  4. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/diff.py +59 -22
  5. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/rclone.py +4 -11
  6. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api.egg-info/PKG-INFO +1 -1
  7. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_diff.py +33 -1
  8. {rclone_api-1.0.66 → rclone_api-1.0.67}/.aiderignore +0 -0
  9. {rclone_api-1.0.66 → rclone_api-1.0.67}/.github/workflows/lint.yml +0 -0
  10. {rclone_api-1.0.66 → rclone_api-1.0.67}/.github/workflows/push_macos.yml +0 -0
  11. {rclone_api-1.0.66 → rclone_api-1.0.67}/.github/workflows/push_ubuntu.yml +0 -0
  12. {rclone_api-1.0.66 → rclone_api-1.0.67}/.github/workflows/push_win.yml +0 -0
  13. {rclone_api-1.0.66 → rclone_api-1.0.67}/.gitignore +0 -0
  14. {rclone_api-1.0.66 → rclone_api-1.0.67}/.pylintrc +0 -0
  15. {rclone_api-1.0.66 → rclone_api-1.0.67}/.vscode/launch.json +0 -0
  16. {rclone_api-1.0.66 → rclone_api-1.0.67}/.vscode/settings.json +0 -0
  17. {rclone_api-1.0.66 → rclone_api-1.0.67}/.vscode/tasks.json +0 -0
  18. {rclone_api-1.0.66 → rclone_api-1.0.67}/LICENSE +0 -0
  19. {rclone_api-1.0.66 → rclone_api-1.0.67}/MANIFEST.in +0 -0
  20. {rclone_api-1.0.66 → rclone_api-1.0.67}/README.md +0 -0
  21. {rclone_api-1.0.66 → rclone_api-1.0.67}/clean +0 -0
  22. {rclone_api-1.0.66 → rclone_api-1.0.67}/install +0 -0
  23. {rclone_api-1.0.66 → rclone_api-1.0.67}/lint +0 -0
  24. {rclone_api-1.0.66 → rclone_api-1.0.67}/requirements.testing.txt +0 -0
  25. {rclone_api-1.0.66 → rclone_api-1.0.67}/setup.cfg +0 -0
  26. {rclone_api-1.0.66 → rclone_api-1.0.67}/setup.py +0 -0
  27. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/assets/example.txt +0 -0
  28. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/cli.py +0 -0
  29. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/cmd/list_files.py +0 -0
  30. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/completed_process.py +0 -0
  31. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/config.py +0 -0
  32. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/convert.py +0 -0
  33. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/deprecated.py +0 -0
  34. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/dir.py +0 -0
  35. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/dir_listing.py +0 -0
  36. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/exec.py +0 -0
  37. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/file.py +0 -0
  38. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/filelist.py +0 -0
  39. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/group_files.py +0 -0
  40. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/process.py +0 -0
  41. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/remote.py +0 -0
  42. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/rpath.py +0 -0
  43. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/util.py +0 -0
  44. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api/walk.py +0 -0
  45. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api.egg-info/SOURCES.txt +0 -0
  46. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  47. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api.egg-info/entry_points.txt +0 -0
  48. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api.egg-info/requires.txt +0 -0
  49. {rclone_api-1.0.66 → rclone_api-1.0.67}/src/rclone_api.egg-info/top_level.txt +0 -0
  50. {rclone_api-1.0.66 → rclone_api-1.0.67}/test +0 -0
  51. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_cmd_list_files.py +0 -0
  52. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_copy.py +0 -0
  53. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_copy_files.py +0 -0
  54. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_group_files.py +0 -0
  55. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_is_synced.py +0 -0
  56. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_ls.py +0 -0
  57. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_mount.py +0 -0
  58. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_mount_s3.py +0 -0
  59. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_mount_webdav.py +0 -0
  60. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_obscure.py +0 -0
  61. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_remote_control.py +0 -0
  62. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_remotes.py +0 -0
  63. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_serve_webdav.py +0 -0
  64. {rclone_api-1.0.66 → rclone_api-1.0.67}/tests/test_walk.py +0 -0
  65. {rclone_api-1.0.66 → rclone_api-1.0.67}/tox.ini +0 -0
  66. {rclone_api-1.0.66 → rclone_api-1.0.67}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.66
3
+ Version: 1.0.67
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  Maintainer: Zachary Vorhies
@@ -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.66"
18
+ version = "1.0.67"
19
19
 
20
20
  [tool.setuptools]
21
21
  package-dir = {"" = "src"}
@@ -6,7 +6,7 @@ from .dir_listing import DirListing
6
6
  from .file import File
7
7
  from .filelist import FileList
8
8
  from .process import Process
9
- from .rclone import DiffOption, Rclone, rclone_verbose
9
+ from .rclone import DiffOption, ListingOption, Rclone, rclone_verbose
10
10
  from .remote import Remote
11
11
  from .rpath import RPath
12
12
 
@@ -25,4 +25,5 @@ __all__ = [
25
25
  "rclone_verbose",
26
26
  "CompletedProcess",
27
27
  "DiffOption",
28
+ "ListingOption",
28
29
  ]
@@ -19,6 +19,15 @@ class DiffType(Enum):
19
19
  ERROR = "!" # means there was an error
20
20
 
21
21
 
22
+ class DiffOption(Enum):
23
+ COMBINED = "combined"
24
+ MISSING_ON_SRC = "missing-on-src"
25
+ MISSING_ON_DST = "missing-on-dst"
26
+ DIFFER = "differ"
27
+ MATCH = "match"
28
+ ERROR = "error"
29
+
30
+
22
31
  @dataclass
23
32
  class DiffItem:
24
33
  type: DiffType
@@ -42,31 +51,56 @@ class DiffItem:
42
51
  return f"{self.src_prefix}/{self.path}"
43
52
 
44
53
 
45
- def _classify_diff(line: str, src_slug: str, dst_slug: str) -> DiffItem | None:
54
+ def _parse_missing_on_src_dst(line: str) -> str | None:
55
+ if line.endswith("does-not-exist"):
56
+ # 2025/02/17 14:43:38 ERROR : zachs_video/breaking_ai_mind.mp4: file not in S3 bucket rclone-api-unit-test path does-not-exist
57
+ parts = line.split(" : ", 1)
58
+ if len(parts) < 1:
59
+ return None
60
+ right = parts[1]
61
+ file_path = right.split(":", 1)[0]
62
+ return file_path.strip()
63
+ return None
64
+
65
+
66
+ def _classify_diff(
67
+ line: str, src_slug: str, dst_slug: str, diff_option: DiffOption
68
+ ) -> DiffItem | None:
46
69
  def _new(type: DiffType, path: str) -> DiffItem:
47
70
  return DiffItem(type, path, src_prefix=src_slug, dst_prefix=dst_slug)
48
71
 
49
- suffix = line[1:].strip() if len(line) > 0 else ""
50
- if line.startswith(DiffType.EQUAL.value):
51
- return _new(DiffType.EQUAL, suffix)
52
- if line.startswith(DiffType.MISSING_ON_SRC.value):
53
- return _new(DiffType.MISSING_ON_SRC, suffix)
54
- if line.startswith(DiffType.MISSING_ON_DST.value):
55
- # return DiffItem(DiffType.MISSING_ON_DST, f"{src_slug}/{suffix}")
56
- return _new(DiffType.MISSING_ON_DST, suffix)
57
- if line.startswith(DiffType.DIFFERENT.value):
58
- # return DiffItem(DiffType.DIFFERENT, suffix)
59
- return _new(DiffType.DIFFERENT, suffix)
60
- if line.startswith(DiffType.ERROR.value):
61
- # return DiffItem(DiffType.ERROR, suffix)
62
- return _new(DiffType.ERROR, suffix)
63
- return None
72
+ if diff_option == DiffOption.COMBINED:
73
+ suffix = line[1:].strip() if len(line) > 0 else ""
74
+ if line.startswith(DiffType.EQUAL.value):
75
+ return _new(DiffType.EQUAL, suffix)
76
+ if line.startswith(DiffType.MISSING_ON_SRC.value):
77
+ return _new(DiffType.MISSING_ON_SRC, suffix)
78
+ if line.startswith(DiffType.MISSING_ON_DST.value):
79
+ return _new(DiffType.MISSING_ON_DST, suffix)
80
+ if line.startswith(DiffType.DIFFERENT.value):
81
+ return _new(DiffType.DIFFERENT, suffix)
82
+ if line.startswith(DiffType.ERROR.value):
83
+ return _new(DiffType.ERROR, suffix)
84
+ return None
85
+ if diff_option == DiffOption.MISSING_ON_SRC:
86
+ filename_src: str | None = _parse_missing_on_src_dst(line)
87
+ if filename_src is not None:
88
+ return _new(DiffType.MISSING_ON_SRC, filename_src)
89
+ return None
90
+ if diff_option == DiffOption.MISSING_ON_DST:
91
+ filename_dst: str | None = _parse_missing_on_src_dst(line)
92
+ if filename_dst is not None:
93
+ return _new(DiffType.MISSING_ON_DST, filename_dst)
94
+ return None
95
+ else:
96
+ raise ValueError(f"Unknown diff_option: {diff_option}")
64
97
 
65
98
 
66
99
  def _async_diff_stream_from_running_process(
67
100
  running_process: Process,
68
101
  src_slug: str,
69
102
  dst_slug: str,
103
+ diff_option: DiffOption,
70
104
  output: Queue[DiffItem | None],
71
105
  ) -> None:
72
106
  count = 0
@@ -81,7 +115,7 @@ def _async_diff_stream_from_running_process(
81
115
  first_few_lines.append(line_str)
82
116
  # _classify_line_type
83
117
  diff_item: DiffItem | None = _classify_diff(
84
- line_str, src_slug, dst_slug
118
+ line_str, src_slug, dst_slug, diff_option
85
119
  )
86
120
  if diff_item is None:
87
121
  # Some other output that we don't care about, debug print etc.
@@ -111,14 +145,17 @@ def diff_stream_from_running_process(
111
145
  running_process: Process,
112
146
  src_slug: str,
113
147
  dst_slug: str,
148
+ diff_option: DiffOption,
114
149
  ) -> Generator[DiffItem, None, None]:
115
150
  output: Queue[DiffItem | None] = Queue()
116
151
  # process_output_to_diff_stream(running_process, src_slug, dst_slug, output)
117
- thread = Thread(
118
- target=_async_diff_stream_from_running_process,
119
- args=(running_process, src_slug, dst_slug, output),
120
- daemon=True,
121
- )
152
+
153
+ def _task() -> None:
154
+ _async_diff_stream_from_running_process(
155
+ running_process, src_slug, dst_slug, diff_option, output
156
+ )
157
+
158
+ thread = Thread(target=_task, daemon=True)
122
159
  thread.start()
123
160
  while True:
124
161
  item = output.get()
@@ -18,7 +18,7 @@ from rclone_api.completed_process import CompletedProcess
18
18
  from rclone_api.config import Config
19
19
  from rclone_api.convert import convert_to_filestr_list, convert_to_str
20
20
  from rclone_api.deprecated import deprecated
21
- from rclone_api.diff import DiffItem, diff_stream_from_running_process
21
+ from rclone_api.diff import DiffItem, DiffOption, diff_stream_from_running_process
22
22
  from rclone_api.dir_listing import DirListing
23
23
  from rclone_api.exec import RcloneExec
24
24
  from rclone_api.file import File
@@ -47,15 +47,6 @@ class ModTimeStrategy(Enum):
47
47
  NO_MODTIME = "no-modtime"
48
48
 
49
49
 
50
- class DiffOption(Enum):
51
- COMBINED = "combined"
52
- MISSING_ON_SRC = "missing-on-src"
53
- MISSING_ON_DST = "missing-on-dst"
54
- DIFFER = "differ"
55
- MATCH = "match"
56
- ERROR = "error"
57
-
58
-
59
50
  class ListingOption(Enum):
60
51
  DIRS_ONLY = "dirs-only"
61
52
  FILES_ONLY = "files-only"
@@ -245,7 +236,9 @@ class Rclone:
245
236
  cmd += other_args
246
237
  proc = self._launch_process(cmd, capture=True)
247
238
  item: DiffItem
248
- for item in diff_stream_from_running_process(proc, src_slug=src, dst_slug=dst):
239
+ for item in diff_stream_from_running_process(
240
+ running_process=proc, src_slug=src, dst_slug=dst, diff_option=diff_option
241
+ ):
249
242
  if item is None:
250
243
  break
251
244
  yield item
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.66
3
+ Version: 1.0.67
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  Maintainer: Zachary Vorhies
@@ -7,7 +7,7 @@ import unittest
7
7
 
8
8
  from dotenv import load_dotenv
9
9
 
10
- from rclone_api import Config, Rclone
10
+ from rclone_api import Config, DiffOption, Rclone
11
11
  from rclone_api.diff import DiffItem, DiffType
12
12
 
13
13
  load_dotenv()
@@ -70,6 +70,38 @@ class RcloneDiffTests(unittest.TestCase):
70
70
  msg = "\n".join([str(item) for item in all])
71
71
  print(msg)
72
72
 
73
+ def test_diff_missing_on_dst(self) -> None:
74
+ rclone = Rclone(_generate_rclone_config())
75
+ item: DiffItem
76
+ all: list[DiffItem] = []
77
+ for item in rclone.diff(
78
+ "dst:rclone-api-unit-test",
79
+ "dst:rclone-api-unit-test/does-not-exist",
80
+ diff_option=DiffOption.MISSING_ON_DST,
81
+ ):
82
+ self.assertEqual(
83
+ item.type, DiffType.MISSING_ON_DST
84
+ ) # should be equal because same repo
85
+ all.append(item)
86
+ self.assertGreater(len(all), 0)
87
+ msg = "\n".join([str(item) for item in all])
88
+ print(msg)
89
+
90
+ def test_diff_missing_on_src(self) -> None:
91
+ rclone = Rclone(_generate_rclone_config())
92
+ item: DiffItem
93
+ all: list[DiffItem] = []
94
+ for item in rclone.diff(
95
+ "dst:rclone-api-unit-test/does-not-exist",
96
+ "dst:rclone-api-unit-test",
97
+ diff_option=DiffOption.MISSING_ON_SRC,
98
+ ):
99
+ self.assertEqual(item.type, DiffType.MISSING_ON_SRC)
100
+ all.append(item)
101
+ self.assertGreater(len(all), 0)
102
+ msg = "\n".join([str(item) for item in all])
103
+ print(msg)
104
+
73
105
 
74
106
  if __name__ == "__main__":
75
107
  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