|
1 | 1 | import asyncio |
2 | | -import ctypes |
3 | 2 | import logging |
4 | 3 | import weakref |
5 | 4 | from collections import deque |
6 | 5 |
|
7 | 6 | from . import asyn as fsspec_asyn |
| 7 | +from .utils import HAS_CPYTHON_API, _fast_slice |
8 | 8 |
|
9 | 9 | logger = logging.getLogger(__name__) |
10 | 10 |
|
11 | | -try: |
12 | | - PyBytes_FromStringAndSize = ctypes.pythonapi.PyBytes_FromStringAndSize |
13 | | - PyBytes_FromStringAndSize.argtypes = (ctypes.c_void_p, ctypes.c_ssize_t) |
14 | | - PyBytes_FromStringAndSize.restype = ctypes.py_object |
15 | | - |
16 | | - PyBytes_AsString = ctypes.pythonapi.PyBytes_AsString |
17 | | - PyBytes_AsString.argtypes = (ctypes.py_object,) |
18 | | - PyBytes_AsString.restype = ctypes.c_void_p |
19 | | - HAS_CPYTHON_API = True |
20 | | -except Exception: |
21 | | - PyBytes_FromStringAndSize = None |
22 | | - PyBytes_AsString = None |
23 | | - HAS_CPYTHON_API = False |
24 | | - |
25 | | - |
26 | | -# Please refer to following discussion to understand why this is required at this point |
27 | | -# Discussion = https://github.com/fsspec/gcsfs/pull/795#discussion_r3032749881 |
28 | | -def _fast_slice(src_bytes, offset, read_size): |
29 | | - if read_size == 0: |
30 | | - return b"" |
31 | | - if offset < 0 or offset + read_size > len(src_bytes): |
32 | | - raise ValueError("Slice indices out of bounds") |
33 | | - |
34 | | - if HAS_CPYTHON_API: |
35 | | - dest_bytes = PyBytes_FromStringAndSize(None, read_size) |
36 | | - src_ptr = PyBytes_AsString(src_bytes) |
37 | | - dest_ptr = PyBytes_AsString(dest_bytes) |
38 | | - # Releases the GIL |
39 | | - ctypes.memmove(dest_ptr, src_ptr + offset, read_size) |
40 | | - return dest_bytes |
41 | | - else: |
42 | | - # Standard fallback for PyPy/non-CPython |
43 | | - return src_bytes[offset : offset + read_size] |
44 | | - |
45 | 11 |
|
46 | 12 | class RunningAverageTracker: |
47 | 13 | """Tracks a running average of values over a sliding window. |
@@ -237,7 +203,7 @@ async def stop(self): |
237 | 203 | self._producer_task.cancel() |
238 | 204 | tasks_to_wait.append(self._producer_task) |
239 | 205 |
|
240 | | - tasks_to_wait.extend(task for task in self._active_tasks if not task.done()) |
| 206 | + tasks_to_wait.extend(task for task in list(self._active_tasks) if not task.done()) |
241 | 207 |
|
242 | 208 | # We do not cancel the network task, instead we wait on them. |
243 | 209 | # This is intentionally done to avoid MRD stream disruption. |
@@ -300,8 +266,7 @@ async def _loop(self): |
300 | 266 | logger.debug("PrefetchProducer loop was cancelled.") |
301 | 267 | except Exception as e: |
302 | 268 | logger.exception( |
303 | | - "PrefetchProducer loop encountered an unexpected error: %s", |
304 | | - e, |
| 269 | + "PrefetchProducer loop encountered an unexpected error." |
305 | 270 | ) |
306 | 271 | self.is_stopped = True |
307 | 272 | self.orchestrator.set_error(e) |
@@ -557,7 +522,7 @@ async def _advance(self, size: int, save_data: bool) -> list[bytes]: |
557 | 522 | except asyncio.CancelledError: |
558 | 523 | raise |
559 | 524 | except Exception as e: |
560 | | - logger.exception("Consumer caught an error: %s", e) |
| 525 | + logger.exception("Consumer caught an error.") |
561 | 526 | self.orchestrator.set_error(e) |
562 | 527 | raise e |
563 | 528 |
|
@@ -817,7 +782,7 @@ async def _async_fetch(self, start, end): |
817 | 782 | self._error = e |
818 | 783 | raise |
819 | 784 | except Exception as e: |
820 | | - logger.exception("Exception raised during asynchronous fetch: %s", e) |
| 785 | + logger.exception("Exception raised during asynchronous fetch.") |
821 | 786 | self._error = e |
822 | 787 | if self.producer and not self.producer.is_stopped: |
823 | 788 | await self.producer.stop() |
|
0 commit comments