rclone-api 1.0.90__py2.py3-none-any.whl → 1.0.92__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.
rclone_api/rclone.py CHANGED
@@ -679,11 +679,12 @@ class Rclone:
679
679
  concurrent_chunks: int = 4, # This setting will scale the performance of the upload
680
680
  retries: int = 3,
681
681
  max_chunks_before_suspension: int | None = None,
682
+ mount_path: Path | None = None,
682
683
  ) -> MultiUploadResult:
683
684
  """For massive files that rclone can't handle in one go, this function will copy the file in chunks to an S3 store"""
684
685
  from rclone_api.s3.api import S3Client
685
686
  from rclone_api.s3.create import S3Credentials
686
- from rclone_api.util import S3PathInfo, split_s3_path
687
+ from rclone_api.util import S3PathInfo, random_str, split_s3_path
687
688
 
688
689
  other_args: list[str] = [
689
690
  "--no-modtime",
@@ -699,7 +700,7 @@ class Rclone:
699
700
  str(concurrent_chunks),
700
701
  "--vfs-fast-fingerprint",
701
702
  ]
702
- mount_path = Path("rclone_api_upload_mount")
703
+ mount_path = mount_path or Path("tmp_mnts") / random_str(12)
703
704
  src_path = Path(src)
704
705
  name = src_path.name
705
706
 
@@ -784,8 +785,7 @@ class Rclone:
784
785
  )
785
786
 
786
787
  out: MultiUploadResult = client.upload_file_multipart(
787
- upload_target=upload_target,
788
- upload_config=upload_config
788
+ upload_target=upload_target, upload_config=upload_config
789
789
  )
790
790
  return out
791
791
 
@@ -877,6 +877,7 @@ class Rclone:
877
877
  other_args: list[str] | None = None,
878
878
  ) -> Generator[Process, None, None]:
879
879
  """Like mount, but can be used in a context manager."""
