rclone-api 1.2.9__py2.py3-none-any.whl → 1.2.12__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.
@@ -9,7 +9,7 @@ from typing import Any, Callable
9
9
 
10
10
  from rclone_api.mount import FilePart
11
11
  from rclone_api.s3.chunk_types import UploadState
12
- from rclone_api.types import Finished
12
+ from rclone_api.types import EndOfStream
13
13
  from rclone_api.util import locked_print
14
14
 
15
15
 
@@ -41,7 +41,7 @@ def file_chunker(
41
41
  fetcher: Callable[[int, int, Any], Future[FilePart]],
42
42
  max_chunks: int | None,
43
43
  cancel_signal: Event,
44
- queue_upload: Queue[FilePart | Finished],
44
+ queue_upload: Queue[FilePart | EndOfStream],
45
45
  ) -> None:
46
46
  count = 0
47
47
 
@@ -51,6 +51,9 @@ def file_chunker(
51
51
  if max_chunks is None:
52
52
  return False
53
53
  if count >= max_chunks:
54
+ print(
55
+ f"Stopping file chunker after {count} chunks because it exceeded max_chunks {max_chunks}"
56
+ )
54
57
  return True
55
58
  count += 1
56
59
  return False
@@ -63,7 +66,7 @@ def file_chunker(
63
66
  try:
64
67
  part_number = 1
65
68
  done_part_numbers: set[int] = {
66
- p.part_number for p in upload_state.parts if p is not None
69
+ p.part_number for p in upload_state.parts if not isinstance(p, EndOfStream)
67
70
  }
68
71
  num_parts = upload_info.total_chunks()
69
72
 
@@ -133,4 +136,7 @@ def file_chunker(
133
136
 
134
137
  warnings.warn(f"Error reading file: {e}")
135
138
  finally:
136
- queue_upload.put(Finished())
139
+ print("#############################################################")
140
+ print(f"Finishing FILE CHUNKER for {file_path} and adding EndOfStream")
141
+ print("#############################################################")
142
+ queue_upload.put(EndOfStream())
@@ -7,7 +7,7 @@ from threading import Lock
7
7
 
8
8
  from botocore.client import BaseClient
9
9
 
10
- from rclone_api.types import SizeSuffix
10
+ from rclone_api.types import EndOfStream, SizeSuffix
11
11
  from rclone_api.util import locked_print
12
12
 
13
13
  # _MIN_UPLOAD_CHUNK_SIZE = 5 * 1024 * 1024 # 5MB
@@ -83,27 +83,34 @@ class FinishedPiece:
83
83
  return json.dumps(self.to_json(), indent=0)
84
84
 
85
85
  @staticmethod
86
- def to_json_array(parts: list["FinishedPiece | None"]) -> list[dict | None]:
87
- non_none: list[FinishedPiece] = [p for p in parts if p is not None]
86
+ def to_json_array(parts: list["FinishedPiece | EndOfStream"]) -> list[dict]:
87
+ non_none: list[FinishedPiece] = []
88
+ for p in parts:
89
+ if not isinstance(p, EndOfStream):
90
+ non_none.append(p)
88
91
  non_none.sort(key=lambda x: x.part_number)
89
- all_nones: list[None] = [None for p in parts if p is None]
90
- assert len(all_nones) <= 1, "Only one None should be present"
92
+ # all_nones: list[None] = [None for p in parts if p is None]
93
+ # assert len(all_nones) <= 1, "Only one None should be present"
94
+ count_eos = 0
95
+ for p in parts:
96
+ if p is EndOfStream:
97
+ count_eos += 1
98
+ assert count_eos <= 1, "Only one EndOfStream should be present"
91
99
  return [p.to_json() for p in non_none]
92
100
 
93
101
  @staticmethod
94
- def from_json(json: dict | None) -> "FinishedPiece | None":
102
+ def from_json(json: dict | None) -> "FinishedPiece | EndOfStream":
95
103
  if json is None:
96
- return None
104
+ return EndOfStream()
97
105
  return FinishedPiece(**json)
98
106
 
99
107
 
100
108
  @dataclass
101
109
  class UploadState:
102
110
  upload_info: UploadInfo
103
- # finished_parts: Queue[FinishedPiece | None]
104
111
  peristant: Path | None
105
112
  lock: Lock = Lock()
106
- parts: list[FinishedPiece | None] = field(default_factory=list)
113
+ parts: list[FinishedPiece | EndOfStream] = field(default_factory=list)
107
114
 
108
115
  def update_source_file(self, src_file: Path, known_file_size: int | None) -> None:
109
116
  new_file_size = (
@@ -126,7 +133,7 @@ class UploadState:
126
133
  num_chunks = self.upload_info.total_chunks()
127
134
  count = 0
128
135
  for p in self.parts:
129
- if p is not None:
136
+ if not isinstance(p, EndOfStream):
130
137
  count += 1
131
138
  return count, num_chunks
132
139
 
@@ -141,7 +148,7 @@ class UploadState:
141
148
  ), f"Count {count} is greater than num_chunks {num_chunks}"
142
149
  return num_chunks - count
143
150
 
144
- def add_finished(self, part: FinishedPiece | None) -> None:
151
+ def add_finished(self, part: FinishedPiece | EndOfStream) -> None:
145
152
  if part is None:
146
153
  return
147
154
  with self.lock:
@@ -195,13 +202,13 @@ class UploadState:
195
202
  def to_json(self) -> dict:
196
203
  # queue -> list
197
204
  # parts: list[dict] = [f.to_json() for f in self.parts]
198
- parts: list[FinishedPiece | None] = list(self.parts)
205
+ parts: list[FinishedPiece | EndOfStream] = list(self.parts)
199
206
 
200
207
  parts_json = FinishedPiece.to_json_array(parts)
201
208
  is_done = self.is_done()
202
209
  count_non_none: int = 0
203
210
  for p in parts:
204
- if p is not None:
211
+ if p is not EndOfStream:
205
212
  count_non_none += 1
206
213
 
207
214
  file_size_bytes = self.upload_info.file_size
@@ -18,7 +18,7 @@ from rclone_api.s3.chunk_types import (
18
18
  UploadState,
19
19
  )
20
20
  from rclone_api.s3.types import MultiUploadResult
21
- from rclone_api.types import Finished
21
+ from rclone_api.types import EndOfStream
22
22
  from rclone_api.util import locked_print
23
23
 
24
24
  _MIN_UPLOAD_CHUNK_SIZE = 5 * 1024 * 1024 # 5MB
@@ -58,10 +58,10 @@ def upload_task(
58
58
 
59
59
 
60
60
  def handle_upload(
61
- upload_info: UploadInfo, fp: FilePart
62
- ) -> FinishedPiece | Exception | None:
63
- if fp is None:
64
- return None
61
+ upload_info: UploadInfo, fp: FilePart | EndOfStream
62
+ ) -> FinishedPiece | Exception | EndOfStream:
63
+ if isinstance(fp, EndOfStream):
64
+ return fp
65
65
  assert isinstance(fp.extra, S3FileInfo)
66
66
  extra: S3FileInfo = fp.extra
67
67
  part_number = extra.part_number
@@ -222,7 +222,7 @@ def upload_file_multipart(
222
222
  started_new_upload = finished == 0
223
223
  upload_info = upload_state.upload_info
224
224
 
225
- queue_upload: Queue[FilePart | Finished] = Queue(work_que_max)
225
+ queue_upload: Queue[FilePart | EndOfStream] = Queue(work_que_max)
226
226
  chunker_errors: Queue[Exception] = Queue()
227
227
  cancel_chunker_event = Event()
228
228
 
@@ -246,6 +246,9 @@ def upload_file_multipart(
246
246
  queue_errors.put(e)
247
247
  _thread.interrupt_main()
248
248
  raise
249
+ print("#########################################")
250
+ print("# CHUNKER TASK COMPLETED")
251
+ print("#########################################")
249
252
 
250
253
  try:
251
254
  thread_chunker = Thread(target=chunker_task, daemon=True)
@@ -254,11 +257,11 @@ def upload_file_multipart(
254
257
  with ThreadPoolExecutor(max_workers=upload_threads) as executor:
255
258
  try:
256
259
  while True:
257
- file_chunk: FilePart | Finished = queue_upload.get()
258
- if file_chunk is Finished:
260
+ file_chunk: FilePart | EndOfStream = queue_upload.get()
261
+ if file_chunk is EndOfStream:
259
262
  break
260
263
 
261
- if isinstance(file_chunk, Finished):
264
+ if isinstance(file_chunk, EndOfStream):
262
265
  break
263
266
 
264
267
  def task(upload_info=upload_info, file_chunk=file_chunk):
@@ -280,7 +283,7 @@ def upload_file_multipart(
280
283
  executor.shutdown(wait=False, cancel_futures=True)
281
284
  raise
282
285
  # upload_state.finished_parts.put(None) # Signal the end of the queue
283
- upload_state.add_finished(None)
286
+ upload_state.add_finished(EndOfStream())
284
287
  thread_chunker.join()
285
288
 
286
289
  if not chunker_errors.empty():
@@ -288,7 +291,9 @@ def upload_file_multipart(
288
291
  if not upload_state.is_done():
289
292
  upload_state.save()
290
293
  return MultiUploadResult.SUSPENDED
291
- parts: list[FinishedPiece] = [p for p in upload_state.parts if p is not None]
294
+ parts: list[FinishedPiece] = [
295
+ p for p in upload_state.parts if not isinstance(p, EndOfStream)
296
+ ]
292
297
  locked_print(f"Upload complete, sorting {len(parts)} parts to complete upload")
293
298
  parts.sort(key=lambda x: x.part_number) # Some backends need this.
294
299
  parts_s3: list[dict] = [
rclone_api/types.py CHANGED
@@ -263,7 +263,7 @@ def get_chunk_tmpdir() -> Path:
263
263
  return out
264
264
 
265
265
 
266
- class Finished:
266
+ class EndOfStream:
267
267
  pass
268
268
 
269
269
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.2.9
3
+ Version: 1.2.12
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -17,7 +17,7 @@ rclone_api/rclone.py,sha256=4_eoKkC0eZDT2VnpMlrF5EkDZam5WWaiiWFxNntqs2k,49323
17
17
  rclone_api/remote.py,sha256=O9WDUFQy9f6oT1HdUbTixK2eg0xtBBm8k4Xl6aa6K00,431
18
18
  rclone_api/rpath.py,sha256=8ZA_1wxWtskwcy0I8V2VbjKDmzPkiWd8Q2JQSvh-sYE,2586
19
19
  rclone_api/scan_missing_folders.py,sha256=Kulca2Q6WZodt00ATFHkmqqInuoPvBkhTcS9703y6po,4740
20
- rclone_api/types.py,sha256=bmLu9EnX5Q2DyUkoyi6ExgywkfOkb_YNJdTQfj8YYrk,9923
20
+ rclone_api/types.py,sha256=XiiWoGXAzNxTEfRcszw3BeRF7ZATXHIAPFg2-aJzUfo,9926
21
21
  rclone_api/util.py,sha256=_Z-GUMVXnHYOGdo2dy2ie2P5fGgyg8KdGjHKicx68Ko,4573
22
22
  rclone_api/walk.py,sha256=-54NVE8EJcCstwDoaC_UtHm73R2HrZwVwQmsnv55xNU,3369
23
23
  rclone_api/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
@@ -28,14 +28,14 @@ rclone_api/experimental/flags_base.py,sha256=ajU_czkTcAxXYU-SlmiCfHY7aCQGHvpCLqJ
28
28
  rclone_api/profile/mount_copy_bytes.py,sha256=HK11knsykKO1WNi8LYOkQbipQBpZn7uhV5CVEQDRCJs,8558
29
29
  rclone_api/s3/api.py,sha256=PafsIEyWDpLWAXsZAjFm9CY14vJpsDr9lOsn0kGRLZ0,4009
30
30
  rclone_api/s3/basic_ops.py,sha256=hK3366xhVEzEcjz9Gk_8lFx6MRceAk72cax6mUrr6ko,2104
31
- rclone_api/s3/chunk_file.py,sha256=lZh4oCEo87jn5oEWHzK786_G9Y2RMmJz6cuL-ypAIT0,4402
32
- rclone_api/s3/chunk_types.py,sha256=NOdMz9lvoOi2DzNIaIZVY4-nGa-00P6eLSsPMak0gh8,8498
31
+ rclone_api/s3/chunk_file.py,sha256=mk0koNiohOTJIp3nor2Lg-KlfbHeetC6GM4HVzkmEGY,4805
32
+ rclone_api/s3/chunk_types.py,sha256=I0YCWFgxCvmt8cp4tMabiiwiD2yKTcbA6ZL2D3xnn5w,8781
33
33
  rclone_api/s3/create.py,sha256=wgfkapv_j904CfKuWyiBIWJVxfAx_ftemFSUV14aT68,3149
34
34
  rclone_api/s3/types.py,sha256=FkUNNAk8fjSbLhDA45YgNQk9BTjmJZHT3fExiCKcDt0,1591
35
- rclone_api/s3/upload_file_multipart.py,sha256=scsGOxMpg2j9qK2oX_Xe4vHI6u0IHX0xtp9mHnt7Ksc,11113
36
- rclone_api-1.2.9.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
37
- rclone_api-1.2.9.dist-info/METADATA,sha256=mSCgGU2Hwr87w4wlc8ZxlqG4oJ1F0t49olLS6I51wDc,4536
38
- rclone_api-1.2.9.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
39
- rclone_api-1.2.9.dist-info/entry_points.txt,sha256=TV8kwP3FRzYwUEr0RLC7aJh0W03SAefIJNXTJ-FdMIQ,200
40
- rclone_api-1.2.9.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
41
- rclone_api-1.2.9.dist-info/RECORD,,
35
+ rclone_api/s3/upload_file_multipart.py,sha256=TrhrYeRkpQRzmn8x_RR59ww3GXA3Wd95pCKI-Bhu9_0,11372
36
+ rclone_api-1.2.12.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
37
+ rclone_api-1.2.12.dist-info/METADATA,sha256=47ATkIGrPGHwqK9hqVVJifxeli3iwGFnvusvIbS0_ms,4537
38
+ rclone_api-1.2.12.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
39
+ rclone_api-1.2.12.dist-info/entry_points.txt,sha256=TV8kwP3FRzYwUEr0RLC7aJh0W03SAefIJNXTJ-FdMIQ,200
40
+ rclone_api-1.2.12.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
41
+ rclone_api-1.2.12.dist-info/RECORD,,