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.

Files changed (130) hide show
  1. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/pytest.yaml +5 -3
  2. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/release.yaml +2 -2
  3. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.gitignore +5 -1
  4. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/Makefile +3 -0
  5. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/PKG-INFO +2 -1
  6. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/README.md +132 -0
  7. ez_a_sync-0.23.0/a_sync/ENVIRONMENT_VARIABLES.py +44 -0
  8. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/__init__.py +32 -11
  9. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/_smart.py +162 -10
  10. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/_typing.py +63 -3
  11. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/_descriptor.py +148 -23
  12. ez_a_sync-0.23.0/a_sync/a_sync/_flags.c +7452 -0
  13. ez_a_sync-0.23.0/a_sync/a_sync/_flags.pyi +61 -0
  14. ez_a_sync-0.23.0/a_sync/a_sync/_flags.pyx +143 -0
  15. ez_a_sync-0.23.0/a_sync/a_sync/_helpers.py +91 -0
  16. ez_a_sync-0.23.0/a_sync/a_sync/_kwargs.c +7900 -0
  17. ez_a_sync-0.23.0/a_sync/a_sync/_kwargs.pyi +52 -0
  18. 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
  19. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/_meta.py +35 -6
  20. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/abstract.py +57 -9
  21. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/base.py +1 -1
  22. ez_a_sync-0.23.0/a_sync/a_sync/config.py +172 -0
  23. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/decorator.py +221 -37
  24. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/function.py +341 -48
  25. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/method.py +246 -52
  26. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/__init__.py +39 -1
  27. ez_a_sync-0.23.0/a_sync/a_sync/modifiers/cache/__init__.py +159 -0
  28. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/cache/memory.py +50 -6
  29. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/limiter.py +55 -6
  30. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/manager.py +131 -20
  31. ez_a_sync-0.23.0/a_sync/a_sync/modifiers/semaphores.py +175 -0
  32. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/property.py +5 -0
  33. ez_a_sync-0.23.0/a_sync/a_sync/singleton.py +63 -0
  34. ez_a_sync-0.23.0/a_sync/asyncio/__init__.py +154 -0
  35. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/asyncio/as_completed.py +46 -40
  36. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/asyncio/create_task.py +46 -13
  37. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/asyncio/gather.py +72 -25
  38. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/exceptions.py +191 -11
  39. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/executor.py +105 -19
  40. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/future.py +689 -29
  41. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/iter.py +111 -13
  42. ez_a_sync-0.23.0/a_sync/primitives/__init__.py +53 -0
  43. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/_debug.py +59 -5
  44. ez_a_sync-0.23.0/a_sync/primitives/_loggable.py +72 -0
  45. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/counter.py +79 -10
  46. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/prio_semaphore.py +93 -8
  47. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/semaphore.py +74 -21
  48. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/queue.py +65 -26
  49. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/task.py +53 -17
  50. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/utils/iterators.py +52 -16
  51. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/conf.py +5 -0
  52. ez_a_sync-0.23.0/docs/index.rst +48 -0
  53. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/PKG-INFO +2 -1
  54. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/SOURCES.txt +7 -2
  55. ez_a_sync-0.23.0/ez_a_sync.egg-info/not-zip-safe +1 -0
  56. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/requires.txt +1 -0
  57. ez_a_sync-0.23.0/pyproject.yaml +5 -0
  58. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/requirements-dev.txt +2 -0
  59. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/requirements.txt +1 -0
  60. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/setup.py +5 -3
  61. ez_a_sync-0.23.0/tests/executor.py +240 -0
  62. ez_a_sync-0.23.0/tests/test_abstract.py +35 -0
  63. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_base.py +198 -2
  64. ez_a_sync-0.23.0/tests/test_executor.py +71 -0
  65. ez_a_sync-0.23.0/tests/test_singleton.py +37 -0
  66. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_task.py +45 -17
  67. ez_a_sync-0.22.15/a_sync/ENVIRONMENT_VARIABLES.py +0 -13
  68. ez_a_sync-0.22.15/a_sync/a_sync/_flags.py +0 -67
  69. ez_a_sync-0.22.15/a_sync/a_sync/_helpers.py +0 -59
  70. ez_a_sync-0.22.15/a_sync/a_sync/config.py +0 -107
  71. ez_a_sync-0.22.15/a_sync/a_sync/modifiers/cache/__init__.py +0 -89
  72. ez_a_sync-0.22.15/a_sync/a_sync/modifiers/semaphores.py +0 -102
  73. ez_a_sync-0.22.15/a_sync/a_sync/singleton.py +0 -37
  74. ez_a_sync-0.22.15/a_sync/asyncio/__init__.py +0 -13
  75. ez_a_sync-0.22.15/a_sync/primitives/__init__.py +0 -30
  76. ez_a_sync-0.22.15/a_sync/primitives/_loggable.py +0 -39
  77. ez_a_sync-0.22.15/docs/index.rst +0 -20
  78. ez_a_sync-0.22.15/pyproject.yaml +0 -2
  79. ez_a_sync-0.22.15/tests/executor.py +0 -114
  80. ez_a_sync-0.22.15/tests/test_abstract.py +0 -20
  81. ez_a_sync-0.22.15/tests/test_executor.py +0 -35
  82. ez_a_sync-0.22.15/tests/test_singleton.py +0 -25
  83. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.coverage +0 -0
  84. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/black.yaml +0 -0
  85. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/codeql.yaml +0 -0
  86. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/docs.yaml +0 -0
  87. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.github/workflows/mypy.yaml +0 -0
  88. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/.sourcery.yaml +0 -0
  89. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/LICENSE.txt +0 -0
  90. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/TODO +0 -0
  91. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/a_sync/__init__.py +0 -0
  92. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/aliases.py +0 -0
  93. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/asyncio/utils.py +0 -0
  94. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/__init__.py +0 -0
  95. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/primitives/locks/event.py +0 -0
  96. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/py.typed +0 -0
  97. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/sphinx/__init__.py +0 -0
  98. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/sphinx/ext.py +0 -0
  99. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/a_sync/utils/__init__.py +0 -0
  100. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/Makefile +0 -0
  101. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/alabaster.css +0 -0
  102. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/basic.css +0 -0
  103. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/custom.css +0 -0
  104. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/doctools.js +0 -0
  105. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/documentation_options.js +0 -0
  106. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/file.png +0 -0
  107. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/language_data.js +0 -0
  108. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/minus.png +0 -0
  109. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/plus.png +0 -0
  110. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/pygments.css +0 -0
  111. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/searchtools.js +0 -0
  112. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/_build/html/_static/sphinx_highlight.js +0 -0
  113. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/docs/make.bat +0 -0
  114. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/dependency_links.txt +0 -0
  115. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/top_level.txt +0 -0
  116. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/setup.cfg +0 -0
  117. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/__init__.py +0 -0
  118. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/conftest.py +0 -0
  119. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/fixtures.py +0 -0
  120. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_as_completed.py +0 -0
  121. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_cache.py +0 -0
  122. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_decorator.py +0 -0
  123. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_future.py +0 -0
  124. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_gather.py +0 -0
  125. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_helpers.py +0 -0
  126. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_iter.py +0 -0
  127. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_limiter.py +0 -0
  128. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_meta.py +0 -0
  129. {ez_a_sync-0.22.15 → ez_a_sync-0.23.0}/tests/test_modified.py +0 -0
  130. {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
- pip install pytest
43
- pip install -r requirements.txt
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 bdist_wheel
30
+ python setup.py sdist
31
31
  twine upload dist/*
@@ -8,4 +8,8 @@ dist/
8
8
  .eggs/
9
9
  *.egg-info
10
10
  cache/**/*.json
11
- cache/**/*.pkl
11
+ cache/**/*.pkl
12
+ mypy_plugin_tests/mypy
13
+ mypy_plugin_tests/venv
14
+ *.c
15
+ *.so
@@ -6,3 +6,6 @@ docs:
6
6
  rm -r ./docs/_templates -f
7
7
  rm -r ./docs/_build -f
8
8
  sphinx-apidoc --private -o ./docs/source ./a_sync
9
+
10
+ cython:
11
+ python csetup.py build_ext --inplace
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ez-a-sync
3
- Version: 0.22.15
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
- - `aliases`, `exceptions`, `iter`, `task`: Core modules of the library.
12
- - `ASyncGenericBase`, `ASyncGenericSingleton`, `a_sync`: Base classes and decorators for dual-context execution.
13
- - `apply_semaphore`: Function to apply semaphores to coroutines.
14
- - `ASyncCachedPropertyDescriptor`, `ASyncPropertyDescriptor`, `cached_property`, `property`: Property descriptors for async properties.
15
- - `as_completed`, `create_task`, `gather`: Enhanced asyncio functions.
16
- - Executors: `AsyncThreadPoolExecutor`, `AsyncProcessPoolExecutor`, `PruningThreadPoolExecutor` for async execution.
17
- - Iterators: `ASyncFilter`, `ASyncSorter`, `ASyncIterable`, `ASyncIterator` for async iteration.
18
- - Utilities: `all`, `any`, `as_yielded` for async utilities.
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
- - `ASyncBase` is an alias for `ASyncGenericBase`, which will be removed eventually, probably in version 0.1.0.
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 task shielding and a custom task factory for creating SmartTask instances.
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, providing additional functionality
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
- Returns:
129
- True if self has more waiters than other.
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, providing additional functionality
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
- It includes various type aliases, protocols, and TypedDicts used throughout the library
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