rclone-api 1.5.60__py3-none-any.whl → 1.5.63__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.
rclone_api/__init__.py CHANGED
@@ -469,6 +469,41 @@ class Rclone:
469
469
  """
470
470
  return self.impl.is_s3(dst=dst)
471
471
 
472
+ def copy_file_s3_resumable(
473
+ self,
474
+ src: str, # src:/Bucket/path/myfile.large.zst
475
+ dst: str, # dst:/Bucket/path/myfile.large.zst
476
+ part_infos: list[PartInfo] | None = None,
477
+ upload_threads: int = 8, # Number of reader and writer threads to use
478
+ merge_threads: int = 4, # Number of threads to use for merging the parts
479
+ ) -> Exception | None:
480
+ """
481
+ Copy a large file to S3 with resumable upload capability.
482
+
483
+ This method splits the file into parts for parallel upload and can
484
+ resume interrupted transfers using a custom algorithm in python.
485
+
486
+ Particularly useful for very large files where network interruptions
487
+ are likely.
488
+
489
+ Args:
490
+ src: Source file path (format: remote:bucket/path/file)
491
+ dst: Destination file path (format: remote:bucket/path/file)
492
+ part_infos: Optional list of part information for resuming uploads
493
+ upload_threads: Number of parallel upload threads
494
+ merge_threads: Number of threads for merging uploaded parts
495
+
496
+ Returns:
497
+ None if successful, Exception if an error occurred
498
+ """
499
+ return self.impl.copy_file_s3_resumable(
500
+ src=src,
501
+ dst=dst,
502
+ part_infos=part_infos,
503
+ upload_threads=upload_threads,
504
+ merge_threads=merge_threads,
505
+ )
506
+
472
507
  def copy_to(
473
508
  self,
474
509
  src: File | str,
@@ -831,41 +866,6 @@ class Rclone:
831
866
  """
832
867
  return self.impl.copy_remote(src=src, dst=dst, args=args)
833
868
 
