rclone-api 1.0.23__tar.gz → 1.0.24__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. {rclone_api-1.0.23 → rclone_api-1.0.24}/PKG-INFO +1 -1
  2. {rclone_api-1.0.23 → rclone_api-1.0.24}/pyproject.toml +3 -3
  3. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/rclone.py +52 -0
  4. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api.egg-info/PKG-INFO +1 -1
  5. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api.egg-info/SOURCES.txt +1 -0
  6. rclone_api-1.0.24/tests/test_mount_s3.py +105 -0
  7. {rclone_api-1.0.23 → rclone_api-1.0.24}/.aiderignore +0 -0
  8. {rclone_api-1.0.23 → rclone_api-1.0.24}/.github/workflows/lint.yml +0 -0
  9. {rclone_api-1.0.23 → rclone_api-1.0.24}/.github/workflows/push_macos.yml +0 -0
  10. {rclone_api-1.0.23 → rclone_api-1.0.24}/.github/workflows/push_ubuntu.yml +0 -0
  11. {rclone_api-1.0.23 → rclone_api-1.0.24}/.github/workflows/push_win.yml +0 -0
  12. {rclone_api-1.0.23 → rclone_api-1.0.24}/.gitignore +0 -0
  13. {rclone_api-1.0.23 → rclone_api-1.0.24}/.pylintrc +0 -0
  14. {rclone_api-1.0.23 → rclone_api-1.0.24}/.vscode/launch.json +0 -0
  15. {rclone_api-1.0.23 → rclone_api-1.0.24}/.vscode/settings.json +0 -0
  16. {rclone_api-1.0.23 → rclone_api-1.0.24}/.vscode/tasks.json +0 -0
  17. {rclone_api-1.0.23 → rclone_api-1.0.24}/LICENSE +0 -0
  18. {rclone_api-1.0.23 → rclone_api-1.0.24}/MANIFEST.in +0 -0
  19. {rclone_api-1.0.23 → rclone_api-1.0.24}/README.md +0 -0
  20. {rclone_api-1.0.23 → rclone_api-1.0.24}/clean +0 -0
  21. {rclone_api-1.0.23 → rclone_api-1.0.24}/install +0 -0
  22. {rclone_api-1.0.23 → rclone_api-1.0.24}/lint +0 -0
  23. {rclone_api-1.0.23 → rclone_api-1.0.24}/requirements.testing.txt +0 -0
  24. {rclone_api-1.0.23 → rclone_api-1.0.24}/setup.cfg +0 -0
  25. {rclone_api-1.0.23 → rclone_api-1.0.24}/setup.py +0 -0
  26. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/__init__.py +0 -0
  27. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/assets/example.txt +0 -0
  28. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/cli.py +0 -0
  29. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/cmd/list_files.py +0 -0
  30. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/config.py +0 -0
  31. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/convert.py +0 -0
  32. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/dir.py +0 -0
  33. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/dir_listing.py +0 -0
  34. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/exec.py +0 -0
  35. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/file.py +0 -0
  36. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/filelist.py +0 -0
  37. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/process.py +0 -0
  38. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/remote.py +0 -0
  39. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/rpath.py +0 -0
  40. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/util.py +0 -0
  41. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api/walk.py +0 -0
  42. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  43. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api.egg-info/entry_points.txt +0 -0
  44. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api.egg-info/requires.txt +0 -0
  45. {rclone_api-1.0.23 → rclone_api-1.0.24}/src/rclone_api.egg-info/top_level.txt +0 -0
  46. {rclone_api-1.0.23 → rclone_api-1.0.24}/test +0 -0
  47. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_cmd_list_files.py +0 -0
  48. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_copy.py +0 -0
  49. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_is_synced.py +0 -0
  50. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_ls.py +0 -0
  51. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_mount.py +0 -0
  52. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_mount_webdav.py +0 -0
  53. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_obscure.py +0 -0
  54. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_remotes.py +0 -0
  55. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_serve_webdav.py +0 -0
  56. {rclone_api-1.0.23 → rclone_api-1.0.24}/tests/test_walk.py +0 -0
  57. {rclone_api-1.0.23 → rclone_api-1.0.24}/tox.ini +0 -0
  58. {rclone_api-1.0.23 → rclone_api-1.0.24}/upload_package.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.23
