rclone-api 1.4.18__tar.gz → 1.4.19__tar.gz

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.
Files changed (109) hide show
  1. {rclone_api-1.4.18 → rclone_api-1.4.19}/PKG-INFO +1 -1
  2. {rclone_api-1.4.18 → rclone_api-1.4.19}/pyproject.toml +1 -1
  3. rclone_api-1.4.19/src/rclone_api/cmd/copy_large_s3_finish.py +73 -0
  4. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/detail/copy_file_parts.py +4 -1
  5. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/merge_state.py +47 -15
  6. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/multipart/finished_piece.py +0 -4
  7. rclone_api-1.4.19/src/rclone_api/s3/s3_multipart_uploader_by_copy.py +518 -0
  8. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api.egg-info/PKG-INFO +1 -1
  9. rclone_api-1.4.18/src/rclone_api/cmd/copy_large_s3_finish.py +0 -225
  10. rclone_api-1.4.18/src/rclone_api/s3/s3_multipart_uploader_by_copy.py +0 -327
  11. {rclone_api-1.4.18 → rclone_api-1.4.19}/.aiderignore +0 -0
  12. {rclone_api-1.4.18 → rclone_api-1.4.19}/.github/workflows/lint.yml +0 -0
  13. {rclone_api-1.4.18 → rclone_api-1.4.19}/.github/workflows/push_macos.yml +0 -0
  14. {rclone_api-1.4.18 → rclone_api-1.4.19}/.github/workflows/push_ubuntu.yml +0 -0
  15. {rclone_api-1.4.18 → rclone_api-1.4.19}/.github/workflows/push_win.yml +0 -0
  16. {rclone_api-1.4.18 → rclone_api-1.4.19}/.gitignore +0 -0
  17. {rclone_api-1.4.18 → rclone_api-1.4.19}/.pylintrc +0 -0
  18. {rclone_api-1.4.18 → rclone_api-1.4.19}/.vscode/launch.json +0 -0
  19. {rclone_api-1.4.18 → rclone_api-1.4.19}/.vscode/settings.json +0 -0
  20. {rclone_api-1.4.18 → rclone_api-1.4.19}/.vscode/tasks.json +0 -0
  21. {rclone_api-1.4.18 → rclone_api-1.4.19}/LICENSE +0 -0
  22. {rclone_api-1.4.18 → rclone_api-1.4.19}/MANIFEST.in +0 -0
  23. {rclone_api-1.4.18 → rclone_api-1.4.19}/README.md +0 -0
  24. {rclone_api-1.4.18 → rclone_api-1.4.19}/clean +0 -0
  25. {rclone_api-1.4.18 → rclone_api-1.4.19}/install +0 -0
  26. {rclone_api-1.4.18 → rclone_api-1.4.19}/lint +0 -0
  27. {rclone_api-1.4.18 → rclone_api-1.4.19}/requirements.testing.txt +0 -0
  28. {rclone_api-1.4.18 → rclone_api-1.4.19}/setup.cfg +0 -0
  29. {rclone_api-1.4.18 → rclone_api-1.4.19}/setup.py +0 -0
  30. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/__init__.py +0 -0
  31. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/assets/example.txt +0 -0
  32. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/cli.py +0 -0
  33. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/cmd/analyze.py +0 -0
  34. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/cmd/copy_large_s3.py +0 -0
  35. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/cmd/list_files.py +0 -0
  36. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/cmd/save_to_db.py +0 -0
  37. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/completed_process.py +0 -0
  38. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/config.py +0 -0
  39. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/convert.py +0 -0
  40. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/db/__init__.py +0 -0
  41. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/db/db.py +0 -0
  42. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/db/models.py +0 -0
  43. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/deprecated.py +0 -0
  44. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/detail/walk.py +0 -0
  45. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/diff.py +0 -0
  46. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/dir.py +0 -0
  47. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/dir_listing.py +0 -0
  48. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/exec.py +0 -0
  49. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/experimental/flags.py +0 -0
  50. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/experimental/flags_base.py +0 -0
  51. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/file.py +0 -0
  52. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/file_item.py +0 -0
  53. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/file_part.py +0 -0
  54. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/file_stream.py +0 -0
  55. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/filelist.py +0 -0
  56. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/group_files.py +0 -0
  57. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/http_server.py +0 -0
  58. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/log.py +0 -0
  59. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/mount.py +0 -0
  60. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/process.py +0 -0
  61. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/rclone_impl.py +0 -0
  62. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/remote.py +0 -0
  63. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/rpath.py +0 -0
  64. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/api.py +0 -0
  65. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/basic_ops.py +0 -0
  66. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/chunk_task.py +0 -0
  67. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/create.py +0 -0
  68. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/multipart/file_info.py +0 -0
  69. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/multipart/upload_info.py +0 -0
  70. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/multipart/upload_state.py +0 -0
  71. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/types.py +0 -0
  72. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/s3/upload_file_multipart.py +0 -0
  73. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/scan_missing_folders.py +0 -0
  74. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/types.py +0 -0
  75. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api/util.py +0 -0
  76. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api.egg-info/SOURCES.txt +0 -0
  77. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  78. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api.egg-info/entry_points.txt +0 -0
  79. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api.egg-info/requires.txt +0 -0
  80. {rclone_api-1.4.18 → rclone_api-1.4.19}/src/rclone_api.egg-info/top_level.txt +0 -0
  81. {rclone_api-1.4.18 → rclone_api-1.4.19}/test +0 -0
  82. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/archive/test_paramiko.py.disabled +0 -0
  83. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_cmd_list_files.py +0 -0
  84. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_copy.py +0 -0
  85. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_copy_bytes.py +0 -0
  86. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_copy_file_resumable_s3.py +0 -0
  87. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_copy_files.py +0 -0
  88. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_db.py +0 -0
  89. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_diff.py +0 -0
  90. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_file_item.py +0 -0
  91. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_group_files.py +0 -0
  92. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_is_synced.py +0 -0
  93. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_ls.py +0 -0
  94. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_ls_stream_files.py +0 -0
  95. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_mount.py +0 -0
  96. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_mount_s3.py +0 -0
  97. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_obscure.py +0 -0
  98. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_rclone_config.py +0 -0
  99. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_read_write_text.py +0 -0
  100. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_remote_control.py +0 -0
  101. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_remotes.py +0 -0
  102. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_s3.py +0 -0
  103. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_scan_missing_folders.py +0 -0
  104. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_serve_http.py +0 -0
  105. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_size_files.py +0 -0
  106. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_size_suffix.py +0 -0
  107. {rclone_api-1.4.18 → rclone_api-1.4.19}/tests/test_walk.py +0 -0
  108. {rclone_api-1.4.18 → rclone_api-1.4.19}/tox.ini +0 -0
  109. {rclone_api-1.4.18 → rclone_api-1.4.19}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.4.18
