rclone-api 1.4.25__tar.gz → 1.4.28__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 (112) hide show
  1. rclone_api-1.4.28/PKG-INFO +556 -0
  2. rclone_api-1.4.28/README.md +535 -0
  3. {rclone_api-1.4.25 → rclone_api-1.4.28}/pyproject.toml +2 -2
  4. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/__init__.py +2 -29
  5. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/cmd/copy_large_s3.py +1 -1
  6. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/rclone_impl.py +1 -104
  7. rclone_api-1.4.28/src/rclone_api.egg-info/PKG-INFO +556 -0
  8. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_copy_file_resumable_s3.py +2 -32
  9. rclone_api-1.4.25/PKG-INFO +0 -154
  10. rclone_api-1.4.25/README.md +0 -133
  11. rclone_api-1.4.25/src/rclone_api.egg-info/PKG-INFO +0 -154
  12. {rclone_api-1.4.25 → rclone_api-1.4.28}/.aiderignore +0 -0
  13. {rclone_api-1.4.25 → rclone_api-1.4.28}/.github/workflows/lint.yml +0 -0
  14. {rclone_api-1.4.25 → rclone_api-1.4.28}/.github/workflows/push_macos.yml +0 -0
  15. {rclone_api-1.4.25 → rclone_api-1.4.28}/.github/workflows/push_ubuntu.yml +0 -0
  16. {rclone_api-1.4.25 → rclone_api-1.4.28}/.github/workflows/push_win.yml +0 -0
  17. {rclone_api-1.4.25 → rclone_api-1.4.28}/.gitignore +0 -0
  18. {rclone_api-1.4.25 → rclone_api-1.4.28}/.pylintrc +0 -0
  19. {rclone_api-1.4.25 → rclone_api-1.4.28}/.vscode/launch.json +0 -0
  20. {rclone_api-1.4.25 → rclone_api-1.4.28}/.vscode/settings.json +0 -0
  21. {rclone_api-1.4.25 → rclone_api-1.4.28}/.vscode/tasks.json +0 -0
  22. {rclone_api-1.4.25 → rclone_api-1.4.28}/LICENSE +0 -0
  23. {rclone_api-1.4.25 → rclone_api-1.4.28}/MANIFEST.in +0 -0
  24. {rclone_api-1.4.25 → rclone_api-1.4.28}/clean +0 -0
  25. {rclone_api-1.4.25 → rclone_api-1.4.28}/install +0 -0
  26. {rclone_api-1.4.25 → rclone_api-1.4.28}/lint +0 -0
  27. {rclone_api-1.4.25 → rclone_api-1.4.28}/requirements.testing.txt +0 -0
  28. {rclone_api-1.4.25 → rclone_api-1.4.28}/setup.cfg +0 -0
  29. {rclone_api-1.4.25 → rclone_api-1.4.28}/setup.py +0 -0
  30. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/assets/example.txt +0 -0
  31. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/cli.py +0 -0
  32. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/cmd/analyze.py +0 -0
  33. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/cmd/copy_large_s3_finish.py +0 -0
  34. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/cmd/list_files.py +0 -0
  35. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/cmd/save_to_db.py +0 -0
  36. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/completed_process.py +0 -0
  37. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/config.py +0 -0
  38. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/convert.py +0 -0
  39. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/db/__init__.py +0 -0
  40. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/db/db.py +0 -0
  41. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/db/models.py +0 -0
  42. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/deprecated.py +0 -0
  43. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/detail/copy_file_parts_resumable.py +0 -0
  44. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/detail/walk.py +0 -0
  45. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/diff.py +0 -0
  46. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/dir.py +0 -0
  47. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/dir_listing.py +0 -0
  48. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/exec.py +0 -0
  49. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/experimental/flags.py +0 -0
  50. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/experimental/flags_base.py +0 -0
  51. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/file.py +0 -0
  52. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/file_item.py +0 -0
  53. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/file_part.py +0 -0
  54. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/file_stream.py +0 -0
  55. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/filelist.py +0 -0
  56. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/group_files.py +0 -0
  57. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/http_server.py +0 -0
  58. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/log.py +0 -0
  59. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/mount.py +0 -0
  60. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/process.py +0 -0
  61. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/remote.py +0 -0
  62. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/rpath.py +0 -0
  63. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/api.py +0 -0
  64. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/basic_ops.py +0 -0
  65. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/chunk_task.py +0 -0
  66. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/create.py +0 -0
  67. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/multipart/file_info.py +0 -0
  68. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/multipart/finished_piece.py +0 -0
  69. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/multipart/info_json.py +0 -0
  70. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/multipart/merge_state.py +0 -0
  71. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/multipart/upload_info.py +0 -0
  72. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/multipart/upload_parts_inline.py +0 -0
  73. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/multipart/upload_parts_resumable.py +0 -0
  74. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/multipart/upload_parts_server_side_merge.py +0 -0
  75. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/multipart/upload_state.py +0 -0
  76. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/s3/types.py +0 -0
  77. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/scan_missing_folders.py +0 -0
  78. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/types.py +0 -0
  79. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api/util.py +0 -0
  80. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api.egg-info/SOURCES.txt +0 -0
  81. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api.egg-info/dependency_links.txt +0 -0
  82. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api.egg-info/entry_points.txt +0 -0
  83. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api.egg-info/requires.txt +0 -0
  84. {rclone_api-1.4.25 → rclone_api-1.4.28}/src/rclone_api.egg-info/top_level.txt +0 -0
  85. {rclone_api-1.4.25 → rclone_api-1.4.28}/test +0 -0
  86. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/archive/test_paramiko.py.disabled +0 -0
  87. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_cmd_list_files.py +0 -0
  88. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_copy.py +0 -0
  89. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_copy_bytes.py +0 -0
  90. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_copy_files.py +0 -0
  91. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_db.py +0 -0
  92. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_diff.py +0 -0
  93. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_file_item.py +0 -0
  94. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_group_files.py +0 -0
  95. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_is_synced.py +0 -0
  96. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_ls.py +0 -0
  97. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_ls_stream_files.py +0 -0
  98. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_mount.py +0 -0
  99. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_mount_s3.py +0 -0
  100. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_obscure.py +0 -0
  101. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_rclone_config.py +0 -0
  102. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_read_write_text.py +0 -0
  103. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_remote_control.py +0 -0
  104. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_remotes.py +0 -0
  105. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_s3.py +0 -0
  106. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_scan_missing_folders.py +0 -0
  107. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_serve_http.py +0 -0
  108. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_size_files.py +0 -0
  109. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_size_suffix.py +0 -0
  110. {rclone_api-1.4.25 → rclone_api-1.4.28}/tests/test_walk.py +0 -0
  111. {rclone_api-1.4.25 → rclone_api-1.4.28}/tox.ini +0 -0
  112. {rclone_api-1.4.25 → rclone_api-1.4.28}/upload_package.sh +0 -0
