rclone-api 1.1.10__tar.gz → 1.1.12__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 (85) hide show
  1. {rclone_api-1.1.10 → rclone_api-1.1.12}/PKG-INFO +1 -1
  2. {rclone_api-1.1.10 → rclone_api-1.1.12}/pyproject.toml +1 -1
  3. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/cmd/copy_large_s3.py +11 -2
  4. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/rclone.py +6 -3
  5. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/s3/chunk_types.py +14 -0
  6. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/s3/chunk_uploader.py +21 -3
  7. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/s3/types.py +1 -0
  8. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api.egg-info/PKG-INFO +1 -1
  9. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api.egg-info/SOURCES.txt +0 -1
  10. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_s3.py +2 -0
  11. rclone_api-1.1.10/rclone-mounted-ranged-download.conf.old3393025366 +0 -0
  12. {rclone_api-1.1.10 → rclone_api-1.1.12}/.aiderignore +0 -0
  13. {rclone_api-1.1.10 → rclone_api-1.1.12}/.github/workflows/lint.yml +0 -0
  14. {rclone_api-1.1.10 → rclone_api-1.1.12}/.github/workflows/push_macos.yml +0 -0
  15. {rclone_api-1.1.10 → rclone_api-1.1.12}/.github/workflows/push_ubuntu.yml +0 -0
  16. {rclone_api-1.1.10 → rclone_api-1.1.12}/.github/workflows/push_win.yml +0 -0
  17. {rclone_api-1.1.10 → rclone_api-1.1.12}/.gitignore +0 -0
  18. {rclone_api-1.1.10 → rclone_api-1.1.12}/.pylintrc +0 -0
  19. {rclone_api-1.1.10 → rclone_api-1.1.12}/.vscode/launch.json +0 -0
  20. {rclone_api-1.1.10 → rclone_api-1.1.12}/.vscode/settings.json +0 -0
  21. {rclone_api-1.1.10 → rclone_api-1.1.12}/.vscode/tasks.json +0 -0
  22. {rclone_api-1.1.10 → rclone_api-1.1.12}/LICENSE +0 -0
  23. {rclone_api-1.1.10 → rclone_api-1.1.12}/MANIFEST.in +0 -0
  24. {rclone_api-1.1.10 → rclone_api-1.1.12}/README.md +0 -0
  25. {rclone_api-1.1.10 → rclone_api-1.1.12}/clean +0 -0
  26. {rclone_api-1.1.10 → rclone_api-1.1.12}/install +0 -0
  27. {rclone_api-1.1.10 → rclone_api-1.1.12}/lint +0 -0
  28. {rclone_api-1.1.10 → rclone_api-1.1.12}/requirements.testing.txt +0 -0
  29. {rclone_api-1.1.10 → rclone_api-1.1.12}/setup.cfg +0 -0
  30. {rclone_api-1.1.10 → rclone_api-1.1.12}/setup.py +0 -0
  31. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/__init__.py +0 -0
  32. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/assets/example.txt +0 -0
  33. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/cli.py +0 -0
  34. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/cmd/list_files.py +0 -0
  35. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/completed_process.py +0 -0
  36. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/config.py +0 -0
  37. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/convert.py +0 -0
  38. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/deprecated.py +0 -0
  39. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/diff.py +0 -0
  40. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/dir.py +0 -0
  41. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/dir_listing.py +0 -0
  42. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/exec.py +0 -0
  43. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/experimental/flags.py +0 -0
  44. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/experimental/flags_base.py +0 -0
  45. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/file.py +0 -0
  46. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/filelist.py +0 -0
  47. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/group_files.py +0 -0
  48. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/mount.py +0 -0
  49. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/process.py +0 -0
  50. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/remote.py +0 -0
  51. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/rpath.py +0 -0
  52. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/s3/api.py +0 -0
  53. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/s3/basic_ops.py +0 -0
  54. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/s3/chunk_file.py +0 -0
  55. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/s3/create.py +0 -0
  56. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/scan_missing_folders.py +0 -0
  57. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/types.py +0 -0
  58. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/util.py +0 -0
  59. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api/walk.py +0 -0
  60. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  61. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api.egg-info/entry_points.txt +0 -0
  62. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api.egg-info/requires.txt +0 -0
  63. {rclone_api-1.1.10 → rclone_api-1.1.12}/src/rclone_api.egg-info/top_level.txt +0 -0
  64. {rclone_api-1.1.10 → rclone_api-1.1.12}/test +0 -0
  65. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/archive/test_paramiko.py.disabled +0 -0
  66. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_cmd_list_files.py +0 -0
  67. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_copy.py +0 -0
  68. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_copy_files.py +0 -0
  69. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_diff.py +0 -0
  70. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_group_files.py +0 -0
  71. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_is_synced.py +0 -0
  72. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_ls.py +0 -0
  73. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_mount.py +0 -0
  74. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_mount_s3.py +0 -0
  75. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_mounted_ranged_download.py +0 -0
  76. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_obscure.py +0 -0
  77. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_rclone_config.py +0 -0
  78. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_remote_control.py +0 -0
  79. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_remotes.py +0 -0
  80. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_scan_missing_folders.py +0 -0
  81. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_size_files.py +0 -0
  82. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_size_suffix.py +0 -0
  83. {rclone_api-1.1.10 → rclone_api-1.1.12}/tests/test_walk.py +0 -0
  84. {rclone_api-1.1.10 → rclone_api-1.1.12}/tox.ini +0 -0
  85. {rclone_api-1.1.10 → rclone_api-1.1.12}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.1.10