834
- def copy_file_s3_resumable(
835
- self,
836
- src: str, # src:/Bucket/path/myfile.large.zst
837
- dst: str, # dst:/Bucket/path/myfile.large.zst
838
- part_infos: list[PartInfo] | None = None,
839
- upload_threads: int = 8, # Number of reader and writer threads to use
840
- merge_threads: int = 4, # Number of threads to use for merging the parts
841
- ) -> Exception | None:
842
- """
843
- Copy a large file to S3 with resumable upload capability.
844
-
845
- This method splits the file into parts for parallel upload and can
846
- resume interrupted transfers using a custom algorithm in python.
847
-
848
- Particularly useful for very large files where network interruptions
849
- are likely.
850
-
851
- Args:
852
- src: Source file path (format: remote:bucket/path/file)
853
- dst: Destination file path (format: remote:bucket/path/file)
854
- part_infos: Optional list of part information for resuming uploads
855
- upload_threads: Number of parallel upload threads
856
- merge_threads: Number of threads for merging uploaded parts
857
-
858
- Returns:
859
- None if successful, Exception if an error occurred
860
- """
861
- return self.impl.copy_file_s3_resumable(
862
- src=src,
863
- dst=dst,
864
- part_infos=part_infos,
865
- upload_threads=upload_threads,
866
- merge_threads=merge_threads,
867
- )
868
-
869
869
  def mount(
870
870
  self,
871
871
  src: Remote | Dir | str,
rclone_api/config.py CHANGED
@@ -52,9 +52,11 @@ class Config:
52
52
  """Rclone configuration dataclass."""
53
53
 
54
54
  # text: str
55
- def __init__(self, text: str | dict) -> None:
55
+ def __init__(self, text: str | dict | None) -> None:
56
56
  self.text: str
57
- if isinstance(text, dict):
57
+ if text is None:
58
+ self.text = ""
59
+ elif isinstance(text, dict):
58
60
  self.text = _json_to_rclone_config_str_or_raise(text)
59
61
  else:
60
62
  self.text = text
rclone_api/exec.py CHANGED
@@ -10,7 +10,7 @@ from rclone_api.process import Process, ProcessArgs
10
10
  class RcloneExec:
11
11
  """Rclone execution dataclass."""
12
12
 
13
- rclone_config: Path | Config
13
+ rclone_config: Path | Config | None
14
14
  rclone_exe: Path
15
15
 
16
16
  def execute(
rclone_api/process.py CHANGED
@@ -15,7 +15,7 @@ from rclone_api.util import clear_temp_config_file, get_verbose, make_temp_confi
15
15
  @dataclass
16
16
  class ProcessArgs:
17
17
  cmd: list[str]
18
- rclone_conf: Path | Config
18
+ rclone_conf: Path | Config | None
19
19
  rclone_exe: Path
20
20
  cmd_list: list[str]
21
21
  verbose: bool | None = None
@@ -32,7 +32,7 @@ class Process:
32
32
  self.log = args.log
33
33
  self.cleaned_up = False
34
34
  self.tempfile: Path | None = None
35
-
35
+ rclone_conf: Path | None = None
36
36
  verbose = get_verbose(args.verbose)
37
37
  # Create a temporary config file if needed.
38
38
  if isinstance(args.rclone_conf, Config):
@@ -41,15 +41,12 @@ class Process:
41
41
  rclone_conf = self.tempfile
42
42
  else:
43
43
  rclone_conf = args.rclone_conf
44
-
45
- assert rclone_conf.exists(), f"rclone config not found: {rclone_conf}"
46
-
44
+ # assert rclone_conf.exists(), f"rclone config not found: {rclone_conf}"
47
45
  # Build the command.
48
- self.cmd = (
49
- [str(args.rclone_exe.resolve())]
50
- + ["--config", str(rclone_conf.resolve())]
51
- + args.cmd
52
- )
46
+ self.cmd = [str(args.rclone_exe.resolve())]
47
+ if rclone_conf:
48
+ self.cmd += ["--config", str(rclone_conf.resolve())]
49
+ self.cmd += args.cmd_list
53
50
  if self.args.log:
54
51
  self.args.log.parent.mkdir(parents=True, exist_ok=True)
55
52
  self.cmd += ["--log-file", str(self.args.log)]
rclone_api/rclone_impl.py CHANGED
@@ -67,8 +67,10 @@ def rclone_verbose(verbose: bool | None) -> bool:
67
67
  return bool(int(os.getenv("RCLONE_API_VERBOSE", "0")))
68
68
 
69
69
 
70
- def _to_rclone_conf(config: Config | Path) -> Config:
71
- if isinstance(config, Path):
70
+ def _to_rclone_conf(config: Config | Path | None) -> Config:
71
+ if config is None:
72
+ return Config(None)
73
+ elif isinstance(config, Path):
72
74
  content = config.read_text(encoding="utf-8")
73
75
  return Config(content)
74
76
  else:
@@ -100,13 +102,17 @@ class RcloneImpl:
100
102
  if isinstance(rclone_conf, Path):
101
103
  if not rclone_conf.exists():
102
104
  raise ValueError(f"Rclone config file not found: {rclone_conf}")
105
+ rclone_exe = get_rclone_exe(rclone_exe)
106
+ # Not fully constructed version of ._exec, which can be used to find a config file from default paths.
107
+ self._exec = RcloneExec(None, get_rclone_exe(rclone_exe))
103
108
  if rclone_conf is None:
104
109
  from rclone_api.config import find_conf_file
105
110
 
106
111
  maybe_path = find_conf_file(self)
107
112
  if not isinstance(maybe_path, Path):
108
- raise ValueError("Rclone config file not found")
113
+ warnings.warn("Rclone config file not found")
109
114
  rclone_conf = _to_rclone_conf(maybe_path)
115
+ # replace self._exec with one that has the config
110
116
  self._exec = RcloneExec(rclone_conf, get_rclone_exe(rclone_exe))
111
117
  self.config: Config = _to_rclone_conf(rclone_conf)
112
118
 
@@ -1334,9 +1340,6 @@ class RcloneImpl:
1334
1340
  if obscure:
1335
1341
  cmd_list.append("--obscure")
1336
1342
 
1337
- if no_obscure:
1338
- cmd_list.append("--no-obscure")
1339
-
1340
1343
  try:
1341
1344
  cp = self._run(cmd_list, capture=True, check=True)
1342
1345
  stdout: str | bytes = cp.stdout
@@ -1360,7 +1363,8 @@ class RcloneImpl:
1360
1363
  verbose = get_verbose(verbose)
1361
1364
  check = get_check(check)
1362
1365
  if len(files) < 2:
1363
- tmp = self.size_file(files[0])
1366
+ full_path = f"{src}/{files[0]}"
1367
+ tmp = self.size_file(full_path)
1364
1368
  if isinstance(tmp, Exception):
1365
1369
  return tmp
1366
1370
  assert isinstance(tmp, SizeSuffix)
rclone_api/util.py CHANGED
@@ -178,7 +178,7 @@ def upgrade_rclone() -> Path:
178
178
 
179
179
  def rclone_execute(
180
180
  cmd: list[str],
181
- rclone_conf: Path | Config,
181
+ rclone_conf: Path | Config | None,
182
182
  rclone_exe: Path,
183
183
  check: bool,
184
184
  capture: bool | Path | None = None,
@@ -202,10 +202,10 @@ def rclone_execute(
202
202
  tmpfile.write_text(rclone_conf.text, encoding="utf-8")
203
203
  rclone_conf = tmpfile
204
204
 
205
- # Build the command line.
206
- full_cmd = (
207
- [str(rclone_exe.resolve())] + ["--config", str(rclone_conf.resolve())] + cmd
208
- )
205
+ full_cmd = [str(rclone_exe.resolve())]
206
+ if rclone_conf:
207
+ full_cmd += ["--config", str(rclone_conf.resolve())]
208
+ full_cmd += cmd
209
209
  if verbose:
210
210
  cmd_str = subprocess.list2cmdline(full_cmd)
211
211
  print(f"\nRunning: {cmd_str}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rclone_api
3
- Version: 1.5.60
3
+ Version: 1.5.63
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -1,13 +1,13 @@
1
- rclone_api/__init__.py,sha256=M3-jlyxhO7Md3FGMO8qBJ1Z7oLcbOjWshCHh2-CqKG4,34885
1
+ rclone_api/__init__.py,sha256=gIONLifrNkReIlQkpJOk3TTueJ9jrJ2ZdM2scQSUvSY,34885
2
2
  rclone_api/cli.py,sha256=dibfAZIh0kXWsBbfp3onKLjyZXo54mTzDjUdzJlDlWo,231
3
3
  rclone_api/completed_process.py,sha256=_IZ8IWK7DM1_tsbDEkH6wPZ-bbcrgf7A7smls854pmg,1775
4
- rclone_api/config.py,sha256=DEBubN0ziUfAFYe6cmDn7YoTqRJPdGronFyRHZvWUso,6070
4
+ rclone_api/config.py,sha256=URZwMME01f0EZymprCESuZ5dk4IuUSKbHhwIeTHrn7A,6131
5
5
  rclone_api/convert.py,sha256=Mx9Qo7zhkOedJd8LdhPvNGHp8znJzOk4f_2KWnoGc78,1012
6
6
  rclone_api/deprecated.py,sha256=qWKpnZdYcBK7YQZKuVoWWXDwi-uqiAtbjgPcci_efow,590
7
7
  rclone_api/diff.py,sha256=tMoJMAGmLSE6Q_7QhPf6PnCzb840djxMZtDmhc2GlGQ,5227
8
8
  rclone_api/dir.py,sha256=_9o-_5tbWVJkL1Vf_Yb8aiQV3xAqvUq5bk3zoJblvEg,3547
9
9
  rclone_api/dir_listing.py,sha256=bSmd8yZtSeyVaDRw2JPB4bCpbCeDzhoa_pomgdJp44c,1884
10
- rclone_api/exec.py,sha256=Bq0gkyZ10mEY0FRyzNZgdN4FaWP9vpeCk1kjpg-gN_8,1083
10
+ rclone_api/exec.py,sha256=3x2FOrh_3Ml23sW_5fry3dmlKyHtq3iYKByLeZtbNcg,1090
11
11
  rclone_api/file.py,sha256=JLPqjUcW_YVb4UQjX6FQ7PABJqhchFUXVy1W-X9rJLk,5659
12
12
  rclone_api/file_item.py,sha256=cH-AQYsxedhNPp4c8NHY1ad4Z7St4yf_VGbmiGD59no,1770
13
13
  rclone_api/file_part.py,sha256=i6ByS5_sae8Eba-4imBVTxd-xKC8ExWy7NR8QGr0ors,6155
@@ -19,13 +19,13 @@ rclone_api/install.py,sha256=ZDG8QNj1JciS_DSqYnMTECwhJksUPAoqZQxtX804TDk,5679
19
19
  rclone_api/log.py,sha256=VZHM7pNSXip2ZLBKMP7M1u-rp_F7zoafFDuR8CPUoKI,1271
20
20
  rclone_api/mount.py,sha256=LZqEhuKZunbWVqmsOIqkkCotaxWJpdFRS1InXveoU5E,1428
21
21
  rclone_api/mount_util.py,sha256=jqhJEVTHV6c6lOOzUYb4FLMbqDMHdz7-QRcdH-IobFc,10154
22
- rclone_api/process.py,sha256=MeWiN-TrrN0HmtWexBPxGwf84z6f-_E5yaXE-YtLYpY,5879
23
- rclone_api/rclone_impl.py,sha256=s00SHQGcKskbauWiIZQBQKSR0NOJ6SSiXhMf0fwkl9U,52328
22
+ rclone_api/process.py,sha256=V4Ax9AyNdC3m4O6gjWSbIJyCQCMhT-t0f-K8z6xux7Q,5946
23
+ rclone_api/rclone_impl.py,sha256=PppFWk4qo7gg6p_k3K7am3_6pytsLG6qTAKo6dBT-tI,52649
24
24
  rclone_api/remote.py,sha256=mTgMTQTwxUmbLjTpr-AGTId2ycXKI9mLX5L7PPpDIoc,520
25
25
  rclone_api/rpath.py,sha256=Y1JjQWcie39EgQrq-UtbfDz5yDLCwwfu27W7AQXllSE,2860
26
26
  rclone_api/scan_missing_folders.py,sha256=-8NCwpCaHeHrX-IepCoAEsX1rl8S-GOCxcIhTr_w3gA,4747
27
27
  rclone_api/types.py,sha256=59Rw7NdHw35X6iiWMemO61IzCbrjgfNHUlzY3Dq0wdM,12303
28
- rclone_api/util.py,sha256=Xa_VifjNT_h9IMkqbnAmgSkEqqwczkGH_TcUUJHx-no,9546
28
+ rclone_api/util.py,sha256=NIWU1YLGWyNhICwXCpmAw0AgCXkOYG6BO6m1mTNQwzY,9559
29
29
  rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
30
30
  rclone_api/cmd/analyze.py,sha256=RHbvk1G5ZUc3qLqlm1AZEyQzd_W_ZjcbCNDvW4YpTKQ,1252
31
31
  rclone_api/cmd/copy_large_s3.py,sha256=E0B7P-JJTuOM7wMZtwQHJCpoLhccJleh0mnMq8ZiSUo,3234
@@ -58,9 +58,9 @@ rclone_api/s3/multipart/upload_parts_inline.py,sha256=V7syKjFyVIe4U9Ahl5XgqVTzt9
58
58
  rclone_api/s3/multipart/upload_parts_resumable.py,sha256=6-nlMclS8jyVvMvFbQDcZOX9MY1WbCcKA_s9bwuYxnk,9793
59
59
  rclone_api/s3/multipart/upload_parts_server_side_merge.py,sha256=Fp2pdrs5dONQI9LkfNolgAGj1-Z2V1SsRd0r0sreuXI,18040
60
60
  rclone_api/s3/multipart/upload_state.py,sha256=f-Aq2NqtAaMUMhYitlICSNIxCKurWAl2gDEUVizLIqw,6019
61
- rclone_api-1.5.60.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
62
- rclone_api-1.5.60.dist-info/METADATA,sha256=E3Sau2-Amjlg3WU7-0QcWjvVJzHpgBb34oYJqe0WoD8,37305
63
- rclone_api-1.5.60.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
64
- rclone_api-1.5.60.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
65
- rclone_api-1.5.60.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
66
- rclone_api-1.5.60.dist-info/RECORD,,
61
+ rclone_api-1.5.63.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
62
+ rclone_api-1.5.63.dist-info/METADATA,sha256=9XSnDbl63rF0hMxexBm7t65FmtxbjMyNiIURw5ixrxo,37305
63
+ rclone_api-1.5.63.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
64
+ rclone_api-1.5.63.dist-info/entry_points.txt,sha256=ognh2e11HTjn73_KL5MWI67pBKS2jekBi-QTiRXySXA,316
65
+ rclone_api-1.5.63.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
66
+ rclone_api-1.5.63.dist-info/RECORD,,