880
+ error_happened = False
880
881
  proc = self.mount(
881
882
  src,
882
883
  outdir,
@@ -888,6 +889,7 @@ class Rclone:
888
889
  try:
889
890
  yield proc
890
891
  except Exception as e:
892
+ error_happened = True
891
893
  stack_trace = traceback.format_exc()
892
894
  warnings.warn(f"Error in scoped_mount: {e}\n\nStack Trace:\n{stack_trace}")
893
895
  raise
@@ -895,6 +897,24 @@ class Rclone:
895
897
  if proc.poll() is None:
896
898
  proc.terminate()
897
899
  proc.wait()
900
+ if not error_happened and outdir.exists():
901
+ time.sleep(2)
902
+ if outdir.exists():
903
+ print(f"{outdir} mount still exists, attempting to remove")
904
+ if not _IS_WINDOWS:
905
+ # attempt
906
+ os.system(f"fusermount -u {outdir}")
907
+ os.system(f"umount {outdir}")
908
+ time.sleep(2)
909
+ if outdir.exists():
910
+ is_empty = not list(outdir.iterdir())
911
+ if not is_empty:
912
+ warnings.warn(f"Failed to unmount {outdir}")
913
+ else:
914
+ try:
915
+ outdir.rmdir()
916
+ except Exception as e:
917
+ warnings.warn(f"Failed to remove {outdir}: {e}")
898
918
 
899
919
  @deprecated("mount")
900
920
  def mount_webdav(
rclone_api/s3/api.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import warnings
2
- from pathlib import Path
3
2
 
4
3
  from botocore.client import BaseClient
5
4
 
@@ -46,28 +45,40 @@ class S3Client:
46
45
  upload_target: S3UploadTarget,
47
46
  upload_config: S3MutliPartUploadConfig,
48
47
  ) -> MultiUploadResult:
49
- filesize = upload_target.src_file.stat().st_size
50
- if filesize < _MIN_THRESHOLD_FOR_CHUNKING:
51
- warnings.warn(
52
- f"File size {filesize} is less than the minimum threshold for chunking ({_MIN_THRESHOLD_FOR_CHUNKING}), switching to single threaded upload."
53
- )
54
- err = self.upload_file(upload_target)
55
- if err:
56
- raise err
57
- return MultiUploadResult.UPLOADED_FRESH
48
+
58
49
  chunk_size = upload_config.chunk_size
59
50
  retries = upload_config.retries
60
51
  resume_path_json = upload_config.resume_path_json
61
52
  max_chunks_before_suspension = upload_config.max_chunks_before_suspension
62
53
  bucket_name = upload_target.bucket_name
63
- out = upload_file_multipart(
64
- s3_client=self.client,
65
- bucket_name=bucket_name,
66
- file_path=upload_target.src_file,
67
- object_name=upload_target.s3_key,
68
- resumable_info_path=resume_path_json,
69
- chunk_size=chunk_size,
70
- retries=retries,
71
- max_chunks_before_suspension=max_chunks_before_suspension,
72
- )
73
- return out
54
+
55
+ try:
56
+ filesize = upload_target.src_file.stat().st_size
57
+ if filesize < _MIN_THRESHOLD_FOR_CHUNKING:
58
+ warnings.warn(
59
+ f"File size {filesize} is less than the minimum threshold for chunking ({_MIN_THRESHOLD_FOR_CHUNKING}), switching to single threaded upload."
60
+ )
61
+ err = self.upload_file(upload_target)
62
+ if err:
63
+ raise err
64
+ return MultiUploadResult.UPLOADED_FRESH
65
+
66
+ out = upload_file_multipart(
67
+ s3_client=self.client,
68
+ bucket_name=bucket_name,
69
+ file_path=upload_target.src_file,
70
+ object_name=upload_target.s3_key,
71
+ resumable_info_path=resume_path_json,
72
+ chunk_size=chunk_size,
73
+ retries=retries,
74
+ max_chunks_before_suspension=max_chunks_before_suspension,
75
+ )
76
+ return out
77
+ except Exception:
78
+ key = upload_target.s3_key
79
+ access_key_id = self.credentials.access_key_id[:4] + "..."
80
+ secret = self.credentials.secret_access_key[:4] + "..."
81
+ warnings.warn(
82
+ f"Error uploading {key} to {bucket_name} with\n access_key_id: {access_key_id}\n secret: {secret}\n"
83
+ )
84
+ raise
rclone_api/s3/types.py CHANGED
@@ -47,8 +47,9 @@ class S3MutliPartUploadConfig:
47
47
  retries: int
48
48
  resume_path_json: Path
49
49
  max_chunks_before_suspension: int | None = None
50
- mount_path: Path | None = None # If set this will be used to mount the src file, otherwise it's one is chosen automatically
51
-
50
+ mount_path: Path | None = (
51
+ None # If set this will be used to mount the src file, otherwise it's one is chosen automatically
52
+ )
52
53
 
53
54
 
54
55
  class MultiUploadResult(Enum):
rclone_api/util.py CHANGED
@@ -166,3 +166,10 @@ def split_s3_path(path: str) -> S3PathInfo:
166
166
  assert bucket
167
167
  assert key
168
168
  return S3PathInfo(remote=remote, bucket=bucket, key=key)
169
+
170
+
171
+ def random_str(length: int) -> str:
172
+ import random
173
+ import string
174
+
175
+ return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.90
3
+ Version: 1.0.92
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -12,24 +12,24 @@ 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
14
  rclone_api/process.py,sha256=RrMfTe0bndmJ6gBK67ioqNvCstJ8aTC8RlGX1XBLlcw,4191
15
- rclone_api/rclone.py,sha256=W4CIhDEPJqY5X9-HXKp-DTVLhU5H8YUOjGYAHDVy-yU,41207
15
+ rclone_api/rclone.py,sha256=tXVZv9N83DVVxVwevOo7FyzHCuUGjWx_KP51VwQ0QIY,42246
16
16
  rclone_api/remote.py,sha256=O9WDUFQy9f6oT1HdUbTixK2eg0xtBBm8k4Xl6aa6K00,431
17
17
  rclone_api/rpath.py,sha256=8ZA_1wxWtskwcy0I8V2VbjKDmzPkiWd8Q2JQSvh-sYE,2586
18
18
  rclone_api/scan_missing_folders.py,sha256=Kulca2Q6WZodt00ATFHkmqqInuoPvBkhTcS9703y6po,4740
19
19
  rclone_api/types.py,sha256=NC3e78aXCx-sEQ-FqEaC9KzaJDdJhJrKa4Nwum_-Db0,563
20
- rclone_api/util.py,sha256=4bJF1CC8J2NW6UbJU3oSxmTJgN04uTovABZJn7c3-zk,5025
20
+ rclone_api/util.py,sha256=efck9W0rw5wfeRI35iiEz4dy2cMkNpVXrQ9zzynkBks,5185
21
21
  rclone_api/walk.py,sha256=-54NVE8EJcCstwDoaC_UtHm73R2HrZwVwQmsnv55xNU,3369
22
22
  rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
23
23
  rclone_api/cmd/copy_large_s3.py,sha256=FPU0S1Y9pApVLmWcdMT_3llywjEtOtwobXTnMXE-FhY,2690
24
24
  rclone_api/cmd/list_files.py,sha256=x8FHODEilwKqwdiU1jdkeJbLwOqUkUQuDWPo2u_zpf0,741
25
- rclone_api/s3/api.py,sha256=Ju9A6uNHON2by2jJPtH-awe-3d588QLh5E-vjdV4kOY,2729
25
+ rclone_api/s3/api.py,sha256=7elz5U5su4rdPHEMHHMBZ_vESQobJDTK_MR7sA_a1YU,3182
26
26
  rclone_api/s3/basic_ops.py,sha256=hK3366xhVEzEcjz9Gk_8lFx6MRceAk72cax6mUrr6ko,2104
27
27
  rclone_api/s3/chunk_uploader.py,sha256=Wcm4h_A6ORaJvT9P9qSeknbJYch22RKZ4FGo1iePlAw,17385
28
28
  rclone_api/s3/create.py,sha256=X4mgjekgAoyHNeXnznHNS63DFViAhI0p7-fXDxml0y4,2701
29
- rclone_api/s3/types.py,sha256=BKvNkAFjLJK7Zd9xQya8gdjqJPLqdCPZSXD8GeFyP1A,1346
30
- rclone_api-1.0.90.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
31
- rclone_api-1.0.90.dist-info/METADATA,sha256=7Y-NCkQi9yBFGqd90T-j9oA2rvA0rEu_-znW5LW_dZY,4479
32
- rclone_api-1.0.90.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
33
- rclone_api-1.0.90.dist-info/entry_points.txt,sha256=6eNqTRXKhVf8CpWNjXiOa_0Du9tHiW_HD2iQSXRsUg8,132
34
- rclone_api-1.0.90.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
35
- rclone_api-1.0.90.dist-info/RECORD,,
29
+ rclone_api/s3/types.py,sha256=81_3jwg6MGIxC-GxL-6zANzKO6au9C0BWvAqRyODxOM,1361
30
+ rclone_api-1.0.92.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
31
+ rclone_api-1.0.92.dist-info/METADATA,sha256=rCGGQg-8Xgf7fRatzVH0cmaNtwVhXsFkc8NO7rPYVY8,4479
32
+ rclone_api-1.0.92.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
33
+ rclone_api-1.0.92.dist-info/entry_points.txt,sha256=6eNqTRXKhVf8CpWNjXiOa_0Du9tHiW_HD2iQSXRsUg8,132
34
+ rclone_api-1.0.92.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
35
+ rclone_api-1.0.92.dist-info/RECORD,,