3
+ Version: 1.1.12
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -21,7 +21,7 @@ dependencies = [
21
21
  ]
22
22
 
23
23
  # Change this with the version number bump.
24
- version = "1.1.10"
24
+ version = "1.1.12"
25
25
 
26
26
  [tool.setuptools]
27
27
  package-dir = {"" = "src"}
@@ -14,6 +14,7 @@ class Args:
14
14
  dst: str
15
15
  chunk_size: SizeSuffix
16
16
  threads: int
17
+ write_threads: int
17
18
  retries: int
18
19
  save_state_json: Path
19
20
  verbose: bool
@@ -38,7 +39,7 @@ def _parse_args() -> Args:
38
39
  "--chunk-size",
39
40
  help="Chunk size that will be read and uploaded in in SizeSuffix (i.e. 128M = 128 megabytes) form",
40
41
  type=str,
41
- default="1G",
42
+ default="512MB",
42
43
  )
43
44
  parser.add_argument(
44
45
  "--threads",
@@ -46,6 +47,12 @@ def _parse_args() -> Args:
46
47
  type=int,
47
48
  default=64,
48
49
  )
50
+ parser.add_argument(
51
+ "--write-threads",
52
+ help="Max number of chunks to upload in parallel to the destination",
53
+ type=int,
54
+ default=64,
55
+ )
49
56
  parser.add_argument("--retries", help="Number of retries", type=int, default=3)
