rclone-api 1.1.60__tar.gz → 1.1.61__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 (86) hide show
  1. {rclone_api-1.1.60 → rclone_api-1.1.61}/PKG-INFO +1 -1
  2. {rclone_api-1.1.60 → rclone_api-1.1.61}/pyproject.toml +1 -1
  3. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/profile/mount_copy_bytes.py +15 -10
  4. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/rclone.py +60 -2
  5. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/types.py +8 -0
  6. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api.egg-info/PKG-INFO +1 -1
  7. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_copy_bytes.py +4 -2
  8. {rclone_api-1.1.60 → rclone_api-1.1.61}/.aiderignore +0 -0
  9. {rclone_api-1.1.60 → rclone_api-1.1.61}/.github/workflows/lint.yml +0 -0
  10. {rclone_api-1.1.60 → rclone_api-1.1.61}/.github/workflows/push_macos.yml +0 -0
  11. {rclone_api-1.1.60 → rclone_api-1.1.61}/.github/workflows/push_ubuntu.yml +0 -0
  12. {rclone_api-1.1.60 → rclone_api-1.1.61}/.github/workflows/push_win.yml +0 -0
  13. {rclone_api-1.1.60 → rclone_api-1.1.61}/.gitignore +0 -0
  14. {rclone_api-1.1.60 → rclone_api-1.1.61}/.pylintrc +0 -0
  15. {rclone_api-1.1.60 → rclone_api-1.1.61}/.vscode/launch.json +0 -0
  16. {rclone_api-1.1.60 → rclone_api-1.1.61}/.vscode/settings.json +0 -0
  17. {rclone_api-1.1.60 → rclone_api-1.1.61}/.vscode/tasks.json +0 -0
  18. {rclone_api-1.1.60 → rclone_api-1.1.61}/LICENSE +0 -0
  19. {rclone_api-1.1.60 → rclone_api-1.1.61}/MANIFEST.in +0 -0
  20. {rclone_api-1.1.60 → rclone_api-1.1.61}/README.md +0 -0
  21. {rclone_api-1.1.60 → rclone_api-1.1.61}/clean +0 -0
  22. {rclone_api-1.1.60 → rclone_api-1.1.61}/install +0 -0
  23. {rclone_api-1.1.60 → rclone_api-1.1.61}/lint +0 -0
  24. {rclone_api-1.1.60 → rclone_api-1.1.61}/requirements.testing.txt +0 -0
  25. {rclone_api-1.1.60 → rclone_api-1.1.61}/setup.cfg +0 -0
  26. {rclone_api-1.1.60 → rclone_api-1.1.61}/setup.py +0 -0
  27. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/__init__.py +0 -0
  28. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/assets/example.txt +0 -0
  29. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/cli.py +0 -0
  30. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/cmd/copy_large_s3.py +0 -0
  31. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/cmd/list_files.py +0 -0
  32. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/completed_process.py +0 -0
  33. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/config.py +0 -0
  34. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/convert.py +0 -0
  35. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/deprecated.py +0 -0
  36. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/diff.py +0 -0
  37. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/dir.py +0 -0
  38. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/dir_listing.py +0 -0
  39. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/exec.py +0 -0
  40. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/experimental/flags.py +0 -0
  41. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/experimental/flags_base.py +0 -0
  42. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/file.py +0 -0
  43. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/filelist.py +0 -0
  44. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/group_files.py +0 -0
  45. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/mount.py +0 -0
  46. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/process.py +0 -0
  47. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/remote.py +0 -0
  48. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/rpath.py +0 -0
  49. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/s3/api.py +0 -0
  50. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/s3/basic_ops.py +0 -0
  51. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/s3/chunk_file.py +0 -0
  52. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/s3/chunk_types.py +0 -0
  53. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/s3/create.py +0 -0
  54. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/s3/types.py +0 -0
  55. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/s3/upload_file_multipart.py +0 -0
  56. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/scan_missing_folders.py +0 -0
  57. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/util.py +0 -0
  58. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api/walk.py +0 -0
  59. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api.egg-info/SOURCES.txt +0 -0
  60. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  61. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api.egg-info/entry_points.txt +0 -0
  62. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api.egg-info/requires.txt +0 -0
  63. {rclone_api-1.1.60 → rclone_api-1.1.61}/src/rclone_api.egg-info/top_level.txt +0 -0
  64. {rclone_api-1.1.60 → rclone_api-1.1.61}/test +0 -0
  65. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/archive/test_paramiko.py.disabled +0 -0
  66. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_cmd_list_files.py +0 -0
  67. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_copy.py +0 -0
  68. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_copy_file_resumable_s3.py +0 -0
  69. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_copy_files.py +0 -0
  70. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_diff.py +0 -0
  71. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_group_files.py +0 -0
  72. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_is_synced.py +0 -0
  73. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_ls.py +0 -0
  74. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_mount.py +0 -0
  75. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_mount_s3.py +0 -0
  76. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_obscure.py +0 -0
  77. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_rclone_config.py +0 -0
  78. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_remote_control.py +0 -0
  79. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_remotes.py +0 -0
  80. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_s3.py +0 -0
  81. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_scan_missing_folders.py +0 -0
  82. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_size_files.py +0 -0
  83. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_size_suffix.py +0 -0
  84. {rclone_api-1.1.60 → rclone_api-1.1.61}/tests/test_walk.py +0 -0
  85. {rclone_api-1.1.60 → rclone_api-1.1.61}/tox.ini +0 -0
  86. {rclone_api-1.1.60 → rclone_api-1.1.61}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.1.60