3
+ Version: 1.0.24
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  Maintainer: Zachary Vorhies
@@ -15,7 +15,7 @@ dependencies = [
15
15
  "python-dotenv>=1.0.0",
16
16
  ]
17
17
  # Change this with the version number bump.
18
- version = "1.0.23"
18
+ version = "1.0.24"
19
19
 
20
20
  [tool.setuptools]
21
21
  package-dir = {"" = "src"}
@@ -44,5 +44,5 @@ profile = "black"
44
44
  ignore_missing_imports = true
45
45
  disable_error_code = ["import-untyped"]
46
46
 
47
- [project.scripts]
48
- rclone-api-listfiles = "rclone_api.cmd.list_files:main"
47
+ [project.scripts]
48
+ rclone-api-listfiles = "rclone_api.cmd.list_files:main"
@@ -6,6 +6,7 @@ import subprocess
6
6
  import time
7
7
  import warnings
8
8
  from concurrent.futures import ThreadPoolExecutor
9
+ from enum import Enum
9
10
  from fnmatch import fnmatch
10
11
  from pathlib import Path
11
12
  from typing import Generator
@@ -23,6 +24,11 @@ from rclone_api.util import get_rclone_exe, to_path, wait_for_mount
23
24
  from rclone_api.walk import walk
24
25
 
25
26
 
27
+ class ModTimeStrategy(Enum):
28
+ USE_SERVER_MODTIME = "use-server-modtime"
29
+ NO_MODTIME = "no-modtime"
30
+
31
+
26
32
  class Rclone:
27
33
  def __init__(
28
34
  self, rclone_conf: Path | Config, rclone_exe: Path | None = None
@@ -299,6 +305,7 @@ class Rclone:
299
305
  url: str,
300
306
  outdir: Path,
301
307
  vfs_cache_mode="full",
308
+ vfs_disk_space_total_size: str | None = "10G",
302
309
  other_cmds: list[str] | None = None,
303
310
  ) -> Process:
