rclone-api 1.0.90__tar.gz → 1.0.93__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 (79) hide show
  1. {rclone_api-1.0.90 → rclone_api-1.0.93}/PKG-INFO +1 -1
  2. {rclone_api-1.0.90 → rclone_api-1.0.93}/pyproject.toml +1 -1
  3. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/rclone.py +24 -4
  4. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/s3/api.py +43 -21
  5. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/s3/types.py +3 -2
  6. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/util.py +7 -0
  7. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api.egg-info/PKG-INFO +1 -1
  8. {rclone_api-1.0.90 → rclone_api-1.0.93}/.aiderignore +0 -0
  9. {rclone_api-1.0.90 → rclone_api-1.0.93}/.github/workflows/lint.yml +0 -0
  10. {rclone_api-1.0.90 → rclone_api-1.0.93}/.github/workflows/push_macos.yml +0 -0
  11. {rclone_api-1.0.90 → rclone_api-1.0.93}/.github/workflows/push_ubuntu.yml +0 -0
  12. {rclone_api-1.0.90 → rclone_api-1.0.93}/.github/workflows/push_win.yml +0 -0
  13. {rclone_api-1.0.90 → rclone_api-1.0.93}/.gitignore +0 -0
  14. {rclone_api-1.0.90 → rclone_api-1.0.93}/.pylintrc +0 -0
  15. {rclone_api-1.0.90 → rclone_api-1.0.93}/.vscode/launch.json +0 -0
  16. {rclone_api-1.0.90 → rclone_api-1.0.93}/.vscode/settings.json +0 -0
  17. {rclone_api-1.0.90 → rclone_api-1.0.93}/.vscode/tasks.json +0 -0
  18. {rclone_api-1.0.90 → rclone_api-1.0.93}/LICENSE +0 -0
  19. {rclone_api-1.0.90 → rclone_api-1.0.93}/MANIFEST.in +0 -0
  20. {rclone_api-1.0.90 → rclone_api-1.0.93}/README.md +0 -0
  21. {rclone_api-1.0.90 → rclone_api-1.0.93}/clean +0 -0
  22. {rclone_api-1.0.90 → rclone_api-1.0.93}/install +0 -0
  23. {rclone_api-1.0.90 → rclone_api-1.0.93}/lint +0 -0
  24. {rclone_api-1.0.90 → rclone_api-1.0.93}/requirements.testing.txt +0 -0
  25. {rclone_api-1.0.90 → rclone_api-1.0.93}/setup.cfg +0 -0
  26. {rclone_api-1.0.90 → rclone_api-1.0.93}/setup.py +0 -0
  27. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/__init__.py +0 -0
  28. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/assets/example.txt +0 -0
  29. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/cli.py +0 -0
  30. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/cmd/copy_large_s3.py +0 -0
  31. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/cmd/list_files.py +0 -0
  32. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/completed_process.py +0 -0
  33. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/config.py +0 -0
  34. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/convert.py +0 -0
  35. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/deprecated.py +0 -0
  36. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/diff.py +0 -0
  37. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/dir.py +0 -0
  38. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/dir_listing.py +0 -0
  39. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/exec.py +0 -0
  40. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/file.py +0 -0
  41. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/filelist.py +0 -0
  42. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/group_files.py +0 -0
  43. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/process.py +0 -0
  44. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/remote.py +0 -0
  45. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/rpath.py +0 -0
  46. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/s3/basic_ops.py +0 -0
  47. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/s3/chunk_uploader.py +0 -0
  48. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/s3/create.py +0 -0
  49. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/scan_missing_folders.py +0 -0
  50. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/types.py +0 -0
  51. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api/walk.py +0 -0
  52. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api.egg-info/SOURCES.txt +0 -0
  53. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  54. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api.egg-info/entry_points.txt +0 -0
  55. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api.egg-info/requires.txt +0 -0
  56. {rclone_api-1.0.90 → rclone_api-1.0.93}/src/rclone_api.egg-info/top_level.txt +0 -0
  57. {rclone_api-1.0.90 → rclone_api-1.0.93}/test +0 -0
  58. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/archive/test_paramiko.py.disabled +0 -0
  59. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_cmd_list_files.py +0 -0
  60. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_copy.py +0 -0
  61. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_copy_files.py +0 -0
  62. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_diff.py +0 -0
  63. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_group_files.py +0 -0
  64. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_is_synced.py +0 -0
  65. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_ls.py +0 -0
  66. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_mount.py +0 -0
  67. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_mount_s3.py +0 -0
  68. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_mount_webdav.py +0 -0
  69. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_mounted_ranged_download.py +0 -0
  70. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_obscure.py +0 -0
  71. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_rclone_config.py +0 -0
  72. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_remote_control.py +0 -0
  73. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_remotes.py +0 -0
  74. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_s3.py +0 -0
  75. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_scan_missing_folders.py +0 -0
  76. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_size_files.py +0 -0
  77. {rclone_api-1.0.90 → rclone_api-1.0.93}/tests/test_walk.py +0 -0
  78. {rclone_api-1.0.90 → rclone_api-1.0.93}/tox.ini +0 -0
  79. {rclone_api-1.0.90 → rclone_api-1.0.93}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.90
