rclone-api 1.2.6__py2.py3-none-any.whl → 1.2.8__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/mount.py CHANGED
@@ -288,6 +288,32 @@ def _cache_dir_delete_on_exit(cache_dir: Path) -> None:
288
288
  warnings.warn(f"Error removing cache directory {cache_dir}: {e}")
289
289
 
290
290
 
291
+ def _read_from_mount_task(
292
+ offset: int, size: int, path: Path, verbose: bool
293
+ ) -> bytes | Exception:
294
+ if verbose or True:
295
+ print(f"Fetching chunk: offset={offset}, size={size}, path={path}")
296
+ try:
297
+ with path.open("rb") as f:
298
+ f.seek(offset)
299
+ sz = f.read(size)
300
+ assert len(sz) == size, f"Invalid read size: {len(sz)}"
301
+ return sz
302
+ except KeyboardInterrupt as e:
303
+ import _thread
304
+
305
+ warnings.warn(f"Error fetching file chunk: {e}")
306
+
307
+ _thread.interrupt_main()
308
+ return Exception(e)
309
+ except Exception as e:
310
+ stack_trace = traceback.format_exc()
311
+ warnings.warn(
312
+ f"Error fetching file chunk at offset {offset} + {size}: {e}\n{stack_trace}"
313
+ )
314
+ return e
315
+
316
+
291
317
  class MultiMountFileChunker:
