ez-a-sync 0.22.15__tar.gz → 0.23.0__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.23.0}/.github/workflows/pytest.yaml +5 -3
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/release.yaml +2 -2
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.gitignore +5 -1
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/Makefile +3 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/PKG-INFO +2 -1
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/README.md +132 -0
- ez_a_sync-0.23.0/a_sync/ENVIRONMENT_VARIABLES.py +44 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/__init__.py +32 -11
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/_smart.py +162 -10
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/_typing.py +63 -3
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/_descriptor.py +148 -23
- ez_a_sync-0.23.0/a_sync/a_sync/_flags.c +7452 -0
- ez_a_sync-0.23.0/a_sync/a_sync/_flags.pyi +61 -0
- ez_a_sync-0.23.0/a_sync/a_sync/_flags.pyx +143 -0
- ez_a_sync-0.23.0/a_sync/a_sync/_helpers.py +91 -0
- ez_a_sync-0.23.0/a_sync/a_sync/_kwargs.c +7900 -0
- ez_a_sync-0.23.0/a_sync/a_sync/_kwargs.pyi +52 -0
- ez_a_sync-0.22.15/a_sync/a_sync/_kwargs.py → ez_a_sync-0.23.0/a_sync/a_sync/_kwargs.pyx +30 -6
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/_meta.py +35 -6
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/abstract.py +57 -9
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/base.py +1 -1
- ez_a_sync-0.23.0/a_sync/a_sync/config.py +172 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/decorator.py +221 -37
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/function.py +341 -48
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/method.py +246 -52
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/__init__.py +39 -1
- ez_a_sync-0.23.0/a_sync/a_sync/modifiers/cache/__init__.py +159 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/cache/memory.py +50 -6
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/limiter.py +55 -6
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/manager.py +131 -20
- ez_a_sync-0.23.0/a_sync/a_sync/modifiers/semaphores.py +175 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/property.py +5 -0
- ez_a_sync-0.23.0/a_sync/a_sync/singleton.py +63 -0
- ez_a_sync-0.23.0/a_sync/asyncio/__init__.py +154 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/asyncio/as_completed.py +46 -40
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/asyncio/create_task.py +46 -13
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/asyncio/gather.py +72 -25
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/exceptions.py +191 -11
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/executor.py +105 -19
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/future.py +689 -29
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/iter.py +111 -13
- ez_a_sync-0.23.0/a_sync/primitives/__init__.py +53 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/_debug.py +59 -5
- ez_a_sync-0.23.0/a_sync/primitives/_loggable.py +72 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/counter.py +79 -10
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/prio_semaphore.py +93 -8
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/semaphore.py +74 -21
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/queue.py +65 -26
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/task.py +53 -17
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/utils/iterators.py +52 -16
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/conf.py +5 -0
- ez_a_sync-0.23.0/docs/index.rst +48 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/PKG-INFO +2 -1
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/SOURCES.txt +7 -2
- ez_a_sync-0.23.0/ez_a_sync.egg-info/not-zip-safe +1 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/requires.txt +1 -0
- ez_a_sync-0.23.0/pyproject.yaml +5 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/requirements-dev.txt +2 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/requirements.txt +1 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/setup.py +5 -3
- ez_a_sync-0.23.0/tests/executor.py +240 -0
- ez_a_sync-0.23.0/tests/test_abstract.py +35 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_base.py +198 -2
- ez_a_sync-0.23.0/tests/test_executor.py +71 -0
- ez_a_sync-0.23.0/tests/test_singleton.py +37 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/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/_flags.py +0 -67
- ez_a_sync-0.22.15/a_sync/a_sync/_helpers.py +0 -59
- ez_a_sync-0.22.15/a_sync/a_sync/config.py +0 -107
- 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/__init__.py +0 -30
- ez_a_sync-0.22.15/a_sync/primitives/_loggable.py +0 -39
- ez_a_sync-0.22.15/docs/index.rst +0 -20
- ez_a_sync-0.22.15/pyproject.yaml +0 -2
- 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_executor.py +0 -35
- ez_a_sync-0.22.15/tests/test_singleton.py +0 -25
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.coverage +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/black.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/codeql.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/docs.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/mypy.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.sourcery.yaml +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/LICENSE.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/TODO +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/aliases.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/asyncio/utils.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/event.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/py.typed +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/sphinx/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/sphinx/ext.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/utils/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/Makefile +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/alabaster.css +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/basic.css +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/custom.css +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/doctools.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/documentation_options.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/file.png +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/language_data.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/minus.png +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/plus.png +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/pygments.css +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/searchtools.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/sphinx_highlight.js +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/make.bat +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/dependency_links.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/top_level.txt +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/setup.cfg +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/__init__.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/conftest.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/fixtures.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_as_completed.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_cache.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_decorator.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_future.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_gather.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_helpers.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_iter.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_limiter.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_meta.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_modified.py +0 -0
- {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_semaphore.py +0 -0
|
@@ -38,10 +38,12 @@ jobs:
|
|
|
38
38
|
python-version: ${{ matrix.pyversion }}
|
|
39
39
|
|
|
40
40
|
- name: Install dependencies
|
|
41
|
+
run: pip install -r requirements.txt -r requirements-dev.txt
|
|
42
|
+
|
|
43
|
+
- name: Install ez-a-sync
|
|
41
44
|
run: |
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
pip install -r requirements-dev.txt
|
|
45
|
+
python setup.py build_ext --inplace
|
|
46
|
+
python setup.py install
|
|
45
47
|
|
|
46
48
|
- name: Run test suite
|
|
47
49
|
run: pytest
|
|
@@ -21,11 +21,11 @@ jobs:
|
|
|
21
21
|
- name: Install dependencies
|
|
22
22
|
run: |
|
|
23
23
|
python -m pip install --upgrade pip
|
|
24
|
-
pip install setuptools wheel twine
|
|
24
|
+
pip install setuptools wheel twine cython
|
|
25
25
|
- name: Build and publish
|
|
26
26
|
env:
|
|
27
27
|
TWINE_USERNAME: __token__
|
|
28
28
|
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
|
29
29
|
run: |
|
|
30
|
-
python setup.py sdist
|
|
30
|
+
python setup.py sdist
|
|
31
31
|
twine upload dist/*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ez-a-sync
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
4
4
|
Summary: A library that makes it easy to define objects that can be used for both sync and async use cases.
|
|
5
5
|
Home-page: https://github.com/BobTheBuidler/a-sync
|
|
6
6
|
Author: BobTheBuidler
|
|
@@ -11,5 +11,6 @@ License-File: LICENSE.txt
|
|
|
11
11
|
Requires-Dist: aiolimiter==1.0.0
|
|
12
12
|
Requires-Dist: async_lru_threadsafe==2.0.4
|
|
13
13
|
Requires-Dist: async_property==0.2.1
|
|
14
|
+
Requires-Dist: Cython>=3.0.11
|
|
14
15
|
Requires-Dist: typed_envs>=0.0.2
|
|
15
16
|
Requires-Dist: typing_extensions>=4.1.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 non-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:`~a_sync.aliases`, :mod:`~a_sync.exceptions`, :mod:`~a_sync.iter`, :mod:`~a_sync.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:`~ASyncIterable`, :class:`~ASyncIterator`, :class:`~filter`, :class:`~sorted` for async iteration.
|
|
17
|
+
- Utilities: :func:`~all`, :func:`~any`, :func:`~as_yielded` for async utilities.
|
|
18
|
+
- :func:`~a_sync.a_sync.modifiers.semaphores.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
|
|
@@ -68,8 +91,6 @@ __all__ = [
|
|
|
68
91
|
"all",
|
|
69
92
|
"any",
|
|
70
93
|
"as_yielded",
|
|
71
|
-
"exhaust_iterator",
|
|
72
|
-
"exhaust_iterators",
|
|
73
94
|
"map",
|
|
74
95
|
# classes
|
|
75
96
|
"ASyncIterable",
|
|
@@ -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
|
|
@@ -28,6 +29,26 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
28
29
|
Mixin class that provides common functionality for smart futures and tasks.
|
|
29
30
|
|
|
30
31
|
This mixin provides methods for managing waiters and integrating with a smart processing queue.
|
|
32
|
+
It uses weak references to manage resources efficiently.
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
Creating a SmartFuture and awaiting it:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
future = SmartFuture()
|
|
39
|
+
result = await future
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Creating a SmartTask and awaiting it:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
task = SmartTask(coro=my_coroutine())
|
|
46
|
+
result = await task
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
See Also:
|
|
50
|
+
- :class:`SmartFuture`
|
|
51
|
+
- :class:`SmartTask`
|
|
31
52
|
"""
|
|
32
53
|
|
|
33
54
|
_queue: Optional["SmartProcessingQueue[Any, Any, T]"] = None
|
|
@@ -37,6 +58,27 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
37
58
|
def __await__(self: Union["SmartFuture", "SmartTask"]) -> Generator[Any, None, T]:
|
|
38
59
|
"""
|
|
39
60
|
Await the smart future or task, handling waiters and logging.
|
|
61
|
+
|
|
62
|
+
Yields:
|
|
63
|
+
The result of the future or task.
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
RuntimeError: If await wasn't used with future.
|
|
67
|
+
|
|
68
|
+
Example:
|
|
69
|
+
Awaiting a SmartFuture:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
future = SmartFuture()
|
|
73
|
+
result = await future
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Awaiting a SmartTask:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
task = SmartTask(coro=my_coroutine())
|
|
80
|
+
result = await task
|
|
81
|
+
```
|
|
40
82
|
"""
|
|
41
83
|
if self.done():
|
|
42
84
|
return self.result() # May raise too.
|
|
@@ -51,12 +93,22 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
51
93
|
|
|
52
94
|
@property
|
|
53
95
|
def num_waiters(self: Union["SmartFuture", "SmartTask"]) -> int:
|
|
54
|
-
# NOTE: we check .done() because the callback may not have ran yet and its very lightweight
|
|
55
96
|
"""
|
|
56
97
|
Get the number of waiters currently awaiting the future or task.
|
|
98
|
+
|
|
99
|
+
This property checks if the future or task is done to ensure accurate counting
|
|
100
|
+
of waiters, as the callback may not have run yet.
|
|
101
|
+
|
|
102
|
+
Example:
|
|
103
|
+
```python
|
|
104
|
+
future = SmartFuture()
|
|
105
|
+
print(future.num_waiters)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
See Also:
|
|
109
|
+
- :meth:`_waiter_done_cleanup_callback`
|
|
57
110
|
"""
|
|
58
111
|
if self.done():
|
|
59
|
-
# if there are any waiters left, there won't be once the event loop runs once
|
|
60
112
|
return 0
|
|
61
113
|
return sum(getattr(waiter, "num_waiters", 1) or 1 for waiter in self._waiters)
|
|
62
114
|
|
|
@@ -66,7 +118,13 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
66
118
|
"""
|
|
67
119
|
Callback to clean up waiters when a waiter task is done.
|
|
68
120
|
|
|
69
|
-
Removes the waiter from _waiters, and _queue._futs if applicable
|
|
121
|
+
Removes the waiter from _waiters, and _queue._futs if applicable.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
waiter: The waiter task to clean up.
|
|
125
|
+
|
|
126
|
+
Example:
|
|
127
|
+
Automatically called when a waiter task completes.
|
|
70
128
|
"""
|
|
71
129
|
if not self.done():
|
|
72
130
|
self._waiters.remove(waiter)
|
|
@@ -74,6 +132,8 @@ class _SmartFutureMixin(Generic[T]):
|
|
|
74
132
|
def _self_done_cleanup_callback(self: Union["SmartFuture", "SmartTask"]) -> None:
|
|
75
133
|
"""
|
|
76
134
|
Callback to clean up waiters and remove the future from the queue when done.
|
|
135
|
+
|
|
136
|
+
This method clears all waiters and removes the future from the associated queue.
|
|
77
137
|
"""
|
|
78
138
|
self._waiters.clear()
|
|
79
139
|
if queue := self._queue:
|
|
@@ -84,8 +144,20 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
|
|
|
84
144
|
"""
|
|
85
145
|
A smart future that tracks waiters and integrates with a smart processing queue.
|
|
86
146
|
|
|
87
|
-
Inherits from both _SmartFutureMixin and asyncio.Future
|
|
147
|
+
Inherits from both :class:`_SmartFutureMixin` and :class:`asyncio.Future`, providing additional functionality
|
|
88
148
|
for tracking waiters and integrating with a smart processing queue.
|
|
149
|
+
|
|
150
|
+
Example:
|
|
151
|
+
Creating and awaiting a SmartFuture:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
future = SmartFuture()
|
|
155
|
+
await future
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
See Also:
|
|
159
|
+
- :class:`_SmartFutureMixin`
|
|
160
|
+
- :class:`asyncio.Future`
|
|
89
161
|
"""
|
|
90
162
|
|
|
91
163
|
_queue = None
|
|
@@ -105,6 +177,14 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
|
|
|
105
177
|
queue: Optional; a smart processing queue.
|
|
106
178
|
key: Optional; a key identifying the future.
|
|
107
179
|
loop: Optional; the event loop.
|
|
180
|
+
|
|
181
|
+
Example:
|
|
182
|
+
```python
|
|
183
|
+
future = SmartFuture(queue=my_queue, key=my_key)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
See Also:
|
|
187
|
+
- :class:`SmartProcessingQueue`
|
|
108
188
|
"""
|
|
109
189
|
super().__init__(loop=loop)
|
|
110
190
|
if queue:
|
|
@@ -125,8 +205,15 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
|
|
|
125
205
|
Args:
|
|
126
206
|
other: Another SmartFuture to compare with.
|
|
127
207
|
|
|
128
|
-
|
|
129
|
-
|
|
208
|
+
Example:
|
|
209
|
+
```python
|
|
210
|
+
future1 = SmartFuture()
|
|
211
|
+
future2 = SmartFuture()
|
|
212
|
+
print(future1 < future2)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
See Also:
|
|
216
|
+
- :meth:`num_waiters`
|
|
130
217
|
"""
|
|
131
218
|
return self.num_waiters > other.num_waiters
|
|
132
219
|
|
|
@@ -138,7 +225,7 @@ def create_future(
|
|
|
138
225
|
loop: Optional[asyncio.AbstractEventLoop] = None,
|
|
139
226
|
) -> SmartFuture[V]:
|
|
140
227
|
"""
|
|
141
|
-
Create a SmartFuture instance.
|
|
228
|
+
Create a :class:`~SmartFuture` instance.
|
|
142
229
|
|
|
143
230
|
Args:
|
|
144
231
|
queue: Optional; a smart processing queue.
|
|
@@ -147,6 +234,16 @@ def create_future(
|
|
|
147
234
|
|
|
148
235
|
Returns:
|
|
149
236
|
A SmartFuture instance.
|
|
237
|
+
|
|
238
|
+
Example:
|
|
239
|
+
Creating a SmartFuture using the factory function:
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
future = create_future(queue=my_queue, key=my_key)
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
See Also:
|
|
246
|
+
- :class:`SmartFuture`
|
|
150
247
|
"""
|
|
151
248
|
return SmartFuture(queue=queue, key=key, loop=loop or asyncio.get_event_loop())
|
|
152
249
|
|
|
@@ -155,8 +252,20 @@ class SmartTask(_SmartFutureMixin[T], asyncio.Task):
|
|
|
155
252
|
"""
|
|
156
253
|
A smart task that tracks waiters and integrates with a smart processing queue.
|
|
157
254
|
|
|
158
|
-
Inherits from both _SmartFutureMixin and asyncio.Task
|
|
255
|
+
Inherits from both :class:`_SmartFutureMixin` and :class:`asyncio.Task`, providing additional functionality
|
|
159
256
|
for tracking waiters and integrating with a smart processing queue.
|
|
257
|
+
|
|
258
|
+
Example:
|
|
259
|
+
Creating and awaiting a SmartTask:
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
task = SmartTask(coro=my_coroutine())
|
|
263
|
+
await task
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
See Also:
|
|
267
|
+
- :class:`_SmartFutureMixin`
|
|
268
|
+
- :class:`asyncio.Task`
|
|
160
269
|
"""
|
|
161
270
|
|
|
162
271
|
def __init__(
|
|
@@ -173,6 +282,14 @@ class SmartTask(_SmartFutureMixin[T], asyncio.Task):
|
|
|
173
282
|
coro: The coroutine to run in the task.
|
|
174
283
|
loop: Optional; the event loop.
|
|
175
284
|
name: Optional; the name of the task.
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
```python
|
|
288
|
+
task = SmartTask(coro=my_coroutine(), name="my_task")
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
See Also:
|
|
292
|
+
- :func:`asyncio.create_task`
|
|
176
293
|
"""
|
|
177
294
|
super().__init__(coro, loop=loop, name=name)
|
|
178
295
|
self._waiters: Set["asyncio.Task[T]"] = set()
|
|
@@ -193,6 +310,18 @@ def smart_task_factory(
|
|
|
193
310
|
|
|
194
311
|
Returns:
|
|
195
312
|
A SmartTask instance running the provided coroutine.
|
|
313
|
+
|
|
314
|
+
Example:
|
|
315
|
+
Using the smart task factory to create a SmartTask:
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
loop = asyncio.get_event_loop()
|
|
319
|
+
task = smart_task_factory(loop, my_coroutine())
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
See Also:
|
|
323
|
+
- :func:`set_smart_task_factory`
|
|
324
|
+
- :class:`SmartTask`
|
|
196
325
|
"""
|
|
197
326
|
return SmartTask(coro, loop=loop)
|
|
198
327
|
|
|
@@ -203,6 +332,16 @@ def set_smart_task_factory(loop: asyncio.AbstractEventLoop = None) -> None:
|
|
|
203
332
|
|
|
204
333
|
Args:
|
|
205
334
|
loop: Optional; the event loop. If None, the current event loop is used.
|
|
335
|
+
|
|
336
|
+
Example:
|
|
337
|
+
Setting the smart task factory for the current event loop:
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
set_smart_task_factory()
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
See Also:
|
|
344
|
+
- :func:`smart_task_factory`
|
|
206
345
|
"""
|
|
207
346
|
if loop is None:
|
|
208
347
|
loop = a_sync.asyncio.get_event_loop()
|
|
@@ -211,7 +350,7 @@ def set_smart_task_factory(loop: asyncio.AbstractEventLoop = None) -> None:
|
|
|
211
350
|
|
|
212
351
|
def shield(
|
|
213
352
|
arg: Awaitable[T], *, loop: Optional[asyncio.AbstractEventLoop] = None
|
|
214
|
-
) -> SmartFuture[T]:
|
|
353
|
+
) -> Union[SmartFuture[T], asyncio.Future]:
|
|
215
354
|
"""
|
|
216
355
|
Wait for a future, shielding it from cancellation.
|
|
217
356
|
|
|
@@ -241,6 +380,19 @@ def shield(
|
|
|
241
380
|
Args:
|
|
242
381
|
arg: The awaitable to shield from cancellation.
|
|
243
382
|
loop: Optional; the event loop. Deprecated since Python 3.8.
|
|
383
|
+
|
|
384
|
+
Returns:
|
|
385
|
+
A :class:`SmartFuture` or :class:`asyncio.Future` instance.
|
|
386
|
+
|
|
387
|
+
Example:
|
|
388
|
+
Using shield to protect a coroutine from cancellation:
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
result = await shield(my_coroutine())
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
See Also:
|
|
395
|
+
- :func:`asyncio.shield`
|
|
244
396
|
"""
|
|
245
397
|
if loop is not None:
|
|
246
398
|
warnings.warn(
|
|
@@ -1,7 +1,67 @@
|
|
|
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 using `CoroFn` with `ParamSpec`:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from a_sync._typing import CoroFn
|
|
37
|
+
from typing_extensions import ParamSpec
|
|
38
|
+
from typing import Awaitable
|
|
39
|
+
|
|
40
|
+
P = ParamSpec("P")
|
|
41
|
+
|
|
42
|
+
async def async_function(x: int) -> str:
|
|
43
|
+
return str(x)
|
|
44
|
+
|
|
45
|
+
coro_fn: CoroFn[[int], str] = async_function
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Example of defining a synchronous function type using `SyncFn` with `ParamSpec`:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from a_sync._typing import SyncFn
|
|
52
|
+
from typing_extensions import ParamSpec
|
|
53
|
+
|
|
54
|
+
P = ParamSpec("P")
|
|
55
|
+
|
|
56
|
+
def sync_function(x: int) -> str:
|
|
57
|
+
return str(x)
|
|
58
|
+
|
|
59
|
+
sync_fn: SyncFn[[int], str] = sync_function
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
See Also:
|
|
63
|
+
- :mod:`typing`
|
|
64
|
+
- :mod:`asyncio`
|
|
5
65
|
"""
|
|
6
66
|
|
|
7
67
|
import asyncio
|