3
+ Version: 1.4.19
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -25,7 +25,7 @@ dependencies = [
25
25
  ]
26
26
 
27
27
  # Change this with the version number bump.
28
- version = "1.4.18"
28
+ version = "1.4.19"
29
29
 
30
30
  [tool.setuptools]
31
31
  package-dir = {"" = "src"}
@@ -0,0 +1,73 @@
1
+ import argparse
2
+ from dataclasses import dataclass
3
+ from pathlib import Path
4
+
5
+ from rclone_api import Rclone
6
+ from rclone_api.s3.s3_multipart_uploader_by_copy import (
7
+ s3_server_side_multi_part_merge,
8
+ )
9
+
10
+
11
+ @dataclass
12
+ class Args:
13
+ config_path: Path
14
+ src: str # like dst:TorrentBooks/aa_misc_data/aa_misc_data/world_lending_library_2024_11.tar.zst-parts/ (info.json will be located here)
15
+ verbose: bool
16
+
17
+
18
+ def list_files(rclone: Rclone, path: str):
19
+ """List files in a remote path."""
20
+ for dirlisting in rclone.walk(path):
21
+ for file in dirlisting.files:
22
+ print(file.path)
23
+
24
+
25
+ def _parse_args() -> Args:
26
+ parser = argparse.ArgumentParser(description="List files in a remote path.")
27
+ parser.add_argument("src", help="Directory that holds the info.json file")
28
+ parser.add_argument("-v", "--verbose", help="Verbose output", action="store_true")
29
+ parser.add_argument(
30
+ "--config", help="Path to rclone config file", type=Path, required=False
31
+ )
32
+ args = parser.parse_args()
33
+ config: Path | None = args.config
34
+ if config is None:
35
+ config = Path("rclone.conf")
36
+ if not config.exists():
37
+ raise FileNotFoundError(f"Config file not found: {config}")
38
+ assert config is not None
39
+ out = Args(
40
+ config_path=config,
41
+ src=args.src,
42
+ verbose=args.verbose,
43
+ )
44
+ return out
45
+
46
+
47
+ def _get_info_path(src: str) -> str:
48
+ if src.endswith("/"):
49
+ src = src[:-1]
50
+ info_path = f"{src}/info.json"
51
+ return info_path
52
+
53
+
54
+ def main() -> int:
55
+ """Main entry point."""
56
+ args = _parse_args()
57
+ rclone = Rclone(rclone_conf=args.config_path)
58
+ info_path = _get_info_path(src=args.src)
59
+ s3_server_side_multi_part_merge(
60
+ rclone=rclone.impl, info_path=info_path, max_workers=1
61
+ )
62
+ return 0
63
+
64
+
65
+ if __name__ == "__main__":
66
+ import sys
67
+
68
+ sys.argv.append("--config")
69
+ sys.argv.append("rclone.conf")
70
+ sys.argv.append(
71
+ "dst:TorrentBooks/aa_misc_data/aa_misc_data/world_lending_library_2024_11.tar.zst-parts/"
72
+ )
73
+ main()
@@ -209,7 +209,10 @@ class InfoJson:
209
209
 
