rclone-api 1.1.7__py2.py3-none-any.whl → 1.1.8__py2.py3-none-any.whl

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.
@@ -12,8 +12,8 @@ class Args:
12
12
  config_path: Path
13
13
  src: str
14
14
  dst: str
15
- chunk_size_mb: SizeSuffix
16
- read_concurrent_chunks: int
15
+ chunk_size: SizeSuffix
16
+ threads: int
17
17
  retries: int
18
18
  save_state_json: Path
19
19
  verbose: bool
@@ -38,13 +38,13 @@ def _parse_args() -> Args:
38
38
  "--chunk-size",
39
39
  help="Chunk size that will be read and uploaded in in SizeSuffix (i.e. 128M = 128 megabytes) form",
40
40
  type=str,
41
- default="128M",
41
+ default="512M",
42
42
  )
43
43
  parser.add_argument(
44
- "--read-concurrent-chunks",
45
- help="Maximum number of chunks to read in a look ahead cache",
44
+ "--threads",
45
+ help="Number of threads to use per chunk",
46
46
  type=int,
47
- default=1,
47
+ default=16,
48
48
  )
49
49
  parser.add_argument("--retries", help="Number of retries", type=int, default=3)
50
50
  parser.add_argument(
@@ -59,8 +59,8 @@ def _parse_args() -> Args:
59
59
  config_path=Path(args.config),
60
60
  src=args.src,
61
61
  dst=args.dst,
62
- chunk_size_mb=SizeSuffix(args.chunk_size),
63
- read_concurrent_chunks=args.read_concurrent_chunks,
62
+ chunk_size=SizeSuffix(args.chunk_size),
63
+ threads=args.threads,
64
64
  retries=args.retries,
65
65
  save_state_json=args.resume_json,
66
66
  verbose=args.verbose,
@@ -72,11 +72,15 @@ def main() -> int:
72
72
  """Main entry point."""
73
73
  args = _parse_args()
74
74
  rclone = Rclone(rclone_conf=args.config_path)
75
+ # unit_chunk = args.chunk_size / args.threads
75
76
  rslt: MultiUploadResult = rclone.copy_file_resumable_s3(
76
77
  src=args.src,
77
78
  dst=args.dst,
78
- chunk_size=args.chunk_size_mb * _1MB,
79
- concurrent_chunks=args.read_concurrent_chunks,
79
+ chunk_size=args.chunk_size,
80
+ threads=args.threads,
81
+ # vfs_read_chunk_size=unit_chunk,
82
+ # vfs_read_chunk_size_limit=args.chunk_size,
83
+ # vfs_read_chunk_streams=args.threads,
80
84
  retries=args.retries,
81
85
  save_state_json=args.save_state_json,
82
86
  verbose=args.verbose,
@@ -1,6 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
 
3
3
  from rclone_api.experimental.flags_base import BaseFlags, merge_flags
4
+ from rclone_api.types import SizeSuffix
4
5
 
5
6
 
6
7
  @dataclass
@@ -20,7 +21,7 @@ class CopyFlags(BaseFlags):
20
21
  links: bool | None = None
21
22
  max_backlog: int | None = None
22
23
  max_duration: str | None = None
23
- max_transfer: str | None = None
24
+ max_transfer: SizeSuffix | None = None
24
25
  metadata: bool | None = None
25
26
  modify_window: str | None = None
26
27
  multi_thread_chunk_size: str | None = None
@@ -77,6 +78,12 @@ def unit_test() -> None:
77
78
  merged_d_c = copy_flags_d.merge(copy_flags_c)
78
79
  print("C:", merged_d_c)
79
80
 
81
+ # now do the one with the SizeSuffix type
82
+ copy_flags_e = CopyFlags(max_transfer=SizeSuffix("128M"))
83
+ copy_flags_f = CopyFlags(max_transfer=SizeSuffix("256M"))
84
+ merged_e_f = copy_flags_e.merge(copy_flags_f)
85
+ print("D:", merged_e_f)
86
+
80
87
 
81
88
  if __name__ == "__main__":
82
89
  unit_test()
rclone_api/mount.py CHANGED
@@ -1,12 +1,30 @@
1
+ import os
1
2
  import platform
2
3
  import subprocess
3
4
  import time
4
5
  import warnings
6
+ from dataclasses import dataclass
5
7
  from pathlib import Path
8
+ from typing import Any
9
+
10
+ from rclone_api.process import Process
6
11
 
7
12
  _SYSTEM = platform.system() # "Linux", "Darwin", "Windows", etc.
8
13
 
9
14
 
15
+ @dataclass
16
+ class Mount:
17
+ """Mount information."""
18
+
19
+ mount_path: Path
20
+ process: Process
21
+
22
+ def __post_init__(self):
23
+ assert isinstance(self.mount_path, Path)
24
+ assert self.process is not None
25
+ wait_for_mount(self.mount_path, self.process)
26
+
27
+
10
28
  def run_command(cmd: str, verbose: bool) -> int:
11
29
  """Run a shell command and print its output if verbose is True."""
12
30
  if verbose:
@@ -36,7 +54,27 @@ def prepare_mount(outdir: Path, verbose: bool) -> None:
36
54
  outdir.mkdir(parents=True, exist_ok=True)
37
55
 
38
56
 
39
- def clean_mount(mount_path: Path, verbose: bool = False) -> None:
57
+ def wait_for_mount(path: Path, mount_process: Any, timeout: int = 10) -> None:
58
+ from rclone_api.process import Process
59
+
60
+ assert isinstance(mount_process, Process)
61
+ expire_time = time.time() + timeout
62
+ while time.time() < expire_time:
63
+ rtn = mount_process.poll()
64
+ if rtn is not None:
65
+ cmd_str = subprocess.list2cmdline(mount_process.cmd)
66
+ raise subprocess.CalledProcessError(rtn, cmd_str)
67
+ if path.exists():
68
+ # how many files?
69
+ dircontents = os.listdir(str(path))
70
+ if len(dircontents) > 0:
71
+ print(f"Mount point {path}, waiting 5 seconds for files to appear.")
72
+ time.sleep(5)
73
+ return
74
+ time.sleep(1)
75
+
76
+
77
+ def clean_mount(mount: Mount | Path, verbose: bool = False) -> None:
40
78
  """
41
79
  Clean up a mount path across Linux, macOS, and Windows.
42
80
 
@@ -45,7 +83,14 @@ def clean_mount(mount_path: Path, verbose: bool = False) -> None:
45
83
  and 'umount'. On macOS it uses 'umount' (and optionally 'diskutil unmount'),
46
84
  while on Windows it attempts to remove the mount point via 'mountvol /D'.
47
85
  """
86
+ proc = mount.process if isinstance(mount, Mount) else None
87
+ if proc is not None and proc.poll() is None:
88
+ if verbose:
89
+ print(f"Terminating mount process {proc.pid}")
90
+ proc.kill()
91
+
48
92
  # Check if the mount path exists; if an OSError occurs, assume it exists.
93
+ mount_path = mount.mount_path if isinstance(mount, Mount) else mount
49
94
  try:
50
95
  mount_exists = mount_path.exists()
51
96
  except OSError as e:
rclone_api/process.py CHANGED
@@ -100,6 +100,10 @@ class Process:
100
100
  except Exception as e:
101
101
  print(f"Error cleaning up tempdir: {e}")
102
102
 
103
+ @property
104
+ def pid(self) -> int:
105
+ return self.process.pid
106
+
103
107
  def __del__(self) -> None:
104
108
  self.cleanup()
105
109
 
rclone_api/rclone.py CHANGED
@@ -25,6 +25,7 @@ from rclone_api.dir_listing import DirListing
25
25
  from rclone_api.exec import RcloneExec
26
26
  from rclone_api.file import File
27
27
  from rclone_api.group_files import group_files
28
+ from rclone_api.mount import Mount, clean_mount, prepare_mount
28
29
  from rclone_api.process import Process
29
30
  from rclone_api.remote import Remote
30
31
  from rclone_api.rpath import RPath
@@ -46,12 +47,9 @@ from rclone_api.util import (
46
47
  get_rclone_exe,
47
48
  get_verbose,
48
49
  to_path,
49
- wait_for_mount,
50
50
  )
51
51
  from rclone_api.walk import walk
52
52
 
53
- _IS_WINDOWS = os.name == "nt"
54
-
55
53
 
56
54
  def rclone_verbose(verbose: bool | None) -> bool:
57
55
  if verbose is not None:
@@ -680,12 +678,7 @@ class Rclone:
680
678
  dst: str,
681
679
  save_state_json: Path,
682
680
  chunk_size: SizeSuffix | None = None,
683
- # 16
684
- # * 1024
685
- # * 1024, # This setting will scale the performance of the upload
686
- concurrent_chunks: (
687
- int | None
688
- ) = None, # This setting will scale the performance of the upload
681
+ threads: int = 16,
689
682
  retries: int = 3,
690
683
  verbose: bool | None = None,
691
684
  max_chunks_before_suspension: int | None = None,
@@ -696,30 +689,24 @@ class Rclone:
696
689
  from rclone_api.s3.create import S3Credentials
697
690
  from rclone_api.util import S3PathInfo, random_str, split_s3_path
698
691
 
699
- _tmp: SizeSuffix | str = chunk_size or "16MiB"
700
- chunk_size = SizeSuffix(_tmp)
701
- assert chunk_size is not None
702
- concurrent_chunks = concurrent_chunks or 4
703
- size_limit = SizeSuffix(chunk_size * concurrent_chunks)
704
-
705
- other_args: list[str] = [
706
- "--no-modtime",
707
- "--vfs-read-wait",
708
- "1s",
709
- "--vfs-disk-space-total-size",
710
- size_limit.as_str(), # purge quickly.
711
- "--vfs-read-chunk-size",
712
- chunk_size.as_str(),
692
+ other_args: list[str] = ["--no-modtime", "--vfs-read-wait", "1s"]
693
+ chunk_size = chunk_size or SizeSuffix("128M")
694
+ unit_chunk_size = chunk_size / threads
695
+ vfs_read_chunk_size = unit_chunk_size
696
+ vfs_read_chunk_size_limit = chunk_size
697
+ vfs_read_chunk_streams = threads
698
+ assert (
699
+ chunk_size.as_int() % vfs_read_chunk_size.as_int() == 0
700
+ ), f"chunk_size {chunk_size} must be a multiple of vfs_read_chunk_size {vfs_read_chunk_size}"
701
+ other_args += ["--vfs-read-chunk-size", vfs_read_chunk_size.as_str()]
702
+ other_args += [
713
703
  "--vfs-read-chunk-size-limit",
714
- size_limit.as_str(),
715
- "--vfs-read-chunk-streams",
716
- str(concurrent_chunks),
717
- "--vfs-fast-fingerprint",
704
+ vfs_read_chunk_size_limit.as_str(),
718
705
  ]
706
+ other_args += ["--vfs-read-chunk-streams", str(vfs_read_chunk_streams)]
719
707
  mount_path = mount_path or Path("tmp_mnts") / random_str(12)
720
708
  src_path = Path(src)
721
709
  name = src_path.name
722
-
723
710
  parent_path = str(src_path.parent.as_posix())
724
711
  with self.scoped_mount(
725
712
  parent_path,
@@ -847,7 +834,7 @@ class Rclone:
847
834
  vfs_cache_mode: str | None = None,
848
835
  verbose: bool | None = None,
849
836
  other_args: list[str] | None = None,
850
- ) -> Process:
837
+ ) -> Mount:
851
838
  """Mount a remote or directory to a local path.
852
839
 
853
840
  Args:
@@ -860,7 +847,6 @@ class Rclone:
860
847
  Raises:
861
848
  subprocess.CalledProcessError: If the mount operation fails
862
849
  """
863
- from rclone_api.mount import clean_mount, prepare_mount
864
850
 
865
851
  allow_writes = allow_writes or False
866
852
  use_links = use_links or True
@@ -882,8 +868,9 @@ class Rclone:
882
868
  if other_args:
883
869
  cmd_list += other_args
884
870
  proc = self._launch_process(cmd_list)
885
- wait_for_mount(outdir, proc)
886
- return proc
871
+
872
+ mount: Mount = Mount(mount_path=outdir, process=proc)
873
+ return mount
887
874
 
888
875
  @contextmanager
889
876
  def scoped_mount(
@@ -895,11 +882,11 @@ class Rclone:
895
882
  vfs_cache_mode: str | None = None,
896
883
  verbose: bool | None = None,
897
884
  other_args: list[str] | None = None,
898
- ) -> Generator[Process, None, None]:
885
+ ) -> Generator[Mount, None, None]:
899
886
  """Like mount, but can be used in a context manager."""
900
887
  error_happened = False
901
888
  verbose = get_verbose(verbose)
902
- proc = self.mount(
889
+ mount: Mount = self.mount(
903
890
  src,
904
891
  outdir,
905
892
  allow_writes=allow_writes,
@@ -909,77 +896,18 @@ class Rclone:
909
896
  other_args=other_args,
910
897
  )
911
898
  try:
912
- yield proc
899
+ yield mount
913
900
  except Exception as e:
914
901
  error_happened = True
915
902
  stack_trace = traceback.format_exc()
916
903
  warnings.warn(f"Error in scoped_mount: {e}\n\nStack Trace:\n{stack_trace}")
917
904
  raise
918
905
  finally:
919
- if proc.poll() is None:
920
- proc.terminate()
921
- proc.wait()
906
+
922
907
  if not error_happened:
923
908
  from rclone_api.mount import clean_mount
924
909
 
925
- clean_mount(outdir, verbose=verbose)
926
-
927
- @deprecated("mount")
928
- def mount_webdav(
929
- self,
930
- url: str,
931
- outdir: Path,
932
- vfs_cache_mode: str | None = None,
933
- vfs_disk_space_total_size: str | None = "10G",
934
- other_args: list[str] | None = None,
935
- ) -> Process:
936
- """Mount a remote or directory to a local path.
937
-
938
- Args:
939
- src: Remote or directory to mount
940
- outdir: Local path to mount to
941
-
942
- Returns:
943
- CompletedProcess from the mount command execution
944
-
945
- Raises:
946
- subprocess.CalledProcessError: If the mount operation fails
947
- """
948
- other_args = other_args or []
949
- if vfs_cache_mode is None:
950
- if "--vfs-cache-mode" in other_args:
951
- pass
952
- else:
953
- vfs_cache_mode = "full"
954
- elif "--vfs-cache-mode" in other_args:
955
- warnings.warn(
956
- f"vfs_cache_mode is set to {vfs_cache_mode} but --vfs-cache-mode is already in other_args"
957
- )
958
- idx = other_args.index("--vfs-cache-mode")
959
- other_args.pop(idx)
960
- other_args.pop(idx) # also the next value which will be the cache mode.
961
-
962
- if outdir.exists():
963
- is_empty = not list(outdir.iterdir())
964
- if not is_empty:
965
- raise ValueError(
966
- f"Mount directory already exists and is not empty: {outdir}"
967
- )
968
- outdir.rmdir()
969
-
970
- src_str = url
971
- cmd_list: list[str] = ["mount", src_str, str(outdir)]
972
- if vfs_cache_mode:
973
- cmd_list.append("--vfs-cache-mode")
974
- cmd_list.append(vfs_cache_mode)
975
- if other_args:
976
- cmd_list += other_args
977
- if vfs_disk_space_total_size is not None:
978
- cmd_list.append("--vfs-cache-max-size")
979
- cmd_list.append(vfs_disk_space_total_size)
980
- proc = self._launch_process(cmd_list)
981
- wait_for_mount(outdir, proc)
982
- return proc
910
+ clean_mount(mount, verbose=verbose)
983
911
 
984
912
  # Settings optimized for s3.
985
913
  def mount_s3(
@@ -988,11 +916,8 @@ class Rclone:
988
916
  outdir: Path,
989
917
  allow_writes=False,
990
918
  vfs_cache_mode="full",
991
- # dir-cache-time
992
919
  dir_cache_time: str | None = "1h",
993
920
  attribute_timeout: str | None = "1h",
994
- # --vfs-cache-max-size
995
- # vfs-cache-max-size
996
921
  vfs_disk_space_total_size: str | None = "100M",
997
922
  transfers: int | None = 128,
998
923
  modtime_strategy: (
@@ -1004,7 +929,7 @@ class Rclone:
1004
929
  # vfs-refresh
1005
930
  vfs_refresh: bool = True,
1006
931
  other_args: list[str] | None = None,
1007
- ) -> Process:
932
+ ) -> Mount:
1008
933
  """Mount a remote or directory to a local path.
1009
934
 
1010
935
  Args:
@@ -7,6 +7,7 @@ from threading import Lock
7
7
 
8
8
  from botocore.client import BaseClient
9
9
 
10
+ from rclone_api.types import SizeSuffix
10
11
  from rclone_api.util import locked_print
11
12
 
12
13
  _MIN_UPLOAD_CHUNK_SIZE = 5 * 1024 * 1024 # 5MB
@@ -108,16 +109,20 @@ class UploadInfo:
108
109
  value = getattr(self, f.name)
109
110
  # Convert non-serializable objects (like s3_client) to a string representation.
110
111
  if f.name == "s3_client":
111
- json_dict[f.name] = "RUNTIME OBJECT"
112
+ continue
112
113
  else:
113
114
  if isinstance(value, Path):
114
115
  value = str(value)
115
116
  json_dict[f.name] = value
117
+
116
118
  return json_dict
117
119
 
118
120
  @staticmethod
119
121
  def from_json(s3_client: BaseClient, json_dict: dict) -> "UploadInfo":
120
- json_dict.pop("s3_client") # Remove the placeholder string
122
+ # json_dict.pop("s3_client") # Remove the placeholder string
123
+ if "s3_client" in json_dict:
124
+ json_dict.pop("s3_client")
125
+
121
126
  return UploadInfo(s3_client=s3_client, **json_dict)
122
127
 
123
128
 
@@ -224,6 +229,12 @@ class UploadState:
224
229
 
225
230
  # self.count()
226
231
  finished_count, total = self.count()
232
+ total_finished: SizeSuffix = SizeSuffix(
233
+ finished_count * self.upload_info.chunk_size
234
+ )
235
+ total_remaining: SizeSuffix = SizeSuffix(
236
+ self.remaining() * self.upload_info.chunk_size
237
+ )
227
238
 
228
239
  # parts.sort(key=lambda x: x.part_number) # Some backends need this.
229
240
  out_json = {
@@ -232,6 +243,10 @@ class UploadState:
232
243
  "is_done": is_done,
233
244
  "finished_count": finished_count,
234
245
  "total_parts": total,
246
+ "total_size": SizeSuffix(self.upload_info.file_size).as_str(),
247
+ "total_finished": total_finished.as_str(),
248
+ "total_remaining": total_remaining.as_str(),
249
+ "completed": f"{(finished_count / total) * 100:.2f}%",
235
250
  }
236
251
 
237
252
  # check that we can sererialize
rclone_api/types.py CHANGED
@@ -58,6 +58,8 @@ _PATTERN_SIZE_SUFFIX = re.compile(r"^(\d+)([A-Za-z]+)$")
58
58
  def _from_size_suffix(size: str) -> int:
59
59
  # 16MiB
60
60
  # parse out number and suffix
61
+ if size == "0":
62
+ return 0
61
63
  match = _PATTERN_SIZE_SUFFIX.match(size)
62
64
  if match is None:
63
65
  raise ValueError(f"Invalid size suffix: {size}")
@@ -88,6 +90,8 @@ class SizeSuffix:
88
90
  self._size = size
89
91
  elif isinstance(size, str):
90
92
  self._size = _from_size_suffix(size)
93
+ elif isinstance(size, float):
94
+ self._size = int(size)
91
95
  else:
92
96
  raise ValueError(f"Invalid type for size: {type(size)}")
93
97
 
@@ -123,3 +127,10 @@ class SizeSuffix:
123
127
  def __sub__(self, other: "int | SizeSuffix") -> "SizeSuffix":
124
128
  other_int = SizeSuffix(other)
125
129
  return SizeSuffix(self._size - other_int._size)
130
+
131
+ def __truediv__(self, other: "int | SizeSuffix") -> "SizeSuffix":
132
+ other_int = SizeSuffix(other)
133
+ if other_int._size == 0:
134
+ raise ZeroDivisionError("Division by zero is undefined")
135
+ # Use floor division to maintain integer arithmetic.
136
+ return SizeSuffix(self._size // other_int._size)
rclone_api/util.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import os
2
2
  import shutil
3
3
  import subprocess
4
- import time
5
4
  import warnings
6
5
  from pathlib import Path
7
6
  from tempfile import TemporaryDirectory
@@ -135,26 +134,6 @@ def rclone_execute(
135
134
  print(f"Error cleaning up tempdir: {e}")
136
135
 
137
136
 
138
- def wait_for_mount(path: Path, mount_process: Any, timeout: int = 10) -> None:
139
- from rclone_api.process import Process
140
-
141
- assert isinstance(mount_process, Process)
142
- expire_time = time.time() + timeout
143
- while time.time() < expire_time:
144
- rtn = mount_process.poll()
145
- if rtn is not None:
146
- cmd_str = subprocess.list2cmdline(mount_process.cmd)
147
- raise subprocess.CalledProcessError(rtn, cmd_str)
148
- if path.exists():
149
- # how many files?
150
- dircontents = os.listdir(str(path))
151
- if len(dircontents) > 0:
152
- print(f"Mount point {path}, waiting 5 seconds for files to appear.")
153
- time.sleep(5)
154
- return
155
- time.sleep(1)
156
-
157
-
158
137
  def split_s3_path(path: str) -> S3PathInfo:
159
138
  if ":" not in path:
160
139
  raise ValueError(f"Invalid S3 path: {path}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.1.7
3
+ Version: 1.1.8
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -11,30 +11,30 @@ rclone_api/exec.py,sha256=1ovvaMXDEfLiT7BrYZyE85u_yFhEUwUNW3jPOzqknR8,1023
11
11
  rclone_api/file.py,sha256=EP5yT2dZ0H2p7CY5n0y5k5pHhIliV25pm8KOwBklUTk,1863
12
12
  rclone_api/filelist.py,sha256=xbiusvNgaB_b_kQOZoHMJJxn6TWGtPrWd2J042BI28o,767
13
13
  rclone_api/group_files.py,sha256=H92xPW9lQnbNw5KbtZCl00bD6iRh9yRbCuxku4j_3dg,8036
14
- rclone_api/mount.py,sha256=Zf41gGfTXtSB-KkQoXCq_dpqBvezgz_dPBzk_aDk5Dc,4354
15
- rclone_api/process.py,sha256=RrMfTe0bndmJ6gBK67ioqNvCstJ8aTC8RlGX1XBLlcw,4191
16
- rclone_api/rclone.py,sha256=yI_8QdDXppcLO-KbRVGteu-onTa4fTd4ojy_N1HYxx4,42029
14
+ rclone_api/mount.py,sha256=8vSXIaVwj6RNwPvk0N4IA6pPBXkI3XRnO4W0JcrAbDc,5759
15
+ rclone_api/process.py,sha256=xYUgU17txkZfZdr4vtRfvD8YjvSfdrbjM7PYW1npAMI,4264
16
+ rclone_api/rclone.py,sha256=-WJseVj--ko_D4dLcEqtfG6i7G_U3fu4YL95XCWH1wE,39718
17
17
  rclone_api/remote.py,sha256=O9WDUFQy9f6oT1HdUbTixK2eg0xtBBm8k4Xl6aa6K00,431
18
18
  rclone_api/rpath.py,sha256=8ZA_1wxWtskwcy0I8V2VbjKDmzPkiWd8Q2JQSvh-sYE,2586
19
19
  rclone_api/scan_missing_folders.py,sha256=Kulca2Q6WZodt00ATFHkmqqInuoPvBkhTcS9703y6po,4740
20
- rclone_api/types.py,sha256=e7VmqA2U6MkTT9VDHeP2qwRw_lUUFbaiN6RO-R8B1oo,3336
21
- rclone_api/util.py,sha256=ujinqW4xUkZAHBCL1VMhGu88LMdUFIu1ApF8rZEH8rQ,5324
20
+ rclone_api/types.py,sha256=OWj9mUFaehC3PMAyt-uBYB1V2MfQ-ugJfUlIVjZ09cw,3775
21
+ rclone_api/util.py,sha256=_Z-GUMVXnHYOGdo2dy2ie2P5fGgyg8KdGjHKicx68Ko,4573
22
22
  rclone_api/walk.py,sha256=-54NVE8EJcCstwDoaC_UtHm73R2HrZwVwQmsnv55xNU,3369
23
23
  rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
24
- rclone_api/cmd/copy_large_s3.py,sha256=kF0wRVRGjIB2CxuwN4z1WnfYjiux7fHkY9FLCw3EJsI,2999
24
+ rclone_api/cmd/copy_large_s3.py,sha256=DNALWMwinu7I03nBhao-7Huo7OoS5k1HcqiaHTM0QZU,3071
25
25
  rclone_api/cmd/list_files.py,sha256=x8FHODEilwKqwdiU1jdkeJbLwOqUkUQuDWPo2u_zpf0,741
26
- rclone_api/experimental/flags.py,sha256=0-mtXg9J4MoMm2uBKbsMLj4pSGRLQUAqNRDJWGttnAQ,2443
26
+ rclone_api/experimental/flags.py,sha256=qCVD--fSTmzlk9hloRLr0q9elzAOFzPsvVpKM3aB1Mk,2739
27
27
  rclone_api/experimental/flags_base.py,sha256=ajU_czkTcAxXYU-SlmiCfHY7aCQGHvpCLqJ-Z8uZLk0,2102
28
28
  rclone_api/s3/api.py,sha256=VstlaEnBjO2JDQuCRLdTfUGvQLbfshlXXhAzimFv4Vc,3763
29
29
  rclone_api/s3/basic_ops.py,sha256=hK3366xhVEzEcjz9Gk_8lFx6MRceAk72cax6mUrr6ko,2104
30
30
  rclone_api/s3/chunk_file.py,sha256=XPoDl7DJMJIGBMRoPO2wqwqCMT7ZrIsEkDqlbMH8jzs,3506
31
- rclone_api/s3/chunk_types.py,sha256=Fq0IlhZ0IftuFQFkbICmmrOonII0BNzuY4CIKNC4wB0,8006
31
+ rclone_api/s3/chunk_types.py,sha256=6_ythhT7EcchJ9MI8qBKVKh-SVOe1Rf15t_JepHPilA,8587
32
32
  rclone_api/s3/chunk_uploader.py,sha256=KO8834Gery9HKWSqjQTNW0pbBbVoGrza9gj-1OaNLQQ,9130
33
33
  rclone_api/s3/create.py,sha256=SK3IGHZwsSkoG4Zb4NCphcVg9_f7VifDKng-tExMS2s,3088
34
34
  rclone_api/s3/types.py,sha256=81_3jwg6MGIxC-GxL-6zANzKO6au9C0BWvAqRyODxOM,1361
35
- rclone_api-1.1.7.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
36
- rclone_api-1.1.7.dist-info/METADATA,sha256=HujPmSO7dGtf6yoYvjQ3ZkVHfezRF9sTXx1ZXLcaCO8,4478
37
- rclone_api-1.1.7.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
38
- rclone_api-1.1.7.dist-info/entry_points.txt,sha256=6eNqTRXKhVf8CpWNjXiOa_0Du9tHiW_HD2iQSXRsUg8,132
39
- rclone_api-1.1.7.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
40
- rclone_api-1.1.7.dist-info/RECORD,,
35
+ rclone_api-1.1.8.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
36
+ rclone_api-1.1.8.dist-info/METADATA,sha256=o2HlbSg87QWtMTq0983EdoivnDCTUsPI4tN5Cowi5Tc,4478
37
+ rclone_api-1.1.8.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
38
+ rclone_api-1.1.8.dist-info/entry_points.txt,sha256=6eNqTRXKhVf8CpWNjXiOa_0Du9tHiW_HD2iQSXRsUg8,132
39
+ rclone_api-1.1.8.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
40
+ rclone_api-1.1.8.dist-info/RECORD,,