diff --git a/a_sync/__init__.py b/a_sync/__init__.py index d8f68d19..e5bea89a 100644 --- a/a_sync/__init__.py +++ b/a_sync/__init__.py @@ -16,6 +16,7 @@ - Iterators: :class:`~ASyncIterable`, :class:`~ASyncIterator`, :class:`~filter`, :class:`~sorted` for async iteration. - Utilities: :func:`~all`, :func:`~any`, :func:`~as_yielded` for async utilities. - :func:`~a_sync.a_sync.modifiers.semaphores.apply_semaphore`: Function to apply semaphores to coroutines. + - :class:`~TaskMapping`: A class for managing and asynchronously generating tasks based on input iterables. Alias for backward compatibility: - :class:`~ASyncBase` is an alias for :class:`~ASyncGenericBase`, which will be removed eventually, probably in version 0.1.0. @@ -38,6 +39,14 @@ >>> result = await obj.my_method() >>> print(result) + Using `TaskMapping` for asynchronous task management: + >>> from a_sync import TaskMapping + >>> async def fetch_data(url): + ... return f"Data from {url}" + >>> tasks = TaskMapping(fetch_data, ['http://example.com', 'https://www.python.org']) + >>> async for key, result in tasks: + ... print(f"Data for {key}: {result}") + See Also: - :mod:`a_sync.a_sync`: Contains the core classes and decorators. - :mod:`a_sync.asyncio`: Provides enhanced asyncio functions. diff --git a/a_sync/a_sync/modifiers/semaphores.py b/a_sync/a_sync/modifiers/semaphores.py index 8a781c94..fe554192 100644 --- a/a_sync/a_sync/modifiers/semaphores.py +++ b/a_sync/a_sync/modifiers/semaphores.py @@ -43,7 +43,7 @@ def apply_semaphore( # type: ignore [misc] - :class:`primitives.Semaphore` Note: - `primitives.Semaphore` is a subclass of `asyncio.Semaphore`. Therefore, when the documentation refers to `asyncio.Semaphore`, it also includes `primitives.Semaphore` and any other subclasses. + `primitives.Semaphore` implements the same API as `asyncio.Semaphore`. Therefore, when the documentation refers to `asyncio.Semaphore`, it also includes `primitives.Semaphore` and any other implementations that conform to the same interface. """ @@ -81,7 +81,7 @@ def apply_semaphore( - :class:`primitives.Semaphore` Note: - `primitives.Semaphore` is a subclass of `asyncio.Semaphore`. Therefore, when the documentation refers to `asyncio.Semaphore`, it also includes `primitives.Semaphore` and any other subclasses. + `primitives.Semaphore` implements the same API as `asyncio.Semaphore`. Therefore, when the documentation refers to `asyncio.Semaphore`, it also includes `primitives.Semaphore` and any other implementations that conform to the same interface. """ @@ -128,7 +128,7 @@ def apply_semaphore( - :class:`primitives.Semaphore` Note: - `primitives.Semaphore` is a subclass of `asyncio.Semaphore`. Therefore, when the documentation refers to `asyncio.Semaphore`, it also includes `primitives.Semaphore` and any other subclasses. + `primitives.Semaphore` implements the same API as `asyncio.Semaphore`. Therefore, when the documentation refers to `asyncio.Semaphore`, it also includes `primitives.Semaphore` and any other implementations that conform to the same interface. """ # Parse Inputs if isinstance(coro_fn, (int, asyncio.Semaphore, primitives.Semaphore)): diff --git a/a_sync/primitives/locks/semaphore.pyx b/a_sync/primitives/locks/semaphore.pyx index 569b3d7b..ea6f43da 100644 --- a/a_sync/primitives/locks/semaphore.pyx +++ b/a_sync/primitives/locks/semaphore.pyx @@ -349,7 +349,8 @@ cdef class DummySemaphore(Semaphore): """An optional name for the counter, used in debug logs.""" if self._name == NULL: - raise MemoryError("Failed to allocate memory for __name.") + raise MemoryError("Failed to allocate memory for _name.") + # Copy the bytes data into the char* strcpy(self._name, encoded_name) diff --git a/a_sync/primitives/queue.py b/a_sync/primitives/queue.py index 86caa820..33398b98 100644 --- a/a_sync/primitives/queue.py +++ b/a_sync/primitives/queue.py @@ -438,17 +438,11 @@ def _ensure_workers(self) -> None: if worker.done(): # its only done if its broken exc = worker.exception() # re-raise with clean traceback - try: - raise type(exc)(*exc.args).with_traceback(exc.__traceback__) # type: ignore [union-attr] - except TypeError as e: - raise exc.with_traceback(exc.__traceback__) from e + raise exc.with_traceback(exc.__traceback__) from exc.__cause__ # this should never be reached, but just in case exc = self._workers.exception() - try: - # re-raise with clean traceback - raise type(exc)(*exc.args).with_traceback(exc.__traceback__) # type: ignore [union-attr] - except TypeError as e: - raise exc.with_traceback(exc.__traceback__) from e + # re-raise with clean traceback + raise exc.with_traceback(exc.__traceback__) from exc.__cause__ @functools.cached_property def _workers(self) -> "asyncio.Task[NoReturn]": diff --git a/a_sync/utils/iterators.py b/a_sync/utils/iterators.py index b50c9f56..44e4da58 100644 --- a/a_sync/utils/iterators.py +++ b/a_sync/utils/iterators.py @@ -258,9 +258,7 @@ def _as_yielded_done_callback(t: asyncio.Task) -> None: del task del queue if item._exc: - raise type(item._exc)(*item._exc.args).with_traceback( - item._tb - ) from item._exc.__cause__ + raise item._exc.with_traceback(item._tb) from item._exc.__cause__ return yield item