304
311
  """Mount a remote or directory to a local path.
@@ -327,10 +334,55 @@ class Rclone:
327
334
  cmd_list.append(vfs_cache_mode)
328
335
  if other_cmds:
329
336
  cmd_list += other_cmds
337
+ if vfs_disk_space_total_size is not None:
338
+ cmd_list.append("--vfs-cache-max-size")
339
+ cmd_list.append(vfs_disk_space_total_size)
330
340
  proc = self._launch_process(cmd_list)
331
341
  wait_for_mount(outdir, proc)
332
342
  return proc
333
343
 
344
+ def mount_s3(
345
+ self,
346
+ url: str,
347
+ outdir: Path,
348
+ vfs_cache_mode="full",
349
+ transfers: int | None = 16,
350
+ modtime_strategy: (
351
+ ModTimeStrategy | None
352
+ ) = ModTimeStrategy.USE_SERVER_MODTIME, # speeds up S3 operations
353
+ vfs_read_chunk_streams: int | None = 16,
354
+ vfs_read_chunk_size: str | None = "4M",
355
+ vfs_fast_fingerprint: bool = True,
356
+ other_cmds: list[str] | None = None,
357
+ ) -> Process:
358
+ """Mount a remote or directory to a local path.
359
+
360
+ Args:
361
+ src: Remote or directory to mount
362
+ outdir: Local path to mount to
363
+ """
364
+ other_cmds = other_cmds or []
365
+ if modtime_strategy is not None:
366
+ other_cmds.append(f"--{modtime_strategy.value}")
367
+ if (vfs_cache_mode == "full" or vfs_cache_mode == "writes") and (
368
+ transfers is not None
369
+ ):
370
+ other_cmds.append("--transfers")
371
+ other_cmds.append(str(transfers))
372
+ if vfs_read_chunk_streams:
373
+ other_cmds.append("--vfs-read-chunk-streams")
374
+ other_cmds.append(str(vfs_read_chunk_streams))
375
+ if vfs_read_chunk_size:
376
+ other_cmds.append("--vfs-read-chunk-size")
377
+ other_cmds.append(vfs_read_chunk_size)
378
+ if vfs_fast_fingerprint:
379
+ other_cmds.append("--vfs-fast-fingerprint")
380
+
381
+ other_cmds = other_cmds if other_cmds else None
382
+ return self.mount(
383
+ url, outdir, vfs_cache_mode=vfs_cache_mode, other_cmds=other_cmds
384
+ )
385
+
334
386
  def serve_webdav(
335
387
  self,
336
388
  src: Remote | Dir | str,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.0.23
3
+ Version: 1.0.24
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  Maintainer: Zachary Vorhies
@@ -48,6 +48,7 @@ tests/test_copy.py
48
48
  tests/test_is_synced.py
49
49
  tests/test_ls.py
50
50
  tests/test_mount.py
51
+ tests/test_mount_s3.py
51
52
  tests/test_mount_webdav.py
52
53
  tests/test_obscure.py
53
54
  tests/test_remotes.py
@@ -0,0 +1,105 @@
1
+ """
2
+ Unit test file for testing rclone mount functionality.
3
+ """
4
+
5
+ import os
6
+ import subprocess
7
+ import unittest
8
+ from pathlib import Path
9
+
10
+ from dotenv import load_dotenv
11
+
12
+ from rclone_api import Config, Process, Rclone
13
+
14
+ load_dotenv()
15
+
16
+
17
+ def _generate_rclone_config() -> Config:
18
+ # Load environment variables
19
+ BUCKET_KEY_SECRET = os.getenv("BUCKET_KEY_SECRET")
20
+ BUCKET_KEY_PUBLIC = os.getenv("BUCKET_KEY_PUBLIC")
21
+ BUCKET_URL = "sfo3.digitaloceanspaces.com"
22
+
23
+ config_text = f"""
24
+ [dst]
25
+ type = s3
26
+ provider = DigitalOcean
27
+ access_key_id = {BUCKET_KEY_PUBLIC}
28
+ secret_access_key = {BUCKET_KEY_SECRET}
29
+ endpoint = {BUCKET_URL}
30
+ """
31
+ return Config(config_text)
32
+
33
+
34
+ class RcloneMountS3Tests(unittest.TestCase):
35
+ """Test rclone mount functionality."""
36
+
37
+ def setUp(self) -> None:
38
+ """Check if all required environment variables are set before running tests."""
39
+ required_vars = [
40
+ "BUCKET_NAME",
41
+ "BUCKET_KEY_SECRET",
42
+ "BUCKET_KEY_PUBLIC",
43
+ "BUCKET_URL",
44
+ ]
45
+ missing = [var for var in required_vars if not os.getenv(var)]
46
+ if missing:
47
+ self.skipTest(
48
+ f"Missing required environment variables: {', '.join(missing)}"
49
+ )
50
+
51
+ self.bucket_name = os.getenv("BUCKET_NAME")
52
+ self.mount_point = Path("test_mount")
53
+ # Create mount point directory if it doesn't exist
54
+ # self.mount_point.mkdir(exist_ok=True)
55
+ # make parents
56
+ parent = self.mount_point.parent
57
+ if not parent.exists():
58
+ parent.mkdir(parents=True)
59
+
60
+ os.environ["RCLONE_API_VERBOSE"] = "1"
61
+ self.rclone = Rclone(_generate_rclone_config())
62
+
63
+ def test_mount(self) -> None:
64
+ """Test mounting a remote bucket."""
65
+ remote_path = f"dst:{self.bucket_name}"
66
+ process: Process | None = None
67
+
68
+ try:
69
+ # Start the mount process
70
+ process = self.rclone.mount_s3(remote_path, self.mount_point)
71
+ self.assertIsNone(
72
+ process.poll(), "Mount process should still be running after 2 seconds"
73
+ )
74
+
75
+ # Verify mount point exists and is accessible
76
+ self.assertTrue(self.mount_point.exists())
77
+ self.assertTrue(self.mount_point.is_dir())
78
+
79
+ # Check if we can list contents
80
+ contents = list(self.mount_point.iterdir())
81
+ self.assertGreater(
82
+ len(contents), 0, "Mounted directory should not be empty"
83
+ )
84
+
85
+ except subprocess.CalledProcessError as e:
86
+ self.fail(f"Mount operation failed: {str(e)}")
87
+ finally:
88
+ # Cleanup will happen in tearDown
89
+ if process:
90
+ if process.poll() is None:
91
+ process.kill()
92
+ stdout = process.stdout
93
+ if stdout:
94
+ # stdout is a buffered reader
95
+ for line in stdout:
96
+ print(line)
97
+ stderr = process.stderr
98
+ if stderr:
99
+ for line in stderr:
100
+ print(line)
101
+ process.kill()
102
+
103
+
104
+ if __name__ == "__main__":
105
+ unittest.main()
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