Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docs): add some examples #339

Merged
merged 1 commit into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
- [async modifiers](#async-modifiers)
- [sync modifiers](#sync-modifiers)
- [Default Modifiers](#default-modifiers)
- [Other Helpful Classes](#other-helpful-classes)
- [ASyncIterable](#asynciterable)
- [ASyncIterator](#asynciterator)
- [ASyncFilter](#asyncfilter)
- [ASyncSorter](#asyncsorter)

<!-- /TOC -->
## Introduction
Expand Down Expand Up @@ -195,3 +200,87 @@ Instead of setting modifiers one by one in functions, you can set a default valu
- `RAM_CACHE_TTL`
- `RUNS_PER_MINUTE`
- `SEMAPHORE`

### Other Helpful Classes
#### ASyncIterable
The `ASyncIterable` class allows objects to be iterated over using either a standard `for` loop or an `async for` loop. This is particularly useful in scenarios where the mode of iteration needs to be flexible or is determined at runtime.

```python
from a_sync import ASyncIterable

async_iterable = ASyncIterable(some_async_iterable)

# Asynchronous iteration
async for item in async_iterable:
...

# Synchronous iteration
for item in async_iterable:
...
```

#### ASyncIterator

The `ASyncIterator` class provides a unified interface for iteration that can operate in both synchronous and asynchronous contexts. It allows the wrapping of asynchronous iterable objects or async generator functions.

```python
from a_sync import ASyncIterator

async_iterator = ASyncIterator(some_async_iterator)

# Asynchronous iteration
async for item in async_iterator:
...

# Synchronous iteration
for item in async_iterator:
...
```

#### ASyncFilter

The `ASyncFilter` class filters items of an async iterable based on a provided function. It can handle both synchronous and asynchronous filter functions.

```python
from a_sync import ASyncFilter

async def is_even(x):
return x % 2 == 0

filtered_iterable = ASyncFilter(is_even, some_async_iterable)

# or use the alias
import a_sync

filtered_iterable = a_sync.filter(is_even, some_async_iterable)

# Asynchronous iteration
async for item in filtered_iterable:
...

# Synchronous iteration
for item in filtered_iterable:
...
```

#### ASyncSorter

The `ASyncSorter` class sorts items of an async iterable based on a provided key function. It supports both synchronous and asynchronous key functions.

```python
from a_sync import ASyncSorter

sorted_iterable = ASyncSorter(some_async_iterable, key=lambda x: x.value)

# or use the alias
import a_sync

sorted_iterable = a_sync.sort(some_async_iterable, key=lambda x: x.value)

# Asynchronous iteration
async for item in sorted_iterable:
...

# Synchronous iteration
for item in sorted_iterable:
...
82 changes: 81 additions & 1 deletion a_sync/_smart.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ class _SmartFutureMixin(Generic[T]):
def __await__(self: Union["SmartFuture", "SmartTask"]) -> Generator[Any, None, T]:
"""
Await the smart future or task, handling waiters and logging.

Yields:
The result of the future or task.

Raises:
RuntimeError: If await wasn't used with future.

Example:
```python
future = SmartFuture()
result = await future
```
"""
if self.done():
return self.result() # May raise too.
Expand All @@ -54,6 +66,15 @@ def num_waiters(self: Union["SmartFuture", "SmartTask"]) -> int:
# NOTE: we check .done() because the callback may not have ran yet and its very lightweight
"""
Get the number of waiters currently awaiting the future or task.

Returns:
int: The number of waiters.

Example:
```python
future = SmartFuture()
print(future.num_waiters)
```
"""
if self.done():
# if there are any waiters left, there won't be once the event loop runs once
Expand All @@ -67,6 +88,9 @@ def _waiter_done_cleanup_callback(
Callback to clean up waiters when a waiter task is done.

Removes the waiter from _waiters, and _queue._futs if applicable

Args:
waiter: The waiter task to clean up.
"""
if not self.done():
self._waiters.remove(waiter)
Expand All @@ -86,6 +110,12 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):

Inherits from both _SmartFutureMixin and asyncio.Future, providing additional functionality
for tracking waiters and integrating with a smart processing queue.

Example:
```python
future = SmartFuture()
await future
```
"""

_queue = None
Expand All @@ -105,6 +135,11 @@ def __init__(
queue: Optional; a smart processing queue.
key: Optional; a key identifying the future.
loop: Optional; the event loop.

Example:
```python
future = SmartFuture(queue=my_queue, key=my_key)
```
"""
super().__init__(loop=loop)
if queue:
Expand All @@ -127,6 +162,13 @@ def __lt__(self, other: "SmartFuture[T]") -> bool:

Returns:
True if self has more waiters than other.

Example:
```python
future1 = SmartFuture()
future2 = SmartFuture()
print(future1 < future2)
```
"""
return self.num_waiters > other.num_waiters

Expand All @@ -147,6 +189,11 @@ def create_future(

Returns:
A SmartFuture instance.

Example:
```python
future = create_future(queue=my_queue, key=my_key)
```
"""
return SmartFuture(queue=queue, key=key, loop=loop or asyncio.get_event_loop())

Expand All @@ -157,6 +204,12 @@ class SmartTask(_SmartFutureMixin[T], asyncio.Task):

Inherits from both _SmartFutureMixin and asyncio.Task, providing additional functionality
for tracking waiters and integrating with a smart processing queue.

Example:
```python
task = SmartTask(coro=my_coroutine())
await task
```
"""

def __init__(
Expand All @@ -173,6 +226,11 @@ def __init__(
coro: The coroutine to run in the task.
loop: Optional; the event loop.
name: Optional; the name of the task.

Example:
```python
task = SmartTask(coro=my_coroutine(), name="my_task")
```
"""
super().__init__(coro, loop=loop, name=name)
self._waiters: Set["asyncio.Task[T]"] = set()
Expand All @@ -193,6 +251,12 @@ def smart_task_factory(

Returns:
A SmartTask instance running the provided coroutine.

Example:
```python
loop = asyncio.get_event_loop()
task = smart_task_factory(loop, my_coroutine())
```
"""
return SmartTask(coro, loop=loop)

Expand All @@ -203,6 +267,14 @@ def set_smart_task_factory(loop: asyncio.AbstractEventLoop = None) -> None:

Args:
loop: Optional; the event loop. If None, the current event loop is used.

Example:
```python
set_smart_task_factory()
```

See Also:
- :func:`smart_task_factory`
"""
if loop is None:
loop = a_sync.asyncio.get_event_loop()
Expand Down Expand Up @@ -241,6 +313,14 @@ def shield(
Args:
arg: The awaitable to shield from cancellation.
loop: Optional; the event loop. Deprecated since Python 3.8.

Example:
```python
result = await shield(my_coroutine())
```

See Also:
- :func:`asyncio.shield`
"""
if loop is not None:
warnings.warn(
Expand Down Expand Up @@ -291,4 +371,4 @@ def _outer_done_callback(outer):
"SmartTask",
"smart_task_factory",
"set_smart_task_factory",
]
]
Loading
Loading