rclone-api 1.3.27__py2.py3-none-any.whl → 1.4.1__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/__init__.py +491 -4
- rclone_api/cmd/copy_large_s3.py +17 -10
- rclone_api/db/db.py +3 -3
- rclone_api/detail/copy_file_parts.py +382 -0
- rclone_api/dir.py +1 -1
- rclone_api/dir_listing.py +1 -1
- rclone_api/file.py +8 -0
- rclone_api/file_part.py +198 -0
- rclone_api/file_stream.py +52 -0
- rclone_api/http_server.py +15 -21
- rclone_api/{rclone.py → rclone_impl.py} +153 -321
- rclone_api/remote.py +3 -3
- rclone_api/rpath.py +11 -4
- rclone_api/s3/chunk_task.py +3 -19
- rclone_api/s3/multipart/file_info.py +7 -0
- rclone_api/s3/multipart/finished_piece.py +38 -0
- rclone_api/s3/multipart/upload_info.py +62 -0
- rclone_api/s3/{chunk_types.py → multipart/upload_state.py} +3 -99
- rclone_api/s3/s3_multipart_uploader.py +138 -0
- rclone_api/s3/types.py +1 -1
- rclone_api/s3/upload_file_multipart.py +14 -14
- rclone_api/scan_missing_folders.py +1 -1
- rclone_api/types.py +136 -165
- rclone_api/util.py +22 -2
- {rclone_api-1.3.27.dist-info → rclone_api-1.4.1.dist-info}/METADATA +1 -1
- rclone_api-1.4.1.dist-info/RECORD +55 -0
- rclone_api/mount_read_chunker.py +0 -130
- rclone_api/profile/mount_copy_bytes.py +0 -311
- rclone_api-1.3.27.dist-info/RECORD +0 -50
- /rclone_api/{walk.py → detail/walk.py} +0 -0
- {rclone_api-1.3.27.dist-info → rclone_api-1.4.1.dist-info}/LICENSE +0 -0
- {rclone_api-1.3.27.dist-info → rclone_api-1.4.1.dist-info}/WHEEL +0 -0
- {rclone_api-1.3.27.dist-info → rclone_api-1.4.1.dist-info}/entry_points.txt +0 -0
- {rclone_api-1.3.27.dist-info → rclone_api-1.4.1.dist-info}/top_level.txt +0 -0
@@ -1,311 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Unit test file.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import argparse
|
6
|
-
import os
|
7
|
-
import shutil
|
8
|
-
import time
|
9
|
-
from concurrent.futures import Future
|
10
|
-
from dataclasses import dataclass
|
11
|
-
from pathlib import Path
|
12
|
-
|
13
|
-
import psutil
|
14
|
-
from dotenv import load_dotenv
|
15
|
-
|
16
|
-
from rclone_api import Config, Rclone, SizeSuffix
|
17
|
-
from rclone_api.mount_read_chunker import MultiMountFileChunker
|
18
|
-
from rclone_api.types import FilePart
|
19
|
-
|
20
|
-
os.environ["RCLONE_API_VERBOSE"] = "1"
|
21
|
-
|
22
|
-
|
23
|
-
@dataclass
|
24
|
-
class Args:
|
25
|
-
direct_io: bool
|
26
|
-
num: int
|
27
|
-
size: SizeSuffix | None
|
28
|
-
|
29
|
-
|
30
|
-
@dataclass
|
31
|
-
class Credentials:
|
32
|
-
BUCKET_KEY_SECRET: str
|
33
|
-
BUCKET_KEY_PUBLIC: str
|
34
|
-
BUCKET_NAME: str
|
35
|
-
SRC_SFTP_HOST: str
|
36
|
-
SRC_SFTP_USER: str
|
37
|
-
SRC_SFTP_PORT: str
|
38
|
-
SRC_SFTP_PASS: str
|
39
|
-
BUCKET_URL: str
|
40
|
-
|
41
|
-
|
42
|
-
def _generate_rclone_config() -> tuple[Config, Credentials]:
|
43
|
-
|
44
|
-
cwd = Path.cwd()
|
45
|
-
env_path = cwd / ".env"
|
46
|
-
assert (
|
47
|
-
env_path.exists()
|
48
|
-
), "this test requires that the secret .env file exists with the credentials"
|
49
|
-
load_dotenv(env_path, verbose=True)
|
50
|
-
print(f"Current working directory: {cwd}")
|
51
|
-
|
52
|
-
# assert that .env exists for this test
|
53
|
-
assert os.path.exists(
|
54
|
-
".env"
|
55
|
-
), "this test requires that the secret .env file exists with the credentials"
|
56
|
-
|
57
|
-
# BUCKET_NAME = os.getenv("BUCKET_NAME", "TorrentBooks") # Default if not in .env
|
58
|
-
|
59
|
-
# Load additional environment variables
|
60
|
-
BUCKET_KEY_SECRET = os.getenv("BUCKET_KEY_SECRET")
|
61
|
-
BUCKET_KEY_PUBLIC = os.getenv("BUCKET_KEY_PUBLIC")
|
62
|
-
BUCKET_NAME = os.getenv("BUCKET_NAME")
|
63
|
-
SRC_SFTP_HOST = os.getenv("SRC_SFTP_HOST")
|
64
|
-
SRC_SFTP_USER = os.getenv("SRC_SFTP_USER")
|
65
|
-
SRC_SFTP_PORT = os.getenv("SRC_SFTP_PORT")
|
66
|
-
SRC_SFTP_PASS = os.getenv("SRC_SFTP_PASS")
|
67
|
-
# BUCKET_URL = os.getenv("BUCKET_URL")
|
68
|
-
BUCKET_URL = "sfo3.digitaloceanspaces.com"
|
69
|
-
|
70
|
-
config_text = f"""
|
71
|
-
[dst]
|
72
|
-
type = s3
|
73
|
-
provider = DigitalOcean
|
74
|
-
access_key_id = {BUCKET_KEY_PUBLIC}
|
75
|
-
secret_access_key = {BUCKET_KEY_SECRET}
|
76
|
-
endpoint = {BUCKET_URL}
|
77
|
-
bucket = {BUCKET_NAME}
|
78
|
-
|
79
|
-
[src]
|
80
|
-
type = sftp
|
81
|
-
host = {SRC_SFTP_HOST}
|
82
|
-
user = {SRC_SFTP_USER}
|
83
|
-
port = {SRC_SFTP_PORT}
|
84
|
-
pass = {SRC_SFTP_PASS}
|
85
|
-
|
86
|
-
"""
|
87
|
-
# print("Config text:")
|
88
|
-
# print(config_text)
|
89
|
-
# _CONFIG_PATH.write_text(config_text, encoding="utf-8")
|
90
|
-
# print(f"Config file written to: {_CONFIG_PATH}")
|
91
|
-
|
92
|
-
creds = Credentials(
|
93
|
-
BUCKET_KEY_SECRET=str(BUCKET_KEY_SECRET),
|
94
|
-
BUCKET_KEY_PUBLIC=str(BUCKET_KEY_PUBLIC),
|
95
|
-
BUCKET_NAME=str(BUCKET_NAME),
|
96
|
-
SRC_SFTP_HOST=str(SRC_SFTP_HOST),
|
97
|
-
SRC_SFTP_USER=str(SRC_SFTP_USER),
|
98
|
-
SRC_SFTP_PORT=str(SRC_SFTP_PORT),
|
99
|
-
SRC_SFTP_PASS=str(SRC_SFTP_PASS),
|
100
|
-
BUCKET_URL=str(BUCKET_URL),
|
101
|
-
)
|
102
|
-
|
103
|
-
return Config(config_text), creds
|
104
|
-
|
105
|
-
|
106
|
-
def _run_profile(
|
107
|
-
rclone: Rclone,
|
108
|
-
src_file: str,
|
109
|
-
transfers: int,
|
110
|
-
offset: SizeSuffix,
|
111
|
-
size: SizeSuffix,
|
112
|
-
log_dir: Path,
|
113
|
-
num: int,
|
114
|
-
direct_io: bool,
|
115
|
-
) -> None:
|
116
|
-
|
117
|
-
mount_log = log_dir / f"mount_{SizeSuffix(size)}_threads_{transfers}.log"
|
118
|
-
print("\n\n")
|
119
|
-
print("#" * 80)
|
120
|
-
print(f"# Started test download of {SizeSuffix(size)} with {transfers} transfers")
|
121
|
-
print("#" * 80)
|
122
|
-
|
123
|
-
chunk_size = size
|
124
|
-
|
125
|
-
filechunker: MultiMountFileChunker = rclone.get_multi_mount_file_chunker(
|
126
|
-
src=src_file,
|
127
|
-
chunk_size=chunk_size,
|
128
|
-
threads=transfers,
|
129
|
-
direct_io=direct_io,
|
130
|
-
mount_log=mount_log,
|
131
|
-
)
|
132
|
-
bytes_count = 0
|
133
|
-
|
134
|
-
futures: list[Future[FilePart]] = []
|
135
|
-
for i in range(num):
|
136
|
-
offset = SizeSuffix(i * chunk_size.as_int()) + offset
|
137
|
-
future = filechunker.fetch(offset.as_int(), size.as_int(), "TEST OBJECT")
|
138
|
-
futures.append(future)
|
139
|
-
|
140
|
-
# dry run to warm up the mounts, then read a different byte range.
|
141
|
-
for future in futures:
|
142
|
-
filepart_or_err = future.result()
|
143
|
-
if isinstance(filepart_or_err, Exception):
|
144
|
-
assert False, f"Error: {filepart_or_err}"
|
145
|
-
filepart_or_err.dispose()
|
146
|
-
futures.clear()
|
147
|
-
|
148
|
-
start = time.time()
|
149
|
-
net_io_start = psutil.net_io_counters()
|
150
|
-
|
151
|
-
offset = SizeSuffix("1G")
|
152
|
-
|
153
|
-
for i in range(num):
|
154
|
-
offset = SizeSuffix(i * chunk_size.as_int()) + offset
|
155
|
-
future = filechunker.fetch(offset.as_int(), size.as_int(), "TEST OBJECT")
|
156
|
-
futures.append(future)
|
157
|
-
|
158
|
-
for future in futures:
|
159
|
-
bytes_or_err = future.result()
|
160
|
-
if isinstance(bytes_or_err, Exception):
|
161
|
-
assert False, f"Error: {bytes_or_err}"
|
162
|
-
bytes_count += bytes_or_err.n_bytes()
|
163
|
-
|
164
|
-
diff = (time.time() - start) / num
|
165
|
-
net_io_end = psutil.net_io_counters()
|
166
|
-
# self.assertEqual(len(bytes_or_err), size)
|
167
|
-
# assert (
|
168
|
-
# bytes_count == SizeSuffix(size * num).as_int()
|
169
|
-
# ), f"Length: {SizeSuffix(bytes_count)} != {SizeSuffix(size* num)}"
|
170
|
-
|
171
|
-
if bytes_count != SizeSuffix(size * num).as_int():
|
172
|
-
print("\n######################## ERROR ########################")
|
173
|
-
print(f"Error: Length: {SizeSuffix(bytes_count)} != {SizeSuffix(size* num)}")
|
174
|
-
print(f" Bytes count: {bytes_count}")
|
175
|
-
print(f" Size: {SizeSuffix(size * num)}")
|
176
|
-
print(f" num: {num}")
|
177
|
-
print("########################################################\n")
|
178
|
-
|
179
|
-
# print io stats
|
180
|
-
bytes_sent = (net_io_end.bytes_sent - net_io_start.bytes_sent) // num
|
181
|
-
bytes_recv = (net_io_end.bytes_recv - net_io_start.bytes_recv) // num
|
182
|
-
packets_sent = (net_io_end.packets_sent - net_io_start.packets_sent) // num
|
183
|
-
efficiency = size.as_int() / (bytes_recv)
|
184
|
-
efficiency_100 = efficiency * 100
|
185
|
-
efficiency_str = f"{efficiency_100:.2f}"
|
186
|
-
|
187
|
-
bytes_send_suffix = SizeSuffix(bytes_sent)
|
188
|
-
bytes_recv_suffix = SizeSuffix(bytes_recv)
|
189
|
-
range_size = SizeSuffix(size)
|
190
|
-
|
191
|
-
print(f"\nFinished downloading {range_size} with {transfers} transfers")
|
192
|
-
print("Net IO stats:")
|
193
|
-
print(f"Bytes sent: {bytes_send_suffix}")
|
194
|
-
print(f"Bytes received: {bytes_recv_suffix}")
|
195
|
-
print(f"Packets sent: {packets_sent}")
|
196
|
-
print(f"Efficiency: {efficiency_str}%")
|
197
|
-
print(f"Time: {diff:.1f} seconds")
|
198
|
-
|
199
|
-
|
200
|
-
def test_profile_copy_bytes(
|
201
|
-
args: Args,
|
202
|
-
rclone: Rclone,
|
203
|
-
offset: SizeSuffix,
|
204
|
-
transfer_list: list[int] | None,
|
205
|
-
mount_root_path: Path,
|
206
|
-
size: SizeSuffix | None,
|
207
|
-
num: int,
|
208
|
-
) -> None:
|
209
|
-
|
210
|
-
if size:
|
211
|
-
sizes = [size.as_int()]
|
212
|
-
else:
|
213
|
-
sizes = [
|
214
|
-
1024 * 1024 * 1,
|
215
|
-
# 1024 * 1024 * 2,
|
216
|
-
1024 * 1024 * 4,
|
217
|
-
# 1024 * 1024 * 8,
|
218
|
-
1024 * 1024 * 16,
|
219
|
-
# 1024 * 1024 * 32,
|
220
|
-
1024 * 1024 * 64,
|
221
|
-
# 1024 * 1024 * 128,
|
222
|
-
1024 * 1024 * 256,
|
223
|
-
]
|
224
|
-
# transfer_list = [1, 2, 4, 8, 16]
|
225
|
-
transfer_list = transfer_list or [1, 2, 4]
|
226
|
-
|
227
|
-
# src_file = "dst:rclone-api-unit-test/zachs_video/internaly_ai_alignment.mp4"
|
228
|
-
# sftp mount
|
229
|
-
src_file = "src:aa_misc_data/aa_misc_data/world_lending_library_2024_11.tar.zst"
|
230
|
-
|
231
|
-
for sz in sizes:
|
232
|
-
for transfers in transfer_list:
|
233
|
-
_run_profile(
|
234
|
-
rclone=rclone,
|
235
|
-
src_file=src_file,
|
236
|
-
transfers=transfers,
|
237
|
-
offset=offset,
|
238
|
-
size=SizeSuffix(sz),
|
239
|
-
direct_io=args.direct_io,
|
240
|
-
log_dir=mount_root_path,
|
241
|
-
num=num,
|
242
|
-
)
|
243
|
-
print("done")
|
244
|
-
|
245
|
-
|
246
|
-
def _parse_args() -> Args:
|
247
|
-
parser = argparse.ArgumentParser(description="Profile copy_bytes")
|
248
|
-
parser.add_argument("--direct-io", help="Use direct IO", action="store_true")
|
249
|
-
parser.add_argument("-n", "--num", help="Number of workers", type=int, default=1)
|
250
|
-
parser.add_argument(
|
251
|
-
"--size", help="Size of the file to download", type=SizeSuffix, default=None
|
252
|
-
)
|
253
|
-
args = parser.parse_args()
|
254
|
-
return Args(direct_io=args.direct_io, num=args.num, size=args.size)
|
255
|
-
|
256
|
-
|
257
|
-
_SHOW_CREDS = False
|
258
|
-
|
259
|
-
|
260
|
-
def main() -> None:
|
261
|
-
"""Main entry point."""
|
262
|
-
print("Running test_profile_copy_bytes")
|
263
|
-
config, creds = _generate_rclone_config()
|
264
|
-
if _SHOW_CREDS:
|
265
|
-
print("Config:")
|
266
|
-
print(config)
|
267
|
-
print("Credentials:")
|
268
|
-
print(creds)
|
269
|
-
rclone = Rclone(config)
|
270
|
-
|
271
|
-
mount_root_path = Path("rclone_logs") / "mount"
|
272
|
-
if mount_root_path.exists():
|
273
|
-
shutil.rmtree(mount_root_path)
|
274
|
-
|
275
|
-
args = _parse_args()
|
276
|
-
transfer_list = None
|
277
|
-
# parallel_workers = args.num
|
278
|
-
|
279
|
-
def task(
|
280
|
-
offset: SizeSuffix,
|
281
|
-
args=args,
|
282
|
-
rclone=rclone,
|
283
|
-
transfer_list=transfer_list,
|
284
|
-
mount_root_path=mount_root_path,
|
285
|
-
):
|
286
|
-
return test_profile_copy_bytes(
|
287
|
-
args=args,
|
288
|
-
rclone=rclone,
|
289
|
-
offset=offset,
|
290
|
-
mount_root_path=mount_root_path,
|
291
|
-
transfer_list=transfer_list,
|
292
|
-
size=args.size,
|
293
|
-
num=args.num,
|
294
|
-
)
|
295
|
-
|
296
|
-
task(offset=SizeSuffix(0))
|
297
|
-
|
298
|
-
# with ThreadPoolExecutor(max_workers=parallel_workers) as _:
|
299
|
-
# tasks: list[Future] = []
|
300
|
-
# for i in range(parallel_workers):
|
301
|
-
# offset = SizeSuffix(i * 1024 * 1024 * 256)
|
302
|
-
# future = ThreadPoolExecutor().submit(lambda: task(offset=offset))
|
303
|
-
# tasks.append(future)
|
304
|
-
|
305
|
-
|
306
|
-
if __name__ == "__main__":
|
307
|
-
import sys
|
308
|
-
|
309
|
-
sys.argv.append("--size")
|
310
|
-
sys.argv.append("16MB")
|
311
|
-
main()
|
@@ -1,50 +0,0 @@
|
|
1
|
-
rclone_api/__init__.py,sha256=gOQJgOs0_oaV_pOwlY00LXRYAHk1_MDwN59od1VpoC0,1334
|
2
|
-
rclone_api/cli.py,sha256=dibfAZIh0kXWsBbfp3onKLjyZXo54mTzDjUdzJlDlWo,231
|
3
|
-
rclone_api/completed_process.py,sha256=_IZ8IWK7DM1_tsbDEkH6wPZ-bbcrgf7A7smls854pmg,1775
|
4
|
-
rclone_api/config.py,sha256=f6jEAxVorGFr31oHfcsu5AJTtOJj2wR5tTSsbGGZuIw,2558
|
5
|
-
rclone_api/convert.py,sha256=Mx9Qo7zhkOedJd8LdhPvNGHp8znJzOk4f_2KWnoGc78,1012
|
6
|
-
rclone_api/deprecated.py,sha256=qWKpnZdYcBK7YQZKuVoWWXDwi-uqiAtbjgPcci_efow,590
|
7
|
-
rclone_api/diff.py,sha256=tMoJMAGmLSE6Q_7QhPf6PnCzb840djxMZtDmhc2GlGQ,5227
|
8
|
-
rclone_api/dir.py,sha256=i4h7LX5hB_WmVixxDRWL_l1nifvscrdWct_8Wx7wHZc,3540
|
9
|
-
rclone_api/dir_listing.py,sha256=GoziW8Sne6FY90MLNcb2aO3aaa3jphB6H8ExYrV0Ryo,1882
|
10
|
-
rclone_api/exec.py,sha256=Bq0gkyZ10mEY0FRyzNZgdN4FaWP9vpeCk1kjpg-gN_8,1083
|
11
|
-
rclone_api/file.py,sha256=cz-7_nJArkVdJ9z2QaC_XZYpihXe3IPBC90Z5_3g2aw,5419
|
12
|
-
rclone_api/file_item.py,sha256=cH-AQYsxedhNPp4c8NHY1ad4Z7St4yf_VGbmiGD59no,1770
|
13
|
-
rclone_api/filelist.py,sha256=xbiusvNgaB_b_kQOZoHMJJxn6TWGtPrWd2J042BI28o,767
|
14
|
-
rclone_api/group_files.py,sha256=H92xPW9lQnbNw5KbtZCl00bD6iRh9yRbCuxku4j_3dg,8036
|
15
|
-
rclone_api/http_server.py,sha256=SmeUDDKaMpJGDqRNkHoImHTRNkvHEtGFzu_8jYfoeZU,8113
|
16
|
-
rclone_api/log.py,sha256=VZHM7pNSXip2ZLBKMP7M1u-rp_F7zoafFDuR8CPUoKI,1271
|
17
|
-
rclone_api/mount.py,sha256=TE_VIBMW7J1UkF_6HRCt8oi_jGdMov4S51bm2OgxFAM,10045
|
18
|
-
rclone_api/mount_read_chunker.py,sha256=7jaF1Rsjr-kXIZW--Ol1QuG7WArBgdIcpQ0AJMYn7bI,4764
|
19
|
-
rclone_api/process.py,sha256=BGXJTZVT__jeaDyjN8_kRycliOhkBErMPdHO1hKRvJE,5271
|
20
|
-
rclone_api/rclone.py,sha256=yRhQoCBJI-tfhxySR17a-vSEhWw5cMbk8_WbYs5WqRc,54117
|
21
|
-
rclone_api/remote.py,sha256=jq3dPbAGvYZFW5cTviqxT2w6_jG2LLfS1RIcYSmMsQQ,503
|
22
|
-
rclone_api/rpath.py,sha256=8ZA_1wxWtskwcy0I8V2VbjKDmzPkiWd8Q2JQSvh-sYE,2586
|
23
|
-
rclone_api/scan_missing_folders.py,sha256=Kulca2Q6WZodt00ATFHkmqqInuoPvBkhTcS9703y6po,4740
|
24
|
-
rclone_api/types.py,sha256=ous70ea5oEs0gz0KLCWfimVyF0_fgrXRA8e0_HLk8nk,12301
|
25
|
-
rclone_api/util.py,sha256=F9Q3zbWRsgPF4NG6OWB63cZ7GVq82lsraP47gmmDohU,5416
|
26
|
-
rclone_api/walk.py,sha256=-54NVE8EJcCstwDoaC_UtHm73R2HrZwVwQmsnv55xNU,3369
|
27
|
-
rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
|
28
|
-
rclone_api/cmd/analyze.py,sha256=RHbvk1G5ZUc3qLqlm1AZEyQzd_W_ZjcbCNDvW4YpTKQ,1252
|
29
|
-
rclone_api/cmd/copy_large_s3.py,sha256=etOMCyN2FECev7sF_Z3Ftp-2UHRE09Yhfg6AgflDHek,3573
|
30
|
-
rclone_api/cmd/list_files.py,sha256=x8FHODEilwKqwdiU1jdkeJbLwOqUkUQuDWPo2u_zpf0,741
|
31
|
-
rclone_api/cmd/save_to_db.py,sha256=ylvnhg_yzexM-m6Zr7XDiswvoDVSl56ELuFAdb9gqBY,1957
|
32
|
-
rclone_api/db/__init__.py,sha256=OSRUdnSWUlDTOHmjdjVmxYTUNpTbtaJ5Ll9sl-PfZg0,40
|
33
|
-
rclone_api/db/db.py,sha256=ZpYfeCUe8MKg_fdJucRSe6-fwGY_rWqUn7WkHCNFH_4,10074
|
34
|
-
rclone_api/db/models.py,sha256=v7qaXUehvsDvU51uk69JI23fSIs9JFGcOa-Tv1c_wVs,1600
|
35
|
-
rclone_api/experimental/flags.py,sha256=qCVD--fSTmzlk9hloRLr0q9elzAOFzPsvVpKM3aB1Mk,2739
|
36
|
-
rclone_api/experimental/flags_base.py,sha256=ajU_czkTcAxXYU-SlmiCfHY7aCQGHvpCLqJ-Z8uZLk0,2102
|
37
|
-
rclone_api/profile/mount_copy_bytes.py,sha256=M1vZn-Mrga14Ik7MHGZHbnwYli41Ep6Tyll7hQc7Wmo,9071
|
38
|
-
rclone_api/s3/api.py,sha256=PafsIEyWDpLWAXsZAjFm9CY14vJpsDr9lOsn0kGRLZ0,4009
|
39
|
-
rclone_api/s3/basic_ops.py,sha256=hK3366xhVEzEcjz9Gk_8lFx6MRceAk72cax6mUrr6ko,2104
|
40
|
-
rclone_api/s3/chunk_task.py,sha256=AanVCygDoUjmMOUdEIYl-hEpPEGSJTIU_MSFGQ0tI0Q,7421
|
41
|
-
rclone_api/s3/chunk_types.py,sha256=oSWv8No9V3BeM7IcGnowyR2a7YrszdAXzEJlxaeZcp0,8852
|
42
|
-
rclone_api/s3/create.py,sha256=wgfkapv_j904CfKuWyiBIWJVxfAx_ftemFSUV14aT68,3149
|
43
|
-
rclone_api/s3/types.py,sha256=Elmh__gvZJyJyElYwMmvYZIBIunDJiTRAbEg21GmsRU,1604
|
44
|
-
rclone_api/s3/upload_file_multipart.py,sha256=bxAB_SFkyydBBzC_cAv7gShe93nBkFVS-TXwM2Xttfk,12425
|
45
|
-
rclone_api-1.3.27.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
46
|
-
rclone_api-1.3.27.dist-info/METADATA,sha256=r9lu8qOOxcB0zfmU6Pnw9eQBo0PvivUPKWtlt2b_XEo,4628
|
47
|
-
rclone_api-1.3.27.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
|
48
|
-
rclone_api-1.3.27.dist-info/entry_points.txt,sha256=fJteOlYVwgX3UbNuL9jJ0zUTuX2O79JFAeNgK7Sw7EQ,255
|
49
|
-
rclone_api-1.3.27.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
|
50
|
-
rclone_api-1.3.27.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|