50
57
  parser.add_argument(
51
58
  "--resume-json",
@@ -61,6 +68,7 @@ def _parse_args() -> Args:
61
68
  dst=args.dst,
62
69
  chunk_size=SizeSuffix(args.chunk_size),
63
70
  threads=args.threads,
71
+ write_threads=args.write_threads,
64
72
  retries=args.retries,
65
73
  save_state_json=args.resume_json,
66
74
  verbose=args.verbose,
@@ -77,7 +85,8 @@ def main() -> int:
77
85
  src=args.src,
78
86
  dst=args.dst,
79
87
  chunk_size=args.chunk_size,
80
- threads=args.threads,
88
+ read_threads=args.threads,
89
+ write_threads=args.write_threads,
81
90
  # vfs_read_chunk_size=unit_chunk,
82
91
  # vfs_read_chunk_size_limit=args.chunk_size,
83
92
  # vfs_read_chunk_streams=args.threads,
@@ -678,7 +678,8 @@ class Rclone:
678
678
  dst: str,
679
679
  save_state_json: Path,
680
680
  chunk_size: SizeSuffix | None = None,
681
- threads: int = 16,
681
+ read_threads: int = 16,
682
+ write_threads: int = 16,
682
683
  retries: int = 3,
683
684
  verbose: bool | None = None,
684
685
  max_chunks_before_suspension: int | None = None,
@@ -691,10 +692,10 @@ class Rclone:
691
692
 
692
693
  other_args: list[str] = ["--no-modtime", "--vfs-read-wait", "1s"]
693
694
  chunk_size = chunk_size or SizeSuffix("128M")
694
- unit_chunk_size = chunk_size / threads
695
+ unit_chunk_size = chunk_size / read_threads
695
696
  vfs_read_chunk_size = unit_chunk_size
696
697
  vfs_read_chunk_size_limit = chunk_size
697
- vfs_read_chunk_streams = threads
698
+ vfs_read_chunk_streams = read_threads
698
699
  vfs_disk_space_total_size = chunk_size
699
700
  assert (
700
701
  chunk_size.as_int() % vfs_read_chunk_size.as_int() == 0
@@ -773,6 +774,7 @@ class Rclone:
773
774
  client = S3Client(s3_creds)
774
775
  config: S3MutliPartUploadConfig = S3MutliPartUploadConfig(
775
776
  chunk_size=chunk_size.as_int(),
777
+ max_write_threads=write_threads,
776
778
  retries=retries,
777
779
  resume_path_json=save_state_json,
778
780
  max_chunks_before_suspension=max_chunks_before_suspension,
@@ -797,6 +799,7 @@ class Rclone:
797
799
  upload_config = S3MutliPartUploadConfig(
798
800
  chunk_size=chunk_size.as_int(),
799
801
  retries=retries,
802
+ max_write_threads=write_threads,
800
803
  resume_path_json=save_state_json,
801
804
  max_chunks_before_suspension=max_chunks_before_suspension,
802
805
  )
@@ -1,3 +1,4 @@
1
+ import hashlib
1
2
  import json
2
3
  import os
3
4
  import time
@@ -103,6 +104,19 @@ class UploadInfo:
103
104
  return
104
105
  self._total_chunks = self.total_chunks()
105
106
 
107
+ def fingerprint(self) -> str:
108
+ # hash the attributes that are used to identify the upload
109
+ hasher = hashlib.sha256()
110
+ # first is file size
111
+ hasher.update(str(self.file_size).encode("utf-8"))
112
+ # second is the file path
113
+ hasher.update(str(self.src_file_path).encode("utf-8"))
114
+ # next is chunk size
115
+ hasher.update(str(self.chunk_size).encode("utf-8"))
116
+ # next is the number of parts
117
+ hasher.update(str(self._total_chunks).encode("utf-8"))
118
+ return hasher.hexdigest()
119
+
106
120
  def to_json(self) -> dict:
107
121
  json_dict = {}
108
122
  for f in fields(self):
@@ -115,6 +115,7 @@ def upload_file_multipart(
115
115
  object_name: str,
116
116
  resumable_info_path: Path | None,
117
117
  chunk_size: int = 16 * 1024 * 1024, # Default chunk size is 16MB; can be overridden
118
+ upload_threads: int = 16,
118
119
  retries: int = 20,
119
120
  max_chunks_before_suspension: int | None = None,
120
121
  abort_transfer_on_failure: bool = False,
@@ -162,7 +163,25 @@ def upload_file_multipart(
162
163
  return upload_state
163
164
 
164
165
  filechunks: Queue[FileChunk | None] = Queue(10)
165
- upload_state = get_upload_state() or make_new_state()
166
+ new_state = make_new_state()
167
+ loaded_state = get_upload_state()
168
+
169
+ if loaded_state is None:
170
+ upload_state = new_state
171
+ else:
172
+ # if the file size has changed, we cannot resume
173
+ if (
174
+ loaded_state.upload_info.fingerprint()
175
+ != new_state.upload_info.fingerprint()
176
+ ):
177
+ locked_print(
178
+ f"Cannot resume upload: file size changed, starting over for {file_path}"
179
+ )
180
+ _abort_previous_upload(loaded_state)
181
+ upload_state = new_state
182
+ else:
183
+ upload_state = loaded_state
184
+
166
185
  try:
167
186
  upload_state.update_source_file(file_path)
168
187
  except ValueError as e:
@@ -179,7 +198,6 @@ def upload_file_multipart(
179
198
  )
180
199
  started_new_upload = finished == 0
181
200
  upload_info = upload_state.upload_info
182
- max_workers = 8
183
201
 
184
202
  chunker_errors: Queue[Exception] = Queue()
185
203
 
@@ -202,7 +220,7 @@ def upload_file_multipart(
202
220
  thread_chunker = Thread(target=chunker_task, daemon=True)
203
221
  thread_chunker.start()
204
222
 
205
- with ThreadPoolExecutor(max_workers=max_workers) as executor:
223
+ with ThreadPoolExecutor(max_workers=upload_threads) as executor:
206
224
  while True:
207
225
  file_chunk: FileChunk | None = filechunks.get()
208
226
  if file_chunk is None:
@@ -46,6 +46,7 @@ class S3MutliPartUploadConfig:
46
46
  chunk_size: int
47
47
  retries: int
48
48
  resume_path_json: Path
49
+ max_write_threads: int
49
50
  max_chunks_before_suspension: int | None = None
50
51
  mount_path: Path | None = (
51
52
  None # If set this will be used to mount the src file, otherwise it's one is chosen automatically
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.1.10
3
+ Version: 1.1.12
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -8,7 +8,6 @@ clean
8
8
  install
9
9
  lint
10
10
  pyproject.toml
11
- rclone-mounted-ranged-download.conf.old3393025366
12
11
  requirements.testing.txt
13
12
  setup.py
14
13
  test
@@ -74,6 +74,7 @@ class RcloneS3Tester(unittest.TestCase):
74
74
  # Uploads one chunk then stops.
75
75
  upload_config_partial: S3MutliPartUploadConfig = S3MutliPartUploadConfig(
76
76
  chunk_size=chunk_size,
77
+ max_write_threads=16,
77
78
  retries=0,
78
79
  resume_path_json=state_json,
79
80
  max_chunks_before_suspension=1,
@@ -82,6 +83,7 @@ class RcloneS3Tester(unittest.TestCase):
82
83
  # Finishes the upload.
83
84
  upload_config_all: S3MutliPartUploadConfig = S3MutliPartUploadConfig(
84
85
  chunk_size=chunk_size,
86
+ max_write_threads=16,
85
87
  retries=0,
86
88
  resume_path_json=state_json,
87
89
  max_chunks_before_suspension=None,
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