@@ -0,0 +1,556 @@
1
+ Metadata-Version: 2.2
2
+ Name: rclone_api
3
+ Version: 1.4.28
4
+ Summary: rclone api in python
5
+ Home-page: https://github.com/zackees/rclone-api
6
+ License: BSD 3-Clause License
7
+ Keywords: rclone,api,python,fast,sftp,s3,backblaze
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: pyright>=1.1.393
13
+ Requires-Dist: python-dotenv>=1.0.0
14
+ Requires-Dist: certifi>=2025.1.31
15
+ Requires-Dist: psutil
16
+ Requires-Dist: boto3<=1.35.99,>=1.20.1
17
+ Requires-Dist: sqlmodel>=0.0.23
18
+ Requires-Dist: psycopg2-binary>=2.9.10
19
+ Requires-Dist: httpx>=0.28.1
20
+ Dynamic: home-page
21
+
22
+ # rclone-api
23
+
24
+
25
+ ![perpetualmaniac_faster_400fd528-df15-4a04-8ad3-3cca786d7bca (2)](https://github.com/user-attachments/assets/65138e38-b115-447c-849a-4adbd27e4b67)
26
+
27
+
28
+ <!--
29
+ [![Linting](https://github.com/zackees/rclone-api/actions/workflows/lint.yml/badge.svg)](https://github.com/zackees/rclone-api/actions/workflows/lint.yml)
30
+ [![MacOS_Tests](https://github.com/zackees/rclone-api/actions/workflows/push_macos.yml/badge.svg)](https://github.com/zackees/rclone-api/actions/workflows/push_macos.yml)
31
+ [![Ubuntu_Tests](https://github.com/zackees/rclone-api/actions/workflows/push_ubuntu.yml/badge.svg)](https://github.com/zackees/rclone-api/actions/workflows/push_ubuntu.yml)
32
+ [![Win_Tests](https://github.com/zackees/rclone-api/actions/workflows/push_win.yml/badge.svg)](https://github.com/zackees/rclone-api/actions/workflows/push_win.yml)
33
+ -->
34
+
35
+
36
+ Got a lot of data to transfer quickly? This package is for you.
37
+
38
+ This library was built out of necessity to transfer large amounts of AI training data. Aggressive default means this api will transfer faster than rclone does in stock settings.
39
+
40
+ You must have [rclone](https://rclone.org/) in your path to use this library. You'd want this anyway because rclone is still under heavy developement.
41
+
42
+ # Install
43
+
44
+ `pip install rclone-api`
45
+
46
+ # Quick
47
+
48
+ In addition to providing easy python use for rclone, this package provides additional features:
49
+
50
+ * Resumable multi-part uploads when s3 is the destination.
51
+ * Diffing src/dst repos as a stream of `list[str]`.
52
+ * Dumping repo information to an sqlite/postgres/mysql database.
53
+ * Efficient copying of byte ranges of a file.
54
+ * Aggressive default settings for copying / syncing operations for extreme performance.
55
+ * Some platform specific fixes.
56
+
57
+
58
+ ## Example
59
+
60
+ ```python
61
+
62
+ from rclone_api import Rclone, DirListing, Config
63
+
64
+ RCLONE_CONFIG = Config("""
65
+ [dst]
66
+ type = s3
67
+ account = *********
68
+ key = ************
69
+ """)
70
+
71
+
72
+ def test_ls_glob_png(self) -> None:
73
+ rclone = Rclone(RCLONE_CONFIG)
74
+ path = f"dst:{BUCKET_NAME}/my_data"
75
+ listing: DirListing = rclone.ls(path, glob="*.png")
76
+ self.assertGreater(len(listing.files), 0)
77
+ for file in listing.files:
78
+ self.assertIsInstance(file, File)
79
+ # test that it ends with .png
80
+ self.assertTrue(file.name.endswith(".png"))
81
+ # there should be no directories with this glob
82
+ self.assertEqual(len(listing.dirs), 0)
83
+ ```
84
+
85
+ ## API
86
+
87
+ ```python
88
+
89
+ # from rclone_api import Rclone
90
+ # Rclone is the main api entry point.
91
+ class Rclone:
92
+ def __init__(
93
+ self, rclone_conf: Path | Config, rclone_exe: Path | None = None
94
+ ) -> None:
95
+ from rclone_api.rclone_impl import RcloneImpl
96
+
97
+ self.impl: RcloneImpl = RcloneImpl(rclone_conf, rclone_exe)
98
+
99
+ def webgui(self, other_args: list[str] | None = None) -> Process:
100
+ """Launch the Rclone web GUI."""
101
+ return self.impl.webgui(other_args=other_args)
102
+
103
+ def launch_server(
104
+ self,
105
+ addr: str,
106
+ user: str | None = None,
107
+ password: str | None = None,
108
+ other_args: list[str] | None = None,
109
+ ) -> Process:
110
+ """Launch the Rclone server so it can receive commands"""
111
+ return self.impl.launch_server(
112
+ addr=addr, user=user, password=password, other_args=other_args
113
+ )
114
+
115
+ def remote_control(
116
+ self,
117
+ addr: str,
118
+ user: str | None = None,
119
+ password: str | None = None,
120
+ capture: bool | None = None,
121
+ other_args: list[str] | None = None,
122
+ ) -> CompletedProcess:
123
+ return self.impl.remote_control(
124
+ addr=addr,
125
+ user=user,
126
+ password=password,
127
+ capture=capture,
128
+ other_args=other_args,
129
+ )
130
+
131
+ def obscure(self, password: str) -> str:
132
+ """Obscure a password for use in rclone config files."""
133
+ return self.impl.obscure(password=password)
134
+
135
+ def ls_stream(
136
+ self,
137
+ path: str,
138
+ max_depth: int = -1,
139
+ fast_list: bool = False,
140
+ ) -> FilesStream:
141
+ """
142
+ List files in the given path
143
+
144
+ Args:
145
+ src: Remote path to list
146
+ max_depth: Maximum recursion depth (-1 for unlimited)
147
+ fast_list: Use fast list (only use when getting THE entire data repository from the root/bucket, or it's small)
148
+ """
149
+ return self.impl.ls_stream(path=path, max_depth=max_depth, fast_list=fast_list)
150
+
151
+ def save_to_db(
152
+ self,
153
+ src: str,
154
+ db_url: str,
155
+ max_depth: int = -1,
156
+ fast_list: bool = False,
157
+ ) -> None:
158
+ """
159
+ Save files to a database (sqlite, mysql, postgres)
160
+
161
+ Args:
162
+ src: Remote path to list, this will be used to populate an entire table, so always use the root-most path.
163
+ db_url: Database URL, like sqlite:///data.db or mysql://user:pass@localhost/db or postgres://user:pass@localhost/db
164
+ max_depth: Maximum depth to traverse (-1 for unlimited)
165
+ fast_list: Use fast list (only use when getting THE entire data repository from the root/bucket)
166
+
167
+ """
168
+ return self.impl.save_to_db(
169
+ src=src, db_url=db_url, max_depth=max_depth, fast_list=fast_list
170
+ )
171
+
172
+ def ls(
173
+ self,
174
+ path: Dir | Remote | str | None = None,
175
+ max_depth: int | None = None,
176
+ glob: str | None = None,
177
+ order: Order = Order.NORMAL,
178
+ listing_option: ListingOption = ListingOption.ALL,
179
+ ) -> DirListing:
180
+ return self.impl.ls(
181
+ path=path,
182
+ max_depth=max_depth,
183
+ glob=glob,
184
+ order=order,
185
+ listing_option=listing_option,
186
+ )
187
+
188
+ def listremotes(self) -> list[Remote]:
189
+ return self.impl.listremotes()
190
+
191
+ def diff(
192
+ self,
193
+ src: str,
194
+ dst: str,
195
+ min_size: (
196
+ str | None
197
+ ) = None, # e. g. "1MB" - see rclone documentation: https://rclone.org/commands/rclone_check/
198
+ max_size: (
199
+ str | None
200
+ ) = None, # e. g. "1GB" - see rclone documentation: https://rclone.org/commands/rclone_check/
201
+ diff_option: DiffOption = DiffOption.COMBINED,
202
+ fast_list: bool = True,
203
+ size_only: bool | None = None,
204
+ checkers: int | None = None,
205
+ other_args: list[str] | None = None,
206
+ ) -> Generator[DiffItem, None, None]:
207
+ """Be extra careful with the src and dst values. If you are off by one
208
+ parent directory, you will get a huge amount of false diffs."""
209
+ return self.impl.diff(
210
+ src=src,
211
+ dst=dst,
212
+ min_size=min_size,
213
+ max_size=max_size,
214
+ diff_option=diff_option,
215
+ fast_list=fast_list,
216
+ size_only=size_only,
217
+ checkers=checkers,
218
+ other_args=other_args,
219
+ )
220
+
221
+ def walk(
222
+ self,
223
+ path: Dir | Remote | str,
224
+ max_depth: int = -1,
225
+ breadth_first: bool = True,
226
+ order: Order = Order.NORMAL,
227
+ ) -> Generator[DirListing, None, None]:
228
+ """Walk through the given path recursively.
229
+
230
+ Args:
231
+ path: Remote path or Remote object to walk through
232
+ max_depth: Maximum depth to traverse (-1 for unlimited)
233
+
234
+ Yields:
235
+ DirListing: Directory listing for each directory encountered
236
+ """
237
+ return self.impl.walk(
238
+ path=path, max_depth=max_depth, breadth_first=breadth_first, order=order
239
+ )
240
+
241
+ def scan_missing_folders(
242
+ self,
243
+ src: Dir | Remote | str,
244
+ dst: Dir | Remote | str,
245
+ max_depth: int = -1,
246
+ order: Order = Order.NORMAL,
247
+ ) -> Generator[Dir, None, None]:
248
+ """Walk through the given path recursively.
249
+
250
+ WORK IN PROGRESS!!
251
+
252
+ Args:
253
+ src: Source directory or Remote to walk through
254
+ dst: Destination directory or Remote to walk through
255
+ max_depth: Maximum depth to traverse (-1 for unlimited)
256
+
257
+ Yields:
258
+ DirListing: Directory listing for each directory encountered
259
+ """
260
+ return self.impl.scan_missing_folders(
261
+ src=src, dst=dst, max_depth=max_depth, order=order
262
+ )
263
+
264
+ def cleanup(
265
+ self, path: str, other_args: list[str] | None = None
266
+ ) -> CompletedProcess:
267
+ """Cleanup any resources used by the Rclone instance."""
268
+ return self.impl.cleanup(path=path, other_args=other_args)
269
+
270
+ def copy_to(
271
+ self,
272
+ src: File | str,
273
+ dst: File | str,
274
+ check: bool | None = None,
275
+ verbose: bool | None = None,
276
+ other_args: list[str] | None = None,
277
+ ) -> CompletedProcess:
278
+ """Copy one file from source to destination.
279
+
280
+ Warning - slow.
281
+
282
+ """
283
+ return self.impl.copy_to(
284
+ src=src, dst=dst, check=check, verbose=verbose, other_args=other_args
285
+ )
286
+
287
+ def copy_files(
288
+ self,
289
+ src: str,
290
+ dst: str,
291
+ files: list[str] | Path,
292
+ check: bool | None = None,
293
+ max_backlog: int | None = None,
294
+ verbose: bool | None = None,
295
+ checkers: int | None = None,
296
+ transfers: int | None = None,
297
+ low_level_retries: int | None = None,
298
+ retries: int | None = None,
299
+ retries_sleep: str | None = None,
300
+ metadata: bool | None = None,
301
+ timeout: str | None = None,
302
+ max_partition_workers: int | None = None,
303
+ multi_thread_streams: int | None = None,
304
+ other_args: list[str] | None = None,
305
+ ) -> list[CompletedProcess]:
306
+ """Copy multiple files from source to destination.
307
+
308
+ Args:
309
+ payload: Dictionary of source and destination file paths
310
+ """
311
+ return self.impl.copy_files(
312
+ src=src,
313
+ dst=dst,
314
+ files=files,
315
+ check=check,
316
+ max_backlog=max_backlog,
317
+ verbose=verbose,
318
+ checkers=checkers,
319
+ transfers=transfers,
320
+ low_level_retries=low_level_retries,
321
+ retries=retries,
322
+ retries_sleep=retries_sleep,
323
+ metadata=metadata,
324
+ timeout=timeout,
325
+ max_partition_workers=max_partition_workers,
326
+ multi_thread_streams=multi_thread_streams,
327
+ other_args=other_args,
328
+ )
329
+
330
+ def copy(
331
+ self,
332
+ src: Dir | str,
333
+ dst: Dir | str,
334
+ check: bool | None = None,
335
+ transfers: int | None = None,
336
+ checkers: int | None = None,
337
+ multi_thread_streams: int | None = None,
338
+ low_level_retries: int | None = None,
339
+ retries: int | None = None,
340
+ other_args: list[str] | None = None,
341
+ ) -> CompletedProcess:
342
+ """Copy files from source to destination.
343
+
344
+ Args:
345
+ src: Source directory
346
+ dst: Destination directory
347
+ """
348
+ return self.impl.copy(
349
+ src=src,
350
+ dst=dst,
351
+ check=check,
352
+ transfers=transfers,
353
+ checkers=checkers,
354
+ multi_thread_streams=multi_thread_streams,
355
+ low_level_retries=low_level_retries,
356
+ retries=retries,
357
+ other_args=other_args,
358
+ )
359
+
360
+ def purge(self, path: Dir | str) -> CompletedProcess:
361
+ """Purge a directory"""
362
+ return self.impl.purge(path=path)
363
+
364
+ def delete_files(
365
+ self,
366
+ files: str | File | list[str] | list[File],
367
+ check: bool | None = None,
368
+ rmdirs=False,
369
+ verbose: bool | None = None,
370
+ max_partition_workers: int | None = None,
371
+ other_args: list[str] | None = None,
372
+ ) -> CompletedProcess:
373
+ """Delete a directory"""
374
+ return self.impl.delete_files(
375
+ files=files,
376
+ check=check,
377
+ rmdirs=rmdirs,
378
+ verbose=verbose,
379
+ max_partition_workers=max_partition_workers,
380
+ other_args=other_args,
381
+ )
382
+
383
+ def exists(self, path: Dir | Remote | str | File) -> bool:
384
+ """Check if a file or directory exists."""
385
+ return self.impl.exists(path=path)
386
+
387
+ def is_synced(self, src: str | Dir, dst: str | Dir) -> bool:
388
+ """Check if two directories are in sync."""
389
+ return self.impl.is_synced(src=src, dst=dst)
390
+
391
+ def modtime(self, src: str) -> str | Exception:
392
+ """Get the modification time of a file or directory."""
393
+ return self.impl.modtime(src=src)
394
+
395
+ def modtime_dt(self, src: str) -> datetime | Exception:
396
+ """Get the modification time of a file or directory."""
397
+ return self.impl.modtime_dt(src=src)
398
+
399
+ def write_text(
400
+ self,
401
+ text: str,
402
+ dst: str,
403
+ ) -> Exception | None:
404
+ """Write text to a file."""
405
+ return self.impl.write_text(text=text, dst=dst)
406
+
407
+ def write_bytes(
408
+ self,
409
+ data: bytes,
410
+ dst: str,
411
+ ) -> Exception | None:
412
+ """Write bytes to a file."""
413
+ return self.impl.write_bytes(data=data, dst=dst)
414
+
415
+ def read_bytes(self, src: str) -> bytes | Exception:
416
+ """Read bytes from a file."""
417
+ return self.impl.read_bytes(src=src)
418
+
419
+ def read_text(self, src: str) -> str | Exception:
420
+ """Read text from a file."""
421
+ return self.impl.read_text(src=src)
422
+
423
+ def copy_bytes(
424
+ self,
425
+ src: str,
426
+ offset: int | SizeSuffix,
427
+ length: int | SizeSuffix,
428
+ outfile: Path,
429
+ other_args: list[str] | None = None,
430
+ ) -> Exception | None:
431
+ """Copy a slice of bytes from the src file to dst."""
432
+ return self.impl.copy_bytes(
433
+ src=src,
434
+ offset=offset,
435
+ length=length,
436
+ outfile=outfile,
437
+ other_args=other_args,
438
+ )
439
+
440
+ def copy_dir(
441
+ self, src: str | Dir, dst: str | Dir, args: list[str] | None = None
442
+ ) -> CompletedProcess:
443
+ """Copy a directory from source to destination."""
444
+ # convert src to str, also dst
445
+ return self.impl.copy_dir(src=src, dst=dst, args=args)
446
+
447
+ def copy_remote(
448
+ self, src: Remote, dst: Remote, args: list[str] | None = None
449
+ ) -> CompletedProcess:
450
+ """Copy a remote to another remote."""
451
+ return self.impl.copy_remote(src=src, dst=dst, args=args)
452
+
453
+ def copy_file_s3_resumable(
454
+ self,
455
+ src: str, # src:/Bucket/path/myfile.large.zst
456
+ dst_dir: str, # dst:/Bucket/path/myfile.large.zst-parts/part.{part_number:05d}.start-end
457
+ part_infos: list[PartInfo] | None = None,
458
+ upload_threads: int = 8, # Number of reader and writer threads to use
459
+ merge_threads: int = 4, # Number of threads to use for merging the parts
460
+ ) -> Exception | None:
461
+ """Copy a file in parts."""
462
+ return self.impl.copy_file_s3_resumable(
463
+ src=src,
464
+ dst_dir=dst_dir,
465
+ part_infos=part_infos,
466
+ upload_threads=upload_threads,
467
+ merge_threads=merge_threads,
468
+ )
469
+
470
+ def mount(
471
+ self,
472
+ src: Remote | Dir | str,
473
+ outdir: Path,
474
+ allow_writes: bool | None = False,
475
+ use_links: bool | None = None,
476
+ vfs_cache_mode: str | None = None,
477
+ verbose: bool | None = None,
478
+ cache_dir: Path | None = None,
479
+ cache_dir_delete_on_exit: bool | None = None,
480
+ log: Path | None = None,
481
+ other_args: list[str] | None = None,
482
+ ) -> Mount:
483
+ """Mount a remote or directory to a local path.
484
+
485
+ Args:
486
+ src: Remote or directory to mount
487
+ outdir: Local path to mount to
488
+
489
+ Returns:
490
+ CompletedProcess from the mount command execution
491
+
492
+ Raises:
493
+ subprocess.CalledProcessError: If the mount operation fails
494
+ """
495
+ return self.impl.mount(
496
+ src=src,
497
+ outdir=outdir,
498
+ allow_writes=allow_writes,
499
+ use_links=use_links,
500
+ vfs_cache_mode=vfs_cache_mode,
501
+ verbose=verbose,
502
+ cache_dir=cache_dir,
503
+ cache_dir_delete_on_exit=cache_dir_delete_on_exit,
504
+ log=log,
505
+ other_args=other_args,
506
+ )
507
+
508
+ def serve_http(
509
+ self,
510
+ src: str,
511
+ addr: str = "localhost:8080",
512
+ other_args: list[str] | None = None,
513
+ ) -> HttpServer:
514
+ """Serve a remote or directory via HTTP. The returned HttpServer has a client which can be used to
515
+ fetch files or parts.
516
+
517
+ Args:
518
+ src: Remote or directory to serve
519
+ addr: Network address and port to serve on (default: localhost:8080)
520
+ """
521
+ return self.impl.serve_http(src=src, addr=addr, other_args=other_args)
522
+
523
+ def size_files(
524
+ self,
525
+ src: str,
526
+ files: list[str],
527
+ fast_list: bool = False, # Recommend that this is False
528
+ other_args: list[str] | None = None,
529
+ check: bool | None = False,
530
+ verbose: bool | None = None,
531
+ ) -> SizeResult | Exception:
532
+ """Get the size of a list of files. Example of files items: "remote:bucket/to/file"."""
533
+ return self.impl.size_files(
534
+ src=src,
535
+ files=files,
536
+ fast_list=fast_list,
537
+ other_args=other_args,
538
+ check=check,
539
+ verbose=verbose,
540
+ )
541
+
542
+ def size_file(self, src: str) -> SizeSuffix | Exception:
543
+ """Get the size of a file."""
544
+ return self.impl.size_file(src=src)
545
+ ```
546
+
547
+
548
+ To develop software, run `. ./activate`
549
+
550
+ # Windows
551
+
552
+ This environment requires you to use `git-bash`.
553
+
554
+ # Linting
555
+
556
+ Run `./lint`