3
+ Version: 1.1.61
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -23,7 +23,7 @@ dependencies = [
23
23
  ]
24
24
 
25
25
  # Change this with the version number bump.
26
- version = "1.1.60"
26
+ version = "1.1.61"
27
27
 
28
28
  [tool.setuptools]
29
29
  package-dir = {"" = "src"}
@@ -6,7 +6,6 @@ import argparse
6
6
  import os
7
7
  import shutil
8
8
  import time
9
- from concurrent.futures import Future, ThreadPoolExecutor
10
9
  from dataclasses import dataclass
11
10
  from pathlib import Path
12
11
 
@@ -119,12 +118,14 @@ def _run_profile(
119
118
  print("#" * 80)
120
119
  net_io_start = psutil.net_io_counters()
121
120
  start = time.time()
121
+ chunk_size = size // transfers
122
122
  bytes_or_err: bytes | Exception = rclone.copy_bytes(
123
123
  src=src_file,
124
124
  offset=offset.as_int(),
125
125
  length=size.as_int(),
126
+ chunk_size=chunk_size,
126
127
  direct_io=direct_io,
127
- transfers=transfers,
128
+ max_threads=transfers,
128
129
  mount_log=mount_log,
129
130
  )
130
131
  diff = time.time() - start
@@ -138,6 +139,8 @@ def _run_profile(
138
139
  assert len(bytes_or_err) == size.as_int(), f"Length: {len(bytes_or_err)} != {size}"
139
140
 
140
141
  # print io stats
142
+ # disabling num for now
143
+ num = 1
141
144
  bytes_sent = (net_io_end.bytes_sent - net_io_start.bytes_sent) // num
142
145
  bytes_recv = (net_io_end.bytes_recv - net_io_start.bytes_recv) // num
143
146
  packets_sent = (net_io_end.packets_sent - net_io_start.packets_sent) // num
@@ -230,8 +233,8 @@ def main() -> None:
230
233
  shutil.rmtree(mount_root_path)
231
234
 
232
235
  args = _parse_args()
233
- transfer_list = [1]
234
- parallel_workers = args.num
236
+ transfer_list = [args.num]
237
+ # parallel_workers = args.num
235
238
 
236
239
  def task(
237
240
  offset: SizeSuffix,
@@ -250,12 +253,14 @@ def main() -> None:
250
253
  num=args.num,
251
254
  )
252
255
 
253
- with ThreadPoolExecutor(max_workers=parallel_workers) as _:
254
- tasks: list[Future] = []
255
- for i in range(parallel_workers):
256
- offset = SizeSuffix(i * 1024 * 1024 * 256)
257
- future = ThreadPoolExecutor().submit(lambda: task(offset=offset))
258
- tasks.append(future)
256
+ task(SizeSuffix(0))
257
+
258
+ # with ThreadPoolExecutor(max_workers=parallel_workers) as _:
259
+ # tasks: list[Future] = []
260
+ # for i in range(parallel_workers):
261
+ # offset = SizeSuffix(i * 1024 * 1024 * 256)
262
+ # future = ThreadPoolExecutor().submit(lambda: task(offset=offset))
263
+ # tasks.append(future)
259
264
 
260
265
 
261
266
  if __name__ == "__main__":
@@ -815,7 +815,7 @@ class Rclone:
815
815
  )
816
816
  return out
817
817
 
818
- def copy_bytes(
818
+ def _copy_bytes(
819
819
  self,
820
820
  src: str,
821
821
  offset: int,
@@ -844,7 +844,7 @@ class Rclone:
844
844
  max_read_ahead = SizeSuffix(vfs_read_chunk_size.as_int())
845
845
 
846
846
  # other_args += ["--vfs-read-chunk-size", str(vfs_read_chunk_size)]
847
- other_args += ["--vfs-read-chunk-size", str(0)]
847
+ other_args += ["--vfs-read-chunk-size", str(vfs_read_chunk_size)]
848
848
  other_args += ["--vfs-read-chunk-size-limit", str(vfs_read_chunk_size_limit)]
849
849
  other_args += ["--vfs-read-chunk-streams", str(vfs_read_chunk_streams)]
850
850
  other_args += ["--vfs-disk-space-total-size", str(vfs_disk_space_total_size)]
@@ -883,6 +883,64 @@ class Rclone:
883
883
  except Exception as e:
884
884
  return e
885
885
 
886
+ def copy_bytes(
887
+ self,
888
+ src: str,
889
+ offset: int,
890
+ length: int,
891
+ chunk_size: SizeSuffix,
892
+ max_threads: int = 1,
893
+ # If outfile is supplied then bytes are written to this file and success returns bytes(0)
894
+ outfile: Path | None = None,
895
+ mount_log: Path | None = None,
896
+ direct_io: bool = True,
897
+ ) -> bytes | Exception:
898
+ """Copy bytes from a file to another file."""
899
+ # determine number of threads from chunk size
900
+ threads = min(max_threads, length // chunk_size.as_int())
901
+
902
+ if threads == 1:
903
+ return self._copy_bytes(
904
+ src,
905
+ offset,
906
+ length,
907
+ transfers=1,
908
+ outfile=outfile,
909
+ mount_log=mount_log,
910
+ direct_io=direct_io,
911
+ )
912
+ else:
913
+ futures: list[Future] = []
914
+ with ThreadPoolExecutor(max_workers=threads) as executor:
915
+ for i in range(threads):
916
+ start = i * chunk_size.as_int()
917
+ end = start + chunk_size.as_int()
918
+ if i == threads - 1:
919
+ end = length
920
+ future = executor.submit(
921
+ self._copy_bytes,
922
+ src,
923
+ offset + start,
924
+ end - start,
925
+ transfers=1,
926
+ outfile=None,
927
+ mount_log=mount_log,
928
+ direct_io=direct_io,
929
+ )
930
+ futures.append(future)
931
+ data: bytes = b""
932
+ for future in futures:
933
+ chunk: bytes | Exception = future.result()
934
+ if isinstance(chunk, Exception):
935
+ return chunk
936
+ data += chunk
937
+ if outfile is not None:
938
+ with open(outfile, "wb") as out:
939
+ out.write(data)
940
+ del data
941
+ return bytes(0)
942
+ return data
943
+
886
944
  def copy_dir(
887
945
  self, src: str | Dir, dst: str | Dir, args: list[str] | None = None
888
946
  ) -> CompletedProcess:
@@ -170,3 +170,11 @@ class SizeSuffix:
170
170
  raise ZeroDivisionError("Division by zero is undefined")
171
171
  # Use floor division to maintain integer arithmetic.
172
172
  return SizeSuffix(self._size // other_int._size)
173
+
174
+ # support / division
175
+ def __floordiv__(self, other: "int | SizeSuffix") -> "SizeSuffix":
176
+ other_int = SizeSuffix(other)
177
+ if other_int._size == 0:
178
+ raise ZeroDivisionError("Division by zero is undefined")
179
+ # Use floor division to maintain integer arithmetic.
180
+ return SizeSuffix(self._size // other_int._size)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.1.60
3
+ Version: 1.1.61
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -9,7 +9,7 @@ from pathlib import Path
9
9
 
10
10
  from dotenv import load_dotenv
11
11
 
12
- from rclone_api import Config, Rclone
12
+ from rclone_api import Config, Rclone, SizeSuffix
13
13
 
14
14
  load_dotenv()
15
15
 
@@ -76,7 +76,8 @@ class RcloneCopyBytesTester(unittest.TestCase):
76
76
  src="dst:rclone-api-unit-test/zachs_video/breaking_ai_mind.mp4",
77
77
  offset=0,
78
78
  length=1024 * 1024,
79
- transfers=1,
79
+ chunk_size=SizeSuffix(1024 * 1024),
80
+ max_threads=1,
80
81
  )
81
82
  if isinstance(bytes_or_err, Exception):
82
83
  print(bytes_or_err)
@@ -95,6 +96,7 @@ class RcloneCopyBytesTester(unittest.TestCase):
95
96
  src="dst:rclone-api-unit-test/zachs_video/breaking_ai_mind.mp4",
96
97
  offset=0,
97
98
  length=1024 * 1024,
99
+ chunk_size=SizeSuffix(1024 * 1024),
98
100
  outfile=tmp,
99
101
  mount_log=log,
100
102
  )
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