292
318
  def __init__(
293
319
  self,
@@ -319,89 +345,34 @@ class MultiMountFileChunker:
319
345
  def fetch(self, offset: int, size: int) -> Future[bytes | Exception]:
320
346
  if self.verbose:
321
347
  print(f"Fetching data range: offset={offset}, size={size}")
348
+
349
+ assert size > 0, f"Invalid size: {size}"
350
+ assert offset >= 0, f"Invalid offset: {offset}"
351
+ assert (
352
+ offset + size <= self.filesize
353
+ ), f"Invalid offset + size: {offset} + {size} ({offset+size}) <= {self.filesize}"
354
+
322
355
  try:
323
- try:
324
- if offset + size > self.filesize:
325
- size = self.filesize - offset
326
- assert (
327
- offset + size <= self.filesize
328
- ), f"Invalid offset + size: {offset + size}, it is beyond the end of the file."
329
- assert size > 0, f"Invalid size: {size}"
330
- assert offset >= 0, f"Invalid offset: {offset}"
331
- except AssertionError as e:
332
- warnings.warn(f"Invalid chunk request: {e}")
333
- # return ValueError(e)
334
- # return self.executor.submit(lambda: Exception(e))
335
- err = Exception(e)
336
- return self.executor.submit(lambda: err)
337
-
338
- chunks: list[tuple[int, int]] = []
339
- start = offset
340
- end = offset + size
341
- while start < end:
342
- chunk_size = min(self.chunk_size.as_int(), end - start)
343
- chunks.append((start, chunk_size))
344
- start += chunk_size
345
-
346
- futures: list[Future[bytes | Exception]] = []
347
- for start, chunk_size in chunks:
348
- self.semaphore.acquire()
356
+ self.semaphore.acquire()
357
+ with self.lock:
358
+ mount = self.mounts_availabe.pop()
359
+ self.mounts_processing.append(mount)
360
+
361
+ path = mount.mount_path / self.filename
362
+
363
+ def task(
364
+ offset=offset, size=size, path=path, mount=mount, verbose=self.verbose
365
+ ) -> bytes | Exception:
366
+ out = _read_from_mount_task(
367
+ offset=offset, size=size, path=path, verbose=verbose
368
+ )
349
369
  with self.lock:
350
- mount = self.mounts_availabe.pop()
351
- self.mounts_processing.append(mount)
352
-
353
- path = mount.mount_path / self.filename
370
+ self.mounts_processing.remove(mount)
371
+ self.mounts_availabe.append(mount)
372
+ self.semaphore.release()
373
+ return out
354
374
 
355
- def task(
356
- offset=start, size=chunk_size, path=path, mount=mount
357
- ) -> bytes | Exception:
358
- if self.verbose:
359
- print(
360
- f"Fetching chunk: offset={offset}, size={size}, path={path}"
361
- )
362
- try:
363
- # make sure we don't overflow the file size
364
- # assert (
365
- # offset + size <= self.chunk_size.as_int()
366
- # ), f"Invalid offset + size: {offset + size}, it is beyond the end of the file."
367
- if offset + size > self.filesize:
368
- size = self.filesize - offset
369
- with path.open("rb") as f:
370
- f.seek(offset)
371
- return f.read(size)
372
- except KeyboardInterrupt as e:
373
- import _thread
374
-
375
- warnings.warn(f"Error fetching file chunk: {e}")
376
-
377
- _thread.interrupt_main()
378
- return Exception(e)
379
- except Exception as e:
380
- stack_trace = traceback.format_exc()
381
- warnings.warn(
382
- f"Error fetching file chunk at offset {offset} + {size}: {e}\n{stack_trace}"
383
- )
384
- return e
385
- finally:
386
- with self.lock:
387
- self.mounts_processing.remove(mount)
388
- self.mounts_availabe.append(mount)
389
- self.semaphore.release()
390
-
391
- fut = self.executor.submit(task)
392
- futures.append(fut)
393
-
394
- def combine(futs: list[Future[bytes | Exception]]) -> bytes | Exception:
395
- finished_list: list[bytes | Exception] = [f.result() for f in futs]
396
- bytes_list = [f for f in finished_list if isinstance(f, bytes)]
397
- if len(bytes_list) != len(finished_list):
398
- exceptions = [f for f in finished_list if isinstance(f, Exception)]
399
- return Exception(f"Error fetching file chunk: {exceptions}")
400
- return b"".join(bytes_list)
401
-
402
- if len(futures) == 1:
403
- return futures[0]
404
- fut = self.executor.submit(combine, futures)
375
+ fut = self.executor.submit(task)
405
376
  return fut
406
377
  except Exception as e:
407
378
  warnings.warn(f"Error fetching file chunk: {e}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rclone_api
3
- Version: 1.2.6
3
+ Version: 1.2.8
4
4
  Summary: rclone api in python
5
5
  Home-page: https://github.com/zackees/rclone-api
6
6
  License: BSD 3-Clause License
@@ -11,7 +11,7 @@ rclone_api/exec.py,sha256=Pd7pUBd8ib5MzqvMybG2DQISPRbDRu20VjVRL2mLAVY,1076
11
11
  rclone_api/file.py,sha256=EP5yT2dZ0H2p7CY5n0y5k5pHhIliV25pm8KOwBklUTk,1863
12
12
  rclone_api/filelist.py,sha256=xbiusvNgaB_b_kQOZoHMJJxn6TWGtPrWd2J042BI28o,767
13
13
  rclone_api/group_files.py,sha256=H92xPW9lQnbNw5KbtZCl00bD6iRh9yRbCuxku4j_3dg,8036
14
- rclone_api/mount.py,sha256=yklGrFzqADpxE8oK6PQCt78ZryK4JmU8lqv4S8cgroA,15234
14
+ rclone_api/mount.py,sha256=qdfPatPKGAAaNexJQCvunq_MdBJL6NSlGmin8cHCXGg,13255
15
15
  rclone_api/process.py,sha256=rBj_S86jC6nqCYop-jq8r9eMSteKeObxUrJMgH8LZvI,5084
16
16
  rclone_api/rclone.py,sha256=V4oeepsleic2llCA7JekMw1iOwN7uYE3ktJ-gEA7wcw,49277
17
17
  rclone_api/remote.py,sha256=O9WDUFQy9f6oT1HdUbTixK2eg0xtBBm8k4Xl6aa6K00,431
@@ -33,9 +33,9 @@ rclone_api/s3/chunk_types.py,sha256=2n9U1BZ_5mcpoLLbSqkhvzgKj814jtSMnih9CWKcChU,
33
33
  rclone_api/s3/create.py,sha256=wgfkapv_j904CfKuWyiBIWJVxfAx_ftemFSUV14aT68,3149
34
34
  rclone_api/s3/types.py,sha256=ZUw9s164wljCEMTS4CoHXNzFIhYJEgKD6NDAu-RXyr8,1551
35
35
  rclone_api/s3/upload_file_multipart.py,sha256=aDaLF2FWSvU_jurxiFphGZBncvkPqWN47VFNzYSSTWM,10906
36
- rclone_api-1.2.6.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
37
- rclone_api-1.2.6.dist-info/METADATA,sha256=zYEyLONtUobgqIBRwPN_iQ1y0rmKFzfT-JKbtt2wXLg,4536
38
- rclone_api-1.2.6.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
39
- rclone_api-1.2.6.dist-info/entry_points.txt,sha256=TV8kwP3FRzYwUEr0RLC7aJh0W03SAefIJNXTJ-FdMIQ,200
40
- rclone_api-1.2.6.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
41
- rclone_api-1.2.6.dist-info/RECORD,,
36
+ rclone_api-1.2.8.dist-info/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
37
+ rclone_api-1.2.8.dist-info/METADATA,sha256=eWhq_lLs9m_Vp01kxODo85kaTye0kNaizIDMFXeIlmY,4536
38
+ rclone_api-1.2.8.dist-info/WHEEL,sha256=rF4EZyR2XVS6irmOHQIJx2SUqXLZKRMUrjsg8UwN-XQ,109
39
+ rclone_api-1.2.8.dist-info/entry_points.txt,sha256=TV8kwP3FRzYwUEr0RLC7aJh0W03SAefIJNXTJ-FdMIQ,200
40
+ rclone_api-1.2.8.dist-info/top_level.txt,sha256=EvZ7uuruUpe9RiUyEp25d1Keq7PWYNT0O_-mr8FCG5g,11
41
+ rclone_api-1.2.8.dist-info/RECORD,,