210
210
  @property
211
211
  def parts_dir(self) -> str:
212
- return os.path.dirname(self.src_info)
212
+ parts_dir = os.path.dirname(self.src_info)
213
+ if parts_dir.endswith("/"):
214
+ parts_dir = parts_dir[:-1]
215
+ return parts_dir
213
216
 
214
217
  @property
215
218
  def dst(self) -> str:
@@ -8,8 +8,9 @@ from existing S3 objects using upload_part_copy.
8
8
 
9
9
  import json
10
10
  from dataclasses import dataclass
11
- from typing import Any, Callable
11
+ from typing import Any
12
12
 
13
+ from rclone_api.rclone_impl import RcloneImpl
13
14
  from rclone_api.s3.multipart.finished_piece import FinishedPiece
14
15
 
15
16
 
@@ -46,34 +47,59 @@ class Part:
46
47
 
47
48
  class MergeState:
48
49
 
49
- def __init__(self, finished: list[FinishedPiece], all_parts: list[Part]) -> None:
50
+ def __init__(
51
+ self,
52
+ rclone_impl: RcloneImpl,
53
+ merge_path: str,
54
+ upload_id: str,
55
+ bucket: str,
56
+ dst_key: str,
57
+ finished: list[FinishedPiece],
58
+ all_parts: list[Part],
59
+ ) -> None:
60
+ self.rclone_impl: RcloneImpl = rclone_impl
61
+ self.merge_path: str = merge_path
62
+ self.merge_parts_path: str = f"{merge_path}/merge" # future use?
63
+ self.upload_id: str = upload_id
64
+ self.bucket: str = bucket
65
+ self.dst_key: str = dst_key
50
66
  self.finished: list[FinishedPiece] = list(finished)
