rclone-api 1.1.25__tar.gz → 1.1.28__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 (84) hide show
  1. {rclone_api-1.1.25 → rclone_api-1.1.28}/PKG-INFO +1 -1
  2. {rclone_api-1.1.25 → rclone_api-1.1.28}/pyproject.toml +1 -1
  3. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/cmd/copy_large_s3.py +9 -12
  4. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/s3/api.py +1 -1
  5. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/types.py +52 -25
  6. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api.egg-info/PKG-INFO +1 -1
  7. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api.egg-info/SOURCES.txt +1 -1
  8. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_s3.py +1 -1
  9. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_size_suffix.py +9 -0
  10. {rclone_api-1.1.25 → rclone_api-1.1.28}/.aiderignore +0 -0
  11. {rclone_api-1.1.25 → rclone_api-1.1.28}/.github/workflows/lint.yml +0 -0
  12. {rclone_api-1.1.25 → rclone_api-1.1.28}/.github/workflows/push_macos.yml +0 -0
  13. {rclone_api-1.1.25 → rclone_api-1.1.28}/.github/workflows/push_ubuntu.yml +0 -0
  14. {rclone_api-1.1.25 → rclone_api-1.1.28}/.github/workflows/push_win.yml +0 -0
  15. {rclone_api-1.1.25 → rclone_api-1.1.28}/.gitignore +0 -0
  16. {rclone_api-1.1.25 → rclone_api-1.1.28}/.pylintrc +0 -0
  17. {rclone_api-1.1.25 → rclone_api-1.1.28}/.vscode/launch.json +0 -0
  18. {rclone_api-1.1.25 → rclone_api-1.1.28}/.vscode/settings.json +0 -0
  19. {rclone_api-1.1.25 → rclone_api-1.1.28}/.vscode/tasks.json +0 -0
  20. {rclone_api-1.1.25 → rclone_api-1.1.28}/LICENSE +0 -0
  21. {rclone_api-1.1.25 → rclone_api-1.1.28}/MANIFEST.in +0 -0
  22. {rclone_api-1.1.25 → rclone_api-1.1.28}/README.md +0 -0
  23. {rclone_api-1.1.25 → rclone_api-1.1.28}/clean +0 -0
  24. {rclone_api-1.1.25 → rclone_api-1.1.28}/install +0 -0
  25. {rclone_api-1.1.25 → rclone_api-1.1.28}/lint +0 -0
  26. {rclone_api-1.1.25 → rclone_api-1.1.28}/requirements.testing.txt +0 -0
  27. {rclone_api-1.1.25 → rclone_api-1.1.28}/setup.cfg +0 -0
  28. {rclone_api-1.1.25 → rclone_api-1.1.28}/setup.py +0 -0
  29. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/__init__.py +0 -0
  30. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/assets/example.txt +0 -0
  31. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/cli.py +0 -0
  32. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/cmd/list_files.py +0 -0
  33. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/completed_process.py +0 -0
  34. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/config.py +0 -0
  35. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/convert.py +0 -0
  36. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/deprecated.py +0 -0
  37. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/diff.py +0 -0
  38. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/dir.py +0 -0
  39. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/dir_listing.py +0 -0
  40. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/exec.py +0 -0
  41. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/experimental/flags.py +0 -0
  42. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/experimental/flags_base.py +0 -0
  43. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/file.py +0 -0
  44. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/filelist.py +0 -0
  45. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/group_files.py +0 -0
  46. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/mount.py +0 -0
  47. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/process.py +0 -0
  48. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/rclone.py +0 -0
  49. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/remote.py +0 -0
  50. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/rpath.py +0 -0
  51. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/s3/basic_ops.py +0 -0
  52. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/s3/chunk_file.py +0 -0
  53. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/s3/chunk_types.py +0 -0
  54. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/s3/create.py +0 -0
  55. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/s3/types.py +0 -0
  56. /rclone_api-1.1.25/src/rclone_api/s3/chunk_uploader.py → /rclone_api-1.1.28/src/rclone_api/s3/upload_file_multipart.py +0 -0
  57. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/scan_missing_folders.py +0 -0
  58. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/util.py +0 -0
  59. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api/walk.py +0 -0
  60. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  61. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api.egg-info/entry_points.txt +0 -0
  62. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api.egg-info/requires.txt +0 -0
  63. {rclone_api-1.1.25 → rclone_api-1.1.28}/src/rclone_api.egg-info/top_level.txt +0 -0
  64. {rclone_api-1.1.25 → rclone_api-1.1.28}/test +0 -0
  65. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/archive/test_paramiko.py.disabled +0 -0
  66. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_cmd_list_files.py +0 -0
  67. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_copy.py +0 -0
  68. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_copy_file_resumable_s3.py +0 -0
  69. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_copy_files.py +0 -0
  70. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_diff.py +0 -0
  71. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_group_files.py +0 -0
  72. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_is_synced.py +0 -0
  73. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_ls.py +0 -0
  74. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_mount.py +0 -0
  75. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_mount_s3.py +0 -0
  76. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_obscure.py +0 -0
  77. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_rclone_config.py +0 -0
  78. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_remote_control.py +0 -0
  79. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_remotes.py +0 -0
  80. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_scan_missing_folders.py +0 -0
  81. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_size_files.py +0 -0
  82. {rclone_api-1.1.25 → rclone_api-1.1.28}/tests/test_walk.py +0 -0
  83. {rclone_api-1.1.25 → rclone_api-1.1.28}/tox.ini +0 -0
  84. {rclone_api-1.1.25 → rclone_api-1.1.28}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.1.25