3
+ Version: 1.0.93
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -21,7 +21,7 @@ dependencies = [
21
21
  ]
22
22
 
23
23
  # Change this with the version number bump.
24
- version = "1.0.90"
24
+ version = "1.0.93"
25
25
 
26
26
  [tool.setuptools]
27
27
  package-dir = {"" = "src"}
@@ -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(
@@ -1,5 +1,5 @@
1
+ import json
1
2
  import warnings
2
- from pathlib import Path
3
3
 
4
4
  from botocore.client import BaseClient
5
5
 
@@ -46,28 +46,50 @@ class S3Client:
46
46
  upload_target: S3UploadTarget,
47
47
  upload_config: S3MutliPartUploadConfig,
48
48
  ) -> 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
49
+
58
50
  chunk_size = upload_config.chunk_size
59
51
  retries = upload_config.retries
60
52
  resume_path_json = upload_config.resume_path_json
61
53
  max_chunks_before_suspension = upload_config.max_chunks_before_suspension
62
54
  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
55
+
56
+ try:
57
+ filesize = upload_target.src_file.stat().st_size
58
+ if filesize < _MIN_THRESHOLD_FOR_CHUNKING:
59
+ warnings.warn(
60
+ f"File size {filesize} is less than the minimum threshold for chunking ({_MIN_THRESHOLD_FOR_CHUNKING}), switching to single threaded upload."
61
+ )
62
+ err = self.upload_file(upload_target)
63
+ if err:
64
+ raise err
65
+ return MultiUploadResult.UPLOADED_FRESH
66
+
67
+ out = upload_file_multipart(
68
+ s3_client=self.client,
69
+ bucket_name=bucket_name,
70
+ file_path=upload_target.src_file,
71
+ object_name=upload_target.s3_key,
72
+ resumable_info_path=resume_path_json,
73
+ chunk_size=chunk_size,
74
+ retries=retries,
75
+ max_chunks_before_suspension=max_chunks_before_suspension,
76
+ )
77
+ return out
78
+ except Exception as e:
79
+ key = upload_target.s3_key
80
+ access_key_id = self.credentials.access_key_id[:4] + "..."
81
+ secret = self.credentials.secret_access_key[:4] + "..."
82
+ endpoint_url = self.credentials.endpoint_url
83
+ provider = self.credentials.provider
84
+ region_name = self.credentials.region_name
85
+ info_json = {
86
+ "key": key,
87
+ "access_key_id": access_key_id[:4] + "...",
88
+ "secret": secret[:4] + "...",
89
+ "endpoint_url": endpoint_url,
90
+ "provider": provider,
91
+ "region": region_name,
92
+ }
93
+ info_json_str = json.dumps(info_json, indent=2)
94
+ warnings.warn(f"Error uploading file: {e}\nInfo:\n\n{info_json_str}")
95
+ raise
@@ -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):
@@ -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.93
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
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