rclone-api 1.1.15__tar.gz → 1.1.17__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.15 → rclone_api-1.1.17}/PKG-INFO +1 -1
  2. {rclone_api-1.1.15 → rclone_api-1.1.17}/pyproject.toml +1 -1
  3. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/process.py +50 -34
  4. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/s3/chunk_types.py +1 -3
  5. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api.egg-info/PKG-INFO +1 -1
  6. {rclone_api-1.1.15 → rclone_api-1.1.17}/.aiderignore +0 -0
  7. {rclone_api-1.1.15 → rclone_api-1.1.17}/.github/workflows/lint.yml +0 -0
  8. {rclone_api-1.1.15 → rclone_api-1.1.17}/.github/workflows/push_macos.yml +0 -0
  9. {rclone_api-1.1.15 → rclone_api-1.1.17}/.github/workflows/push_ubuntu.yml +0 -0
  10. {rclone_api-1.1.15 → rclone_api-1.1.17}/.github/workflows/push_win.yml +0 -0
  11. {rclone_api-1.1.15 → rclone_api-1.1.17}/.gitignore +0 -0
  12. {rclone_api-1.1.15 → rclone_api-1.1.17}/.pylintrc +0 -0
  13. {rclone_api-1.1.15 → rclone_api-1.1.17}/.vscode/launch.json +0 -0
  14. {rclone_api-1.1.15 → rclone_api-1.1.17}/.vscode/settings.json +0 -0
  15. {rclone_api-1.1.15 → rclone_api-1.1.17}/.vscode/tasks.json +0 -0
  16. {rclone_api-1.1.15 → rclone_api-1.1.17}/LICENSE +0 -0
  17. {rclone_api-1.1.15 → rclone_api-1.1.17}/MANIFEST.in +0 -0
  18. {rclone_api-1.1.15 → rclone_api-1.1.17}/README.md +0 -0
  19. {rclone_api-1.1.15 → rclone_api-1.1.17}/clean +0 -0
  20. {rclone_api-1.1.15 → rclone_api-1.1.17}/install +0 -0
  21. {rclone_api-1.1.15 → rclone_api-1.1.17}/lint +0 -0
  22. {rclone_api-1.1.15 → rclone_api-1.1.17}/requirements.testing.txt +0 -0
  23. {rclone_api-1.1.15 → rclone_api-1.1.17}/setup.cfg +0 -0
  24. {rclone_api-1.1.15 → rclone_api-1.1.17}/setup.py +0 -0
  25. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/__init__.py +0 -0
  26. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/assets/example.txt +0 -0
  27. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/cli.py +0 -0
  28. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/cmd/copy_large_s3.py +0 -0
  29. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/cmd/list_files.py +0 -0
  30. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/completed_process.py +0 -0
  31. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/config.py +0 -0
  32. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/convert.py +0 -0
  33. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/deprecated.py +0 -0
  34. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/diff.py +0 -0
  35. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/dir.py +0 -0
  36. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/dir_listing.py +0 -0
  37. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/exec.py +0 -0
  38. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/experimental/flags.py +0 -0
  39. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/experimental/flags_base.py +0 -0
  40. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/file.py +0 -0
  41. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/filelist.py +0 -0
  42. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/group_files.py +0 -0
  43. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/mount.py +0 -0
  44. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/rclone.py +0 -0
  45. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/remote.py +0 -0
  46. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/rpath.py +0 -0
  47. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/s3/api.py +0 -0
  48. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/s3/basic_ops.py +0 -0
  49. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/s3/chunk_file.py +0 -0
  50. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/s3/chunk_uploader.py +0 -0
  51. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/s3/create.py +0 -0
  52. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/s3/types.py +0 -0
  53. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/scan_missing_folders.py +0 -0
  54. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/types.py +0 -0
  55. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/util.py +0 -0
  56. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api/walk.py +0 -0
  57. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api.egg-info/SOURCES.txt +0 -0
  58. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  59. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api.egg-info/entry_points.txt +0 -0
  60. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api.egg-info/requires.txt +0 -0
  61. {rclone_api-1.1.15 → rclone_api-1.1.17}/src/rclone_api.egg-info/top_level.txt +0 -0
  62. {rclone_api-1.1.15 → rclone_api-1.1.17}/test +0 -0
  63. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/archive/test_paramiko.py.disabled +0 -0
  64. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_cmd_list_files.py +0 -0
  65. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_copy.py +0 -0
  66. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_copy_files.py +0 -0
  67. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_diff.py +0 -0
  68. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_group_files.py +0 -0
  69. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_is_synced.py +0 -0
  70. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_ls.py +0 -0
  71. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_mount.py +0 -0
  72. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_mount_s3.py +0 -0
  73. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_mounted_ranged_download.py +0 -0
  74. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_obscure.py +0 -0
  75. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_rclone_config.py +0 -0
  76. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_remote_control.py +0 -0
  77. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_remotes.py +0 -0
  78. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_s3.py +0 -0
  79. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_scan_missing_folders.py +0 -0
  80. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_size_files.py +0 -0
  81. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_size_suffix.py +0 -0
  82. {rclone_api-1.1.15 → rclone_api-1.1.17}/tests/test_walk.py +0 -0
  83. {rclone_api-1.1.15 → rclone_api-1.1.17}/tox.ini +0 -0
  84. {rclone_api-1.1.15 → rclone_api-1.1.17}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.1.15
3
+ Version: 1.1.17
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.1.15"
24
+ version = "1.1.17"
25
25
 