3
+ Version: 1.1.28
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -22,7 +22,7 @@ dependencies = [
22
22
  ]
23
23
 
24
24
  # Change this with the version number bump.
25
- version = "1.1.25"
25
+ version = "1.1.28"
26
26
 
27
27
  [tool.setuptools]
28
28
  package-dir = {"" = "src"}
@@ -13,7 +13,7 @@ class Args:
13
13
  src: str
14
14
  dst: str
15
15
  chunk_size: SizeSuffix
16
- threads: int
16
+ read_threads: int
17
17
  write_threads: int
18
18
  retries: int
19
19
  save_state_json: Path
@@ -37,19 +37,19 @@ def _parse_args() -> Args:
37
37
  )
38
38
  parser.add_argument(
39
39
  "--chunk-size",
40
- help="Chunk size that will be read and uploaded in in SizeSuffix (i.e. 128M = 128 megabytes) form",
40
+ help="Chunk size that will be read and uploaded in SizeSuffix form, too low or too high will cause issues",
41
41
  type=str,
42
- default="64MB",
42
+ default="64MB", # if this is too low or too high an s3 service
43
43
  )
44
44
  parser.add_argument(
45
- "--threads",
46
- help="Number of threads to use per chunk",
45
+ "--read-threads",
46
+ help="Number of concurrent read threads per chunk, only one chunk will be read at a time",
47
47
  type=int,
48
- default=8,
48
+ default=32,
49
49
  )
50
50
  parser.add_argument(
51
51
  "--write-threads",
52
- help="Max number of chunks to upload in parallel to the destination",
52
+ help="Max number of chunks to upload in parallel to the destination, each chunk is uploaded in a separate thread",
53
53
  type=int,
54
54
  default=64,
55
55
  )
@@ -67,7 +67,7 @@ def _parse_args() -> Args:
67
67
  src=args.src,
68
68
  dst=args.dst,
69
69
  chunk_size=SizeSuffix(args.chunk_size),
70
- threads=args.threads,
70
+ read_threads=args.read_threads,
71
71
  write_threads=args.write_threads,
72
72
  retries=args.retries,
73
73
  save_state_json=args.resume_json,
@@ -85,11 +85,8 @@ def main() -> int:
85
85
  src=args.src,
86
86
  dst=args.dst,
87
87
  chunk_size=args.chunk_size,
88
- read_threads=args.threads,
88
+ read_threads=args.read_threads,
89
89
  write_threads=args.write_threads,
90
- # vfs_read_chunk_size=unit_chunk,
91
- # vfs_read_chunk_size_limit=args.chunk_size,
92
- # vfs_read_chunk_streams=args.threads,
93
90
  retries=args.retries,
94
91
  save_state_json=args.save_state_json,
95
92
  verbose=args.verbose,
@@ -9,9 +9,9 @@ from rclone_api.s3.basic_ops import (
9
9
  list_bucket_contents,
10
10
  upload_file,
11
11
  )
12
- from rclone_api.s3.chunk_uploader import MultiUploadResult, upload_file_multipart
13
12
  from rclone_api.s3.create import create_s3_client
14
13
  from rclone_api.s3.types import S3Credentials, S3MutliPartUploadConfig, S3UploadTarget
14
+ from rclone_api.s3.upload_file_multipart import MultiUploadResult, upload_file_multipart
15
15
 
16
16
  _MIN_THRESHOLD_FOR_CHUNKING = 5 * 1024 * 1024
17
17
 
@@ -37,41 +37,68 @@ class SizeResult:
37
37
 
38
38
 
39
39
  def _to_size_suffix(size: int) -> str:
