ez-a-sync 0.22.15__tar.gz → 0.22.16__tar.gz
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.
Potentially problematic release.
This version of ez-a-sync might be problematic. Click here for more details.
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/PKG-INFO +1 -1
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/README.md +132 -0
- ez_a_sync-0.22.16/a_sync/ENVIRONMENT_VARIABLES.py +44 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/__init__.py +32 -9
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/_smart.py +105 -6
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/_typing.py +56 -3
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/_descriptor.py +174 -12
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/_flags.py +64 -3
- ez_a_sync-0.22.16/a_sync/a_sync/_helpers.py +91 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/_kwargs.py +30 -6
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/_meta.py +35 -6
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/abstract.py +57 -9
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/config.py +44 -7
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/decorator.py +217 -37
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/function.py +339 -47
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/method.py +241 -52
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/modifiers/__init__.py +39 -1
- ez_a_sync-0.22.16/a_sync/a_sync/modifiers/cache/__init__.py +159 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/modifiers/cache/memory.py +50 -6
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/modifiers/limiter.py +55 -6
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/modifiers/manager.py +46 -2
- ez_a_sync-0.22.16/a_sync/a_sync/modifiers/semaphores.py +175 -0
- ez_a_sync-0.22.16/a_sync/a_sync/singleton.py +61 -0
- ez_a_sync-0.22.16/a_sync/asyncio/__init__.py +149 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/asyncio/as_completed.py +44 -38
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/asyncio/create_task.py +46 -10
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/asyncio/gather.py +72 -25
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/exceptions.py +178 -11
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/executor.py +51 -3
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/future.py +671 -29
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/iter.py +64 -7
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/primitives/_debug.py +59 -5
- ez_a_sync-0.22.16/a_sync/primitives/_loggable.py +69 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/primitives/locks/counter.py +74 -7
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/primitives/locks/prio_semaphore.py +87 -8
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/primitives/locks/semaphore.py +68 -20
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/primitives/queue.py +65 -26
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/task.py +51 -15
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/utils/iterators.py +52 -16
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/ez_a_sync.egg-info/PKG-INFO +1 -1
- ez_a_sync-0.22.16/tests/executor.py +252 -0
- ez_a_sync-0.22.16/tests/test_abstract.py +35 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_base.py +198 -2
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_executor.py +23 -0
- ez_a_sync-0.22.16/tests/test_singleton.py +37 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_task.py +45 -17
- ez_a_sync-0.22.15/a_sync/ENVIRONMENT_VARIABLES.py +0 -13
- ez_a_sync-0.22.15/a_sync/a_sync/_helpers.py +0 -59
- ez_a_sync-0.22.15/a_sync/a_sync/modifiers/cache/__init__.py +0 -89
- ez_a_sync-0.22.15/a_sync/a_sync/modifiers/semaphores.py +0 -102
- ez_a_sync-0.22.15/a_sync/a_sync/singleton.py +0 -37
- ez_a_sync-0.22.15/a_sync/asyncio/__init__.py +0 -13
- ez_a_sync-0.22.15/a_sync/primitives/_loggable.py +0 -39
- ez_a_sync-0.22.15/tests/executor.py +0 -114
- ez_a_sync-0.22.15/tests/test_abstract.py +0 -20
- ez_a_sync-0.22.15/tests/test_singleton.py +0 -25
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/.coverage +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/.github/workflows/black.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/.github/workflows/codeql.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/.github/workflows/docs.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/.github/workflows/mypy.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/.github/workflows/pytest.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/.github/workflows/release.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/.gitignore +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/.sourcery.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/LICENSE.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/Makefile +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/TODO +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/base.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/a_sync/property.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/aliases.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/asyncio/utils.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/primitives/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/primitives/locks/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/primitives/locks/event.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/py.typed +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/sphinx/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/sphinx/ext.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/a_sync/utils/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/Makefile +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/alabaster.css +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/basic.css +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/custom.css +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/doctools.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/documentation_options.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/file.png +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/language_data.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/minus.png +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/plus.png +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/pygments.css +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/searchtools.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/_build/html/_static/sphinx_highlight.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/conf.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/index.rst +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/docs/make.bat +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/ez_a_sync.egg-info/SOURCES.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/ez_a_sync.egg-info/dependency_links.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/ez_a_sync.egg-info/requires.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/ez_a_sync.egg-info/top_level.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/pyproject.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/requirements-dev.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/requirements.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/setup.cfg +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/setup.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/conftest.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/fixtures.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_as_completed.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_cache.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_decorator.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_future.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_gather.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_helpers.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_iter.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_limiter.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_meta.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_modified.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.22.16}/tests/test_semaphore.py +0 -0
|
@@ -13,6 +13,16 @@
|
|
|
13
13
|
- [async modifiers](#async-modifiers)
|
|
14
14
|
- [sync modifiers](#sync-modifiers)
|
|
15
15
|
- [Default Modifiers](#default-modifiers)
|
|
16
|
+
- [Other Helpful Classes](#other-helpful-modules)
|
|
17
|
+
- [ASyncIterable](#asynciterable)
|
|
18
|
+
- [ASyncIterator](#asynciterator)
|
|
19
|
+
- [ASyncFilter](#asyncfilter)
|
|
20
|
+
- [ASyncSorter](#asyncsorter)
|
|
21
|
+
- [Other Helpful Modules](#other-helpful-modules)
|
|
22
|
+
- [future](#future)
|
|
23
|
+
- [ASyncFuture](#asyncfuture)
|
|
24
|
+
- [future decorator](#future-decorator)
|
|
25
|
+
- [asyncio](#asyncio)
|
|
16
26
|
|
|
17
27
|
<!-- /TOC -->
|
|
18
28
|
## Introduction
|
|
@@ -195,3 +205,125 @@ Instead of setting modifiers one by one in functions, you can set a default valu
|
|
|
195
205
|
- `RAM_CACHE_TTL`
|
|
196
206
|
- `RUNS_PER_MINUTE`
|
|
197
207
|
- `SEMAPHORE`
|
|
208
|
+
|
|
209
|
+
### Other Helpful Classes
|
|
210
|
+
#### ASyncIterable
|
|
211
|
+
The [ASyncIterable](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.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.
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
from a_sync import ASyncIterable
|
|
215
|
+
|
|
216
|
+
async_iterable = ASyncIterable(some_async_iterable)
|
|
217
|
+
|
|
218
|
+
# Asynchronous iteration
|
|
219
|
+
async for item in async_iterable:
|
|
220
|
+
...
|
|
221
|
+
|
|
222
|
+
# Synchronous iteration
|
|
223
|
+
for item in async_iterable:
|
|
224
|
+
...
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
See the [documentation](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.ASyncIterable) for more information.
|
|
228
|
+
|
|
229
|
+
#### ASyncIterator
|
|
230
|
+
|
|
231
|
+
The [ASyncIterator](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.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.
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
from a_sync import ASyncIterator
|
|
235
|
+
|
|
236
|
+
async_iterator = ASyncIterator(some_async_iterator)
|
|
237
|
+
|
|
238
|
+
# Asynchronous iteration
|
|
239
|
+
async for item in async_iterator:
|
|
240
|
+
...
|
|
241
|
+
|
|
242
|
+
# Synchronous iteration
|
|
243
|
+
for item in async_iterator:
|
|
244
|
+
...
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
See the [documentation](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.ASyncIterator) for more information.
|
|
248
|
+
|
|
249
|
+
#### ASyncFilter
|
|
250
|
+
|
|
251
|
+
The [ASyncFilter](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.ASyncFilter) class filters items of an async iterable based on a provided function. It can handle both synchronous and asynchronous filter functions.
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from a_sync import ASyncFilter
|
|
255
|
+
|
|
256
|
+
async def is_even(x):
|
|
257
|
+
return x % 2 == 0
|
|
258
|
+
|
|
259
|
+
filtered_iterable = ASyncFilter(is_even, some_async_iterable)
|
|
260
|
+
|
|
261
|
+
# or use the alias
|
|
262
|
+
import a_sync
|
|
263
|
+
|
|
264
|
+
filtered_iterable = a_sync.filter(is_even, some_async_iterable)
|
|
265
|
+
|
|
266
|
+
# Asynchronous iteration
|
|
267
|
+
async for item in filtered_iterable:
|
|
268
|
+
...
|
|
269
|
+
|
|
270
|
+
# Synchronous iteration
|
|
271
|
+
for item in filtered_iterable:
|
|
272
|
+
...
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
See the [documentation](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.ASyncFilter) for more information.
|
|
276
|
+
|
|
277
|
+
#### ASyncSorter
|
|
278
|
+
|
|
279
|
+
The [ASyncSorter](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.ASyncSorter) class sorts items of an async iterable based on a provided key function. It supports both synchronous and asynchronous key functions.
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
from a_sync import ASyncSorter
|
|
283
|
+
|
|
284
|
+
sorted_iterable = ASyncSorter(some_async_iterable, key=lambda x: x.value)
|
|
285
|
+
|
|
286
|
+
# or use the alias
|
|
287
|
+
import a_sync
|
|
288
|
+
|
|
289
|
+
sorted_iterable = a_sync.sort(some_async_iterable, key=lambda x: x.value)
|
|
290
|
+
|
|
291
|
+
# Asynchronous iteration
|
|
292
|
+
async for item in sorted_iterable:
|
|
293
|
+
...
|
|
294
|
+
|
|
295
|
+
# Synchronous iteration
|
|
296
|
+
for item in sorted_iterable:
|
|
297
|
+
...
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
See the [documentation](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.ASyncSorter) for more information.
|
|
301
|
+
|
|
302
|
+
## Other Helpful Modules
|
|
303
|
+
The stuff here is unrelated to the main purpose of ez-a-sync, but cool and useful nonetheless
|
|
304
|
+
|
|
305
|
+
### asyncio
|
|
306
|
+
|
|
307
|
+
The `ez-a-sync` library extends the functionality of Python's `asyncio` module with additional utilities to simplify asynchronous programming.
|
|
308
|
+
|
|
309
|
+
- **as_completed**: This function allows you to iterate over awaitables as they complete, similar to `asyncio.as_completed`. It supports both synchronous and asynchronous iteration. [Learn more about `as_completed`](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.asyncio.as_completed).
|
|
310
|
+
|
|
311
|
+
- **gather**: A utility to run multiple asynchronous operations concurrently and wait for all of them to complete. It is similar to `asyncio.gather` but integrates seamlessly with the `ez-a-sync` library. [Learn more about `gather`](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.asyncio.gather).
|
|
312
|
+
|
|
313
|
+
- **create_task**: A function to create a new task from a coroutine, similar to `asyncio.create_task`, but with additional features provided by `ez-a-sync`. [Learn more about `create_task`](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.asyncio.create_task).
|
|
314
|
+
|
|
315
|
+
- **as_completed**: This function allows you to iterate over awaitables as they complete, similar to `asyncio.as_completed`. It supports both synchronous and asynchronous iteration. [Learn more about `as_completed`](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.asyncio.as_completed).
|
|
316
|
+
|
|
317
|
+
These utilities enhance the standard `asyncio` module, providing more flexibility and control over asynchronous operations. For detailed documentation and examples, please refer to the [documentation](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.asyncio)
|
|
318
|
+
|
|
319
|
+
### future
|
|
320
|
+
The future module is something totally different.
|
|
321
|
+
TODO: short explainer of module value prop and use case
|
|
322
|
+
|
|
323
|
+
#### ASyncFuture
|
|
324
|
+
[documentation](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.future.ASyncFuture)
|
|
325
|
+
TODO: short explainers on ASyncFuture class
|
|
326
|
+
|
|
327
|
+
#### future decorator
|
|
328
|
+
[documentation](#https://bobthebuidler.github.io/ez-a-sync/source/a_sync.html#a_sync.future.future)
|
|
329
|
+
TODO: short explainers on future fn
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from typed_envs import EnvVarFactory
|
|
2
|
+
|
|
3
|
+
envs = EnvVarFactory("EZASYNC")
|
|
4
|
+
|
|
5
|
+
# We have some envs here to help you debug your custom class implementations
|
|
6
|
+
|
|
7
|
+
DEBUG_CLASS_NAME = envs.create_env("DEBUG_CLASS_NAME", str, default="", verbose=False)
|
|
8
|
+
"""str: The name of the class to debug.
|
|
9
|
+
|
|
10
|
+
If you're only interested in debugging a specific class, set this to the class name.
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
To debug a class named `MyClass`, set the environment variable:
|
|
14
|
+
|
|
15
|
+
.. code-block:: bash
|
|
16
|
+
|
|
17
|
+
export EZASYNC_DEBUG_CLASS_NAME=MyClass
|
|
18
|
+
|
|
19
|
+
See Also:
|
|
20
|
+
:func:`DEBUG_MODE` for enabling debug mode on all classes.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
DEBUG_MODE = envs.create_env(
|
|
24
|
+
"DEBUG_MODE", bool, default=bool(DEBUG_CLASS_NAME), verbose=False
|
|
25
|
+
)
|
|
26
|
+
"""bool: Enables debug mode on all classes.
|
|
27
|
+
|
|
28
|
+
Set this environment variable to `True` to enable debug mode on all classes.
|
|
29
|
+
If `DEBUG_CLASS_NAME` is set to a truthy value other than an empty string,
|
|
30
|
+
`DEBUG_MODE` will default to `True`.
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
To enable debug mode globally, set the environment variable:
|
|
34
|
+
|
|
35
|
+
.. code-block:: bash
|
|
36
|
+
|
|
37
|
+
export EZASYNC_DEBUG_MODE=True
|
|
38
|
+
|
|
39
|
+
If you have set `DEBUG_CLASS_NAME` to a specific class, `DEBUG_MODE` will
|
|
40
|
+
automatically be `True` unless `DEBUG_CLASS_NAME` is an empty string.
|
|
41
|
+
|
|
42
|
+
See Also:
|
|
43
|
+
:func:`DEBUG_CLASS_NAME` for debugging a specific class.
|
|
44
|
+
"""
|
|
@@ -8,17 +8,40 @@ that can operate in both synchronous and asynchronous contexts. Additionally, it
|
|
|
8
8
|
such as queues and locks, with extra functionality.
|
|
9
9
|
|
|
10
10
|
Modules and components included:
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- `
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
11
|
+
- :mod:`~aliases`, :mod:`~exceptions`, :mod:`~iter`, :mod:`~task`: Core modules of the library.
|
|
12
|
+
- :class:`~ASyncGenericBase`, :class:`~ASyncGenericSingleton`, :func:`~a_sync`: Base classes and decorators for dual-context execution.
|
|
13
|
+
- :class:`~ASyncCachedPropertyDescriptor`, :class:`~ASyncPropertyDescriptor`, `cached_property`, `property`: Property descriptors for async properties.
|
|
14
|
+
- :func:`~as_completed`, :func:`~create_task`, :func:`~gather`: Enhanced asyncio functions.
|
|
15
|
+
- Executors: :class:`~AsyncThreadPoolExecutor`, :class:`~AsyncProcessPoolExecutor`, :class:`~PruningThreadPoolExecutor` for async execution.
|
|
16
|
+
- Iterators: :class:`~ASyncFilter`, :class:`~ASyncSorter`, :class:`~ASyncIterable`, :class:`~ASyncIterator` for async iteration.
|
|
17
|
+
- Utilities: :func:`~all`, :func:`~any`, :func:`~as_yielded`, :func:`~exhaust_iterator`, :func:`~exhaust_iterators` for async utilities.
|
|
18
|
+
- :func:`~apply_semaphore`: Function to apply semaphores to coroutines.
|
|
19
19
|
|
|
20
20
|
Alias for backward compatibility:
|
|
21
|
-
-
|
|
21
|
+
- :class:`~ASyncBase` is an alias for :class:`~ASyncGenericBase`, which will be removed eventually, probably in version 0.1.0.
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
Using the `@a_sync` decorator:
|
|
25
|
+
>>> from a_sync import a_sync
|
|
26
|
+
>>> @a_sync
|
|
27
|
+
... async def my_function():
|
|
28
|
+
... return "Hello, World!"
|
|
29
|
+
>>> result = await my_function()
|
|
30
|
+
>>> print(result)
|
|
31
|
+
|
|
32
|
+
Using `ASyncGenericBase` for dual-context classes:
|
|
33
|
+
>>> from a_sync import ASyncGenericBase
|
|
34
|
+
>>> class MyClass(ASyncGenericBase):
|
|
35
|
+
... async def my_method(self):
|
|
36
|
+
... return "Hello from MyClass"
|
|
37
|
+
>>> obj = MyClass()
|
|
38
|
+
>>> result = await obj.my_method()
|
|
39
|
+
>>> print(result)
|
|
40
|
+
|
|
41
|
+
See Also:
|
|
42
|
+
- :mod:`a_sync.a_sync`: Contains the core classes and decorators.
|
|
43
|
+
- :mod:`a_sync.asyncio`: Provides enhanced asyncio functions.
|
|
44
|
+
- :mod:`a_sync.primitives`: Includes modified versions of standard asyncio primitives.
|
|
22
45
|
"""
|
|
23
46
|
|
|
24
47
|
from a_sync import aliases, exceptions, iter, task
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module defines smart future and task utilities for the a_sync library.
|
|
3
3
|
These utilities provide enhanced functionality for managing asynchronous tasks and futures,
|
|
4
|
-
including
|
|
4
|
+
including a custom task factory for creating :class:`~SmartTask` instances and a shielding mechanism
|
|
5
|
+
to protect tasks from cancellation.
|
|
5
6
|
"""
|
|
6
7
|
|
|
7
8
|
import asyncio
|
|
@@ -37,6 +38,27 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
37
38
|
def __await__(self: Union["SmartFuture", "SmartTask"]) -> Generator[Any, None, T]:
|
|
38
39
|
"""
|
|
39
40
|
Await the smart future or task, handling waiters and logging.
|
|
41
|
+
|
|
42
|
+
Yields:
|
|
43
|
+
The result of the future or task.
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
RuntimeError: If await wasn't used with future.
|
|
47
|
+
|
|
48
|
+
Example:
|
|
49
|
+
Awaiting a SmartFuture:
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
future = SmartFuture()
|
|
53
|
+
result = await future
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Awaiting a SmartTask:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
task = SmartTask(coro=my_coroutine())
|
|
60
|
+
result = await task
|
|
61
|
+
```
|
|
40
62
|
"""
|
|
41
63
|
if self.done():
|
|
42
64
|
return self.result() # May raise too.
|
|
@@ -54,6 +76,12 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
54
76
|
# NOTE: we check .done() because the callback may not have ran yet and its very lightweight
|
|
55
77
|
"""
|
|
56
78
|
Get the number of waiters currently awaiting the future or task.
|
|
79
|
+
|
|
80
|
+
Example:
|
|
81
|
+
```python
|
|
82
|
+
future = SmartFuture()
|
|
83
|
+
print(future.num_waiters)
|
|
84
|
+
```
|
|
57
85
|
"""
|
|
58
86
|
if self.done():
|
|
59
87
|
# if there are any waiters left, there won't be once the event loop runs once
|
|
@@ -67,6 +95,9 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
67
95
|
Callback to clean up waiters when a waiter task is done.
|
|
68
96
|
|
|
69
97
|
Removes the waiter from _waiters, and _queue._futs if applicable
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
waiter: The waiter task to clean up.
|
|
70
101
|
"""
|
|
71
102
|
if not self.done():
|
|
72
103
|
self._waiters.remove(waiter)
|
|
@@ -84,8 +115,16 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
|
|
|
84
115
|
"""
|
|
85
116
|
A smart future that tracks waiters and integrates with a smart processing queue.
|
|
86
117
|
|
|
87
|
-
Inherits from both _SmartFutureMixin and asyncio.Future
|
|
118
|
+
Inherits from both :class:`_SmartFutureMixin` and :class:`asyncio.Future`, providing additional functionality
|
|
88
119
|
for tracking waiters and integrating with a smart processing queue.
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
Creating and awaiting a SmartFuture:
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
future = SmartFuture()
|
|
126
|
+
await future
|
|
127
|
+
```
|
|
89
128
|
"""
|
|
90
129
|
|
|
91
130
|
_queue = None
|
|
@@ -105,6 +144,11 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
|
|
|
105
144
|
queue: Optional; a smart processing queue.
|
|
106
145
|
key: Optional; a key identifying the future.
|
|
107
146
|
loop: Optional; the event loop.
|
|
147
|
+
|
|
148
|
+
Example:
|
|
149
|
+
```python
|
|
150
|
+
future = SmartFuture(queue=my_queue, key=my_key)
|
|
151
|
+
```
|
|
108
152
|
"""
|
|
109
153
|
super().__init__(loop=loop)
|
|
110
154
|
if queue:
|
|
@@ -125,8 +169,12 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
|
|
|
125
169
|
Args:
|
|
126
170
|
other: Another SmartFuture to compare with.
|
|
127
171
|
|
|
128
|
-
|
|
129
|
-
|
|
172
|
+
Example:
|
|
173
|
+
```python
|
|
174
|
+
future1 = SmartFuture()
|
|
175
|
+
future2 = SmartFuture()
|
|
176
|
+
print(future1 < future2)
|
|
177
|
+
```
|
|
130
178
|
"""
|
|
131
179
|
return self.num_waiters > other.num_waiters
|
|
132
180
|
|
|
@@ -138,7 +186,7 @@ def create_future(
|
|
|
138
186
|
loop: Optional[asyncio.AbstractEventLoop] = None,
|
|
139
187
|
) -> SmartFuture[V]:
|
|
140
188
|
"""
|
|
141
|
-
Create a SmartFuture instance.
|
|
189
|
+
Create a :class:`~SmartFuture` instance.
|
|
142
190
|
|
|
143
191
|
Args:
|
|
144
192
|
queue: Optional; a smart processing queue.
|
|
@@ -147,6 +195,13 @@ def create_future(
|
|
|
147
195
|
|
|
148
196
|
Returns:
|
|
149
197
|
A SmartFuture instance.
|
|
198
|
+
|
|
199
|
+
Example:
|
|
200
|
+
Creating a SmartFuture using the factory function:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
future = create_future(queue=my_queue, key=my_key)
|
|
204
|
+
```
|
|
150
205
|
"""
|
|
151
206
|
return SmartFuture(queue=queue, key=key, loop=loop or asyncio.get_event_loop())
|
|
152
207
|
|
|
@@ -155,8 +210,16 @@ class SmartTask(_SmartFutureMixin[T], asyncio.Task):
|
|
|
155
210
|
"""
|
|
156
211
|
A smart task that tracks waiters and integrates with a smart processing queue.
|
|
157
212
|
|
|
158
|
-
Inherits from both _SmartFutureMixin and asyncio.Task
|
|
213
|
+
Inherits from both :class:`_SmartFutureMixin` and :class:`asyncio.Task`, providing additional functionality
|
|
159
214
|
for tracking waiters and integrating with a smart processing queue.
|
|
215
|
+
|
|
216
|
+
Example:
|
|
217
|
+
Creating and awaiting a SmartTask:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
task = SmartTask(coro=my_coroutine())
|
|
221
|
+
await task
|
|
222
|
+
```
|
|
160
223
|
"""
|
|
161
224
|
|
|
162
225
|
def __init__(
|
|
@@ -173,6 +236,11 @@ class SmartTask(_SmartFutureMixin[T], asyncio.Task):
|
|
|
173
236
|
coro: The coroutine to run in the task.
|
|
174
237
|
loop: Optional; the event loop.
|
|
175
238
|
name: Optional; the name of the task.
|
|
239
|
+
|
|
240
|
+
Example:
|
|
241
|
+
```python
|
|
242
|
+
task = SmartTask(coro=my_coroutine(), name="my_task")
|
|
243
|
+
```
|
|
176
244
|
"""
|
|
177
245
|
super().__init__(coro, loop=loop, name=name)
|
|
178
246
|
self._waiters: Set["asyncio.Task[T]"] = set()
|
|
@@ -193,6 +261,17 @@ def smart_task_factory(
|
|
|
193
261
|
|
|
194
262
|
Returns:
|
|
195
263
|
A SmartTask instance running the provided coroutine.
|
|
264
|
+
|
|
265
|
+
Example:
|
|
266
|
+
Using the smart task factory to create a SmartTask:
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
loop = asyncio.get_event_loop()
|
|
270
|
+
task = smart_task_factory(loop, my_coroutine())
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
See Also:
|
|
274
|
+
- :func:`set_smart_task_factory`
|
|
196
275
|
"""
|
|
197
276
|
return SmartTask(coro, loop=loop)
|
|
198
277
|
|
|
@@ -203,6 +282,16 @@ def set_smart_task_factory(loop: asyncio.AbstractEventLoop = None) -> None:
|
|
|
203
282
|
|
|
204
283
|
Args:
|
|
205
284
|
loop: Optional; the event loop. If None, the current event loop is used.
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
Setting the smart task factory for the current event loop:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
set_smart_task_factory()
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
See Also:
|
|
294
|
+
- :func:`smart_task_factory`
|
|
206
295
|
"""
|
|
207
296
|
if loop is None:
|
|
208
297
|
loop = a_sync.asyncio.get_event_loop()
|
|
@@ -241,6 +330,16 @@ def shield(
|
|
|
241
330
|
Args:
|
|
242
331
|
arg: The awaitable to shield from cancellation.
|
|
243
332
|
loop: Optional; the event loop. Deprecated since Python 3.8.
|
|
333
|
+
|
|
334
|
+
Example:
|
|
335
|
+
Using shield to protect a coroutine from cancellation:
|
|
336
|
+
|
|
337
|
+
```python
|
|
338
|
+
result = await shield(my_coroutine())
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
See Also:
|
|
342
|
+
- :func:`asyncio.shield`
|
|
244
343
|
"""
|
|
245
344
|
if loop is not None:
|
|
246
345
|
warnings.warn(
|
|
@@ -1,7 +1,60 @@
|
|
|
1
1
|
"""
|
|
2
|
-
This module provides type definitions and type-related utilities for the a_sync library.
|
|
3
|
-
|
|
4
|
-
to enhance type checking and provide better IDE support.
|
|
2
|
+
This module provides type definitions and type-related utilities for the `a_sync` library.
|
|
3
|
+
|
|
4
|
+
It includes various type aliases and protocols used throughout the library to enhance type checking and provide better IDE support.
|
|
5
|
+
|
|
6
|
+
Examples:
|
|
7
|
+
The following examples demonstrate how to use some of the type aliases and protocols defined in this module.
|
|
8
|
+
|
|
9
|
+
Example of a function that can return either an awaitable or a direct value:
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from a_sync._typing import MaybeAwaitable
|
|
13
|
+
from typing import Awaitable
|
|
14
|
+
|
|
15
|
+
async def process_data(data: MaybeAwaitable[int]) -> int:
|
|
16
|
+
if isinstance(data, Awaitable):
|
|
17
|
+
return await data
|
|
18
|
+
return data
|
|
19
|
+
|
|
20
|
+
# Usage
|
|
21
|
+
import asyncio
|
|
22
|
+
|
|
23
|
+
async def main():
|
|
24
|
+
result = await process_data(asyncio.sleep(1, result=42))
|
|
25
|
+
print(result) # Output: 42
|
|
26
|
+
|
|
27
|
+
result = await process_data(42)
|
|
28
|
+
print(result) # Output: 42
|
|
29
|
+
|
|
30
|
+
asyncio.run(main())
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Example of defining a coroutine function type:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from a_sync._typing import CoroFn
|
|
37
|
+
|
|
38
|
+
async def async_function(x: int) -> str:
|
|
39
|
+
return str(x)
|
|
40
|
+
|
|
41
|
+
coro_fn: CoroFn[[int], str] = async_function
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Example of defining a synchronous function type:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from a_sync._typing import SyncFn
|
|
48
|
+
|
|
49
|
+
def sync_function(x: int) -> str:
|
|
50
|
+
return str(x)
|
|
51
|
+
|
|
52
|
+
sync_fn: SyncFn[[int], str] = sync_function
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
See Also:
|
|
56
|
+
- :mod:`typing`
|
|
57
|
+
- :mod:`asyncio`
|
|
5
58
|
"""
|
|
6
59
|
|
|
7
60
|
import asyncio
|