26
26
  [tool.setuptools]
27
27
  package-dir = {"" = "src"}
@@ -1,5 +1,9 @@
1
+ import atexit
1
2
  import os
2
3
  import subprocess
4
+ import threading
5
+ import time
6
+ import weakref
3
7
  from dataclasses import dataclass
4
8
  from pathlib import Path
5
9
  from tempfile import TemporaryDirectory
@@ -8,44 +12,10 @@ from typing import Any
8
12
  from rclone_api.config import Config
9
13
  from rclone_api.util import get_verbose
10
14
 
11
- # def rclone_launch_process(
12
- # cmd: list[str],
13
- # rclone_conf: Path | Config,
14
- # rclone_exe: Path,
15
- # verbose: bool | None = None,
16
- # ) -> subprocess.Popen:
17
- # tempdir: TemporaryDirectory | None = None
18
- # verbose = _get_verbose(verbose)
19
- # assert verbose is not None
20
-
21
- # try:
22
- # if isinstance(rclone_conf, Config):
23
- # tempdir = TemporaryDirectory()
24
- # tmpfile = Path(tempdir.name) / "rclone.conf"
25
- # tmpfile.write_text(rclone_conf.text, encoding="utf-8")
26
- # rclone_conf = tmpfile
27
- # cmd = (
28
- # [str(rclone_exe.resolve())] + ["--config", str(rclone_conf.resolve())] + cmd
29
- # )
30
- # if verbose:
31
- # cmd_str = subprocess.list2cmdline(cmd)
32
- # print(f"Running: {cmd_str}")
33
- # cp = subprocess.Popen(
34
- # cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False
35
- # )
36
- # return cp
37
- # finally:
38
- # if tempdir:
39
- # try:
40
- # tempdir.cleanup()
41
- # except Exception as e:
42
- # print(f"Error cleaning up tempdir: {e}")
43
-
44
15
 
45
16
  def _get_verbose(verbose: bool | None) -> bool:
46
17
  if verbose is not None:
47
18
  return verbose
48
- # get it from the environment
49
19
  return bool(int(os.getenv("RCLONE_API_VERBOSE", "0")))
50
20
 
51
21
 
@@ -93,6 +63,17 @@ class Process:
93
63
 
94
64
  self.process = subprocess.Popen(self.cmd, **kwargs) # type: ignore
95
65
 
66
+ # Register an atexit callback using a weak reference to avoid
67
+ # keeping the Process instance alive solely due to the callback.
68
+ self_ref = weakref.ref(self)
69
+
70
+ def exit_cleanup():
71
+ obj = self_ref()
72
+ if obj is not None:
73
+ obj._atexit_terminate()
74
+
75
+ atexit.register(exit_cleanup)
76
+
96
77
  def cleanup(self) -> None:
97
78
  if self.tempdir and self.needs_cleanup:
98
79
  try:
@@ -100,6 +81,41 @@ class Process:
100
81
  except Exception as e:
101
82
  print(f"Error cleaning up tempdir: {e}")
102
83
 
84
+ def _atexit_terminate(self) -> None:
85
+ """
86
+ Registered via atexit, this method attempts to gracefully terminate the process.
87
+ If the process does not exit within a short timeout, it is aggressively killed.
88
+ """
89
+ if self.process.poll() is None: # Process is still running
90
+
91
+ def terminate_sequence():
92
+ try:
93
+ # Try to terminate gracefully.
94
+ self.process.terminate()
95
+ except Exception as e:
96
+ print(f"Error calling terminate on process {self.process.pid}: {e}")
97
+ # Allow time for graceful shutdown.
98
+ timeout = 2 # seconds
99
+ start = time.time()
100
+ while self.process.poll() is None and (time.time() - start) < timeout:
101
+ time.sleep(0.1)
102
+ # If still running, kill aggressively.
103
+ if self.process.poll() is None:
104
+ try:
105
+ self.process.kill()
106
+ except Exception as e:
107
+ print(f"Error calling kill on process {self.process.pid}: {e}")
108
+ # Optionally wait briefly for termination.
109
+ try:
110
+ self.process.wait(timeout=1)
111
+ except Exception:
112
+ pass
113
+
114
+ # Run the termination sequence in a separate daemon thread.
115
+ t = threading.Thread(target=terminate_sequence, daemon=True)
116
+ t.start()
117
+ t.join(timeout=3)
118
+
103
119
  @property
104
120
  def pid(self) -> int:
105
121
  return self.process.pid
@@ -221,9 +221,7 @@ class UploadState:
221
221
 
222
222
  def save(self) -> None:
223
223
  with _SAVE_STATE_LOCK:
224
-
225
224
  self._check_fingerprint_no_lock()
226
-
227
225
  self._save_no_lock()
228
226
 
229
227
  def _check_fingerprint_no_lock(self) -> None:
@@ -243,7 +241,7 @@ class UploadState:
243
241
  curr_fingerprint = self.fingerprint()
244
242
  if curr_fingerprint != last_upload_state.fingerprint():
245
243
  raise ValueError(
246
- f"Cannot save state, fingerprint changed from {curr_fingerprint} to {self.upload_info.fingerprint()}"
244
+ f"Cannot save state, fingerprint changed from {curr_fingerprint} to {last_upload_state.fingerprint()}"
247
245
  )
248
246
 
249
247
  def _save_no_lock(self) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.1.15
3
+ Version: 1.1.17
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