40
- if size < 1024:
41
- return f"{size}B"
42
- elif size < 1024**2:
43
- val = size / 1024
44
- unit = "K"
45
- elif size < 1024**3:
46
- val = size / (1024**2)
47
- unit = "M"
48
- elif size < 1024**4:
49
- val = size / (1024**3)
50
- unit = "G"
51
- elif size < 1024**5:
52
- val = size / (1024**4)
53
- unit = "T"
54
- elif size < 1024**6:
55
- val = size / (1024**5)
56
- unit = "P"
57
- else:
58
- raise ValueError(f"Invalid size: {size}")
59
-
60
- # If the float is an integer, drop the decimal, otherwise format with one decimal.
61
- return f"{int(val) if val.is_integer() else f'{val:.1f}'}{unit}"
40
+ def _convert(size: int) -> tuple[float, str]:
41
+ val: float
42
+ unit: str
43
+ if size < 1024:
44
+ val = size
45
+ unit = "B"
46
+ elif size < 1024**2:
47
+ val = size / 1024
48
+ unit = "K"
49
+ elif size < 1024**3:
50
+ val = size / (1024**2)
51
+ unit = "M"
52
+ elif size < 1024**4:
53
+ val = size / (1024**3)
54
+ unit = "G"
55
+ elif size < 1024**5:
56
+ val = size / (1024**4)
57
+ unit = "T"
58
+ elif size < 1024**6:
59
+ val = size / (1024**5)
60
+ unit = "P"
61
+ else:
62
+ raise ValueError(f"Invalid size: {size}")
63
+
64
+ return val, unit
65
+
66
+ def _fmt(_val: float | int, _unit: str) -> str:
67
+ # If the float is an integer, drop the decimal, otherwise format with one decimal.
68
+ val_str: str = str(_val)
69
+ if not val_str.endswith(".0"):
70
+ first_str: str = f"{_val:.1f}"
71
+ else:
72
+ first_str = str(int(_val))
73
+ return first_str + _unit
74
+
75
+ val, unit = _convert(size)
76
+ out = _fmt(val, unit)
77
+ # Now round trip the value to fix floating point issues via rounding.
78
+ int_val = _from_size_suffix(out)
79
+ val, unit = _convert(int_val)
80
+ out = _fmt(val, unit)
81
+ return out
62
82
 
63
83
 
64
84
  # Update regex to allow decimals (e.g., 16.5MB)
65
85
  _PATTERN_SIZE_SUFFIX = re.compile(r"^(\d+(?:\.\d+)?)([A-Za-z]+)$")
66
86
 
67
87
 
88
+ def _parse_elements(value: str) -> tuple[str, str] | None:
89
+ match = _PATTERN_SIZE_SUFFIX.match(value)
90
+ if match is None:
91
+ return None
92
+ return match.group(1), match.group(2)
93
+
94
+
68
95
  def _from_size_suffix(size: str) -> int:
69
96
  if size == "0":
70
97
  return 0
71
- match = _PATTERN_SIZE_SUFFIX.match(size)
72
- if match is None:
98
+ pair = _parse_elements(size)
99
+ if pair is None:
73
100
  raise ValueError(f"Invalid size suffix: {size}")
74
- num_str, suffix = match.group(1), match.group(2)
101
+ num_str, suffix = pair
75
102
  n = float(num_str)
76
103
  # Determine the unit from the first letter (e.g., "M" from "MB")
77
104
  unit = suffix[0].upper()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.1.25
3
+ Version: 1.1.28
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -57,9 +57,9 @@ src/rclone_api/s3/api.py
57
57
  src/rclone_api/s3/basic_ops.py
58
58
  src/rclone_api/s3/chunk_file.py
59
59
  src/rclone_api/s3/chunk_types.py
60
- src/rclone_api/s3/chunk_uploader.py
61
60
  src/rclone_api/s3/create.py
62
61
  src/rclone_api/s3/types.py
62
+ src/rclone_api/s3/upload_file_multipart.py
63
63
  tests/test_cmd_list_files.py
64
64
  tests/test_copy.py
65
65
  tests/test_copy_file_resumable_s3.py
@@ -6,9 +6,9 @@ from pathlib import Path
6
6
  from dotenv import load_dotenv
7
7
 
8
8
  from rclone_api.s3.api import S3Client
9
- from rclone_api.s3.chunk_uploader import MultiUploadResult
10
9
  from rclone_api.s3.create import S3Provider
11
10
  from rclone_api.s3.types import S3Credentials, S3MutliPartUploadConfig, S3UploadTarget
11
+ from rclone_api.s3.upload_file_multipart import MultiUploadResult
12
12
 
13
13
  load_dotenv()
14
14
 
@@ -24,6 +24,15 @@ class RcloneSuffixSize(unittest.TestCase):
24
24
  out_str = str(size_suffix)
25
25
  self.assertEqual(out_str, "16.5M")
26
26
 
27
+ def test_float_suffix_border(self) -> None:
28
+ size_suffix = SizeSuffix("1M")
29
+ size_int = size_suffix.as_int()
30
+ size_int -= 1
31
+ # now assert that the string value is the same as the input
32
+ tmp = SizeSuffix(size_int)
33
+ out_str = tmp.as_str()
34
+ self.assertEqual(out_str, "1M")
35
+
27
36
 
28
37
  if __name__ == "__main__":
29
38
  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