51
67
  self.all_parts: list[Part] = list(all_parts)
52
- self.callbacks: list[Callable[[FinishedPiece], None]] = []
53
-
54
- def add_callback(self, callback: Callable[[FinishedPiece], None]) -> None:
55
- self.callbacks.append(callback)
56
68
 
57
69
  def on_finished(self, finished_piece: FinishedPiece) -> None:
58
- for callback in list(self.callbacks):
59
- callback(finished_piece)
70
+ self.finished.append(finished_piece)
71
+
72
+ def remaining_parts(self) -> list[Part]:
73
+ finished_parts: set[int] = set([p.part_number for p in self.finished])
74
+ remaining = [p for p in self.all_parts if p.part_number not in finished_parts]
75
+ return remaining
60
76
 
61
77
  @staticmethod
62
- def from_json_array(json_array: dict) -> "MergeState | Exception":
78
+ def from_json(rclone_impl: RcloneImpl, json: dict) -> "MergeState | Exception":
63
79
  try:
80
+ merge_path = json["merge_path"]
81
+ bucket = json["bucket"]
82
+ dst_key = json["dst_key"]
64
83
  finished: list[FinishedPiece] = FinishedPiece.from_json_array(
65
- json_array["finished"]
84
+ json["finished"]
66
85
  )
67
- all_parts: list[Part | Exception] = [
68
- Part.from_json(j) for j in json_array["all"]
69
- ]
86
+ all_parts: list[Part | Exception] = [Part.from_json(j) for j in json["all"]]
70
87
  all_parts_no_err: list[Part] = [
71
88
  p for p in all_parts if not isinstance(p, Exception)
72
89
  ]
90
+ upload_id: str = json["upload_id"]
73
91
  errs: list[Exception] = [p for p in all_parts if isinstance(p, Exception)]
74
92
  if len(errs):
75
93
  return Exception(f"Errors in parts: {errs}")
76
- return MergeState(finished=finished, all_parts=all_parts_no_err)
94
+ return MergeState(
95
+ rclone_impl=rclone_impl,
96
+ merge_path=merge_path,
97
+ upload_id=upload_id,
98
+ bucket=bucket,
99
+ dst_key=dst_key,
100
+ finished=finished,
101
+ all_parts=all_parts_no_err,
102
+ )
77
103
  except Exception as e:
78
104
  return e
79
105
 
@@ -81,12 +107,18 @@ class MergeState:
81
107
  finished = self.finished.copy()
82
108
  all_parts = self.all_parts.copy()
83
109
  return {
110
+ "merge_path": self.merge_path,
111
+ "bucket": self.bucket,
112
+ "dst_key": self.dst_key,
113
+ "upload_id": self.upload_id,
84
114
  "finished": FinishedPiece.to_json_array(finished),
85
115
  "all": [part.to_json() for part in all_parts],
86
116
  }
87
117
 
88
118
  def to_json_str(self) -> str:
89
- return json.dumps(self.to_json(), indent=1)
119
+ data = self.to_json()
120
+ out = json.dumps(data, indent=2)
121
+ return out
90
122
 
91
123
  def __str__(self):
92
124
  return self.to_json_str()
@@ -1,4 +1,3 @@
1
- import json
2
1
  import warnings
3
2
  from dataclasses import dataclass
4
3
 
@@ -13,9 +12,6 @@ class FinishedPiece:
13
12
  def to_json(self) -> dict:
14
13
  return {"part_number": self.part_number, "etag": self.etag}
15
14
 
16
- def to_json_str(self) -> str:
17
- return json.dumps(self.to_json(), indent=0)
18
-
19
15
  @staticmethod
20
16
  def to_json_array(
21
17
  parts: list["FinishedPiece | EndOfStream"] | list["FinishedPiece"],