ez-a-sync 0.22.16__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 (118) hide show
  1. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/.github/workflows/pytest.yaml +5 -3
  2. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/.github/workflows/release.yaml +2 -2
  3. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/.gitignore +5 -1
  4. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/Makefile +3 -0
  5. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/PKG-INFO +2 -1
  6. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/ENVIRONMENT_VARIABLES.py +1 -1
  7. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/__init__.py +8 -10
  8. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/_smart.py +57 -4
  9. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/_typing.py +9 -2
  10. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/_descriptor.py +42 -79
  11. ez_a_sync-0.23.0/a_sync/a_sync/_flags.c +7452 -0
  12. ez_a_sync-0.23.0/a_sync/a_sync/_flags.pyi +61 -0
  13. ez_a_sync-0.22.16/a_sync/a_sync/_flags.py → ez_a_sync-0.23.0/a_sync/a_sync/_flags.pyx +30 -15
  14. ez_a_sync-0.23.0/a_sync/a_sync/_kwargs.c +7900 -0
  15. ez_a_sync-0.23.0/a_sync/a_sync/_kwargs.pyi +52 -0
  16. ez_a_sync-0.22.16/a_sync/a_sync/_kwargs.py → ez_a_sync-0.23.0/a_sync/a_sync/_kwargs.pyx +3 -3
  17. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/base.py +1 -1
  18. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/config.py +41 -13
  19. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/decorator.py +4 -0
  20. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/function.py +6 -5
  21. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/method.py +5 -0
  22. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/manager.py +85 -18
  23. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/semaphores.py +1 -1
  24. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/property.py +5 -0
  25. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/singleton.py +5 -3
  26. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/asyncio/__init__.py +8 -3
  27. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/asyncio/as_completed.py +4 -4
  28. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/asyncio/create_task.py +4 -7
  29. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/exceptions.py +15 -2
  30. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/executor.py +56 -18
  31. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/future.py +24 -6
  32. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/iter.py +50 -9
  33. ez_a_sync-0.23.0/a_sync/primitives/__init__.py +53 -0
  34. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/primitives/_debug.py +1 -1
  35. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/primitives/_loggable.py +5 -2
  36. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/primitives/locks/counter.py +5 -3
  37. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/primitives/locks/prio_semaphore.py +8 -2
  38. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/primitives/locks/semaphore.py +6 -1
  39. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/task.py +2 -2
  40. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/conf.py +5 -0
  41. ez_a_sync-0.23.0/docs/index.rst +48 -0
  42. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/PKG-INFO +2 -1
  43. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/SOURCES.txt +7 -2
  44. ez_a_sync-0.23.0/ez_a_sync.egg-info/not-zip-safe +1 -0
  45. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/requires.txt +1 -0
  46. ez_a_sync-0.23.0/pyproject.yaml +5 -0
  47. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/requirements-dev.txt +2 -0
  48. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/requirements.txt +1 -0
  49. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/setup.py +5 -3
  50. ez_a_sync-0.23.0/tests/executor.py +240 -0
  51. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_executor.py +19 -6
  52. ez_a_sync-0.22.16/a_sync/primitives/__init__.py +0 -30
  53. ez_a_sync-0.22.16/docs/index.rst +0 -20
  54. ez_a_sync-0.22.16/pyproject.yaml +0 -2
  55. ez_a_sync-0.22.16/tests/executor.py +0 -252
  56. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/.coverage +0 -0
  57. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/.github/workflows/black.yaml +0 -0
  58. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/.github/workflows/codeql.yaml +0 -0
  59. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/.github/workflows/docs.yaml +0 -0
  60. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/.github/workflows/mypy.yaml +0 -0
  61. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/.sourcery.yaml +0 -0
  62. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/LICENSE.txt +0 -0
  63. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/README.md +0 -0
  64. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/TODO +0 -0
  65. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/__init__.py +0 -0
  66. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/_helpers.py +0 -0
  67. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/_meta.py +0 -0
  68. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/abstract.py +0 -0
  69. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/__init__.py +0 -0
  70. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/cache/__init__.py +0 -0
  71. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/cache/memory.py +0 -0
  72. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/a_sync/modifiers/limiter.py +0 -0
  73. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/aliases.py +0 -0
  74. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/asyncio/gather.py +0 -0
  75. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/asyncio/utils.py +0 -0
  76. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/primitives/locks/__init__.py +0 -0
  77. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/primitives/locks/event.py +0 -0
  78. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/primitives/queue.py +0 -0
  79. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/py.typed +0 -0
  80. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/sphinx/__init__.py +0 -0
  81. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/sphinx/ext.py +0 -0
  82. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/utils/__init__.py +0 -0
  83. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/a_sync/utils/iterators.py +0 -0
  84. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/Makefile +0 -0
  85. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/alabaster.css +0 -0
  86. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/basic.css +0 -0
  87. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/custom.css +0 -0
  88. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/doctools.js +0 -0
  89. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/documentation_options.js +0 -0
  90. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/file.png +0 -0
  91. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/language_data.js +0 -0
  92. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/minus.png +0 -0
  93. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/plus.png +0 -0
  94. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/pygments.css +0 -0
  95. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/searchtools.js +0 -0
  96. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/_build/html/_static/sphinx_highlight.js +0 -0
  97. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/docs/make.bat +0 -0
  98. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/dependency_links.txt +0 -0
  99. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/ez_a_sync.egg-info/top_level.txt +0 -0
  100. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/setup.cfg +0 -0
  101. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/__init__.py +0 -0
  102. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/conftest.py +0 -0
  103. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/fixtures.py +0 -0
  104. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_abstract.py +0 -0
  105. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_as_completed.py +0 -0
  106. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_base.py +0 -0
  107. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_cache.py +0 -0
  108. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_decorator.py +0 -0
  109. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_future.py +0 -0
  110. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_gather.py +0 -0
  111. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_helpers.py +0 -0
  112. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_iter.py +0 -0
  113. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_limiter.py +0 -0
  114. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_meta.py +0 -0
  115. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_modified.py +0 -0
  116. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_semaphore.py +0 -0
  117. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_singleton.py +0 -0
  118. {ez_a_sync-0.22.16 → ez_a_sync-0.23.0}/tests/test_task.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.16
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
@@ -26,7 +26,7 @@ DEBUG_MODE = envs.create_env(
26
26
  """bool: Enables debug mode on all classes.
27
27
 
28
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,
29
+ If `DEBUG_CLASS_NAME` is set to a non-empty string,
30
30
  `DEBUG_MODE` will default to `True`.
31
31
 
32
32
  Examples:
@@ -8,14 +8,14 @@ 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
- - :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.
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.
@@ -91,8 +91,6 @@ __all__ = [
91
91
  "all",
92
92
  "any",
93
93
  "as_yielded",
94
- "exhaust_iterator",
95
- "exhaust_iterators",
96
94
  "map",
97
95
  # classes
98
96
  "ASyncIterable",
@@ -29,6 +29,26 @@ class _SmartFutureMixin(Generic[T]):
29
29
  Mixin class that provides common functionality for smart futures and tasks.
30
30
 
31
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`
32
52
  """
33
53
 
34
54
  _queue: Optional["SmartProcessingQueue[Any, Any, T]"] = None
@@ -73,18 +93,22 @@ class _SmartFutureMixin(Generic[T]):
73
93
 
74
94
  @property
75
95
  def num_waiters(self: Union["SmartFuture", "SmartTask"]) -> int:
76
- # NOTE: we check .done() because the callback may not have ran yet and its very lightweight
77
96
  """
78
97
  Get the number of waiters currently awaiting the future or task.
79
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
+
80
102
  Example:
81
103
  ```python
82
104
  future = SmartFuture()
83
105
  print(future.num_waiters)
84
106
  ```
107
+
108
+ See Also:
109
+ - :meth:`_waiter_done_cleanup_callback`
85
110
  """
86
111
  if self.done():
87
- # if there are any waiters left, there won't be once the event loop runs once
88
112
  return 0
89
113
  return sum(getattr(waiter, "num_waiters", 1) or 1 for waiter in self._waiters)
90
114
 
@@ -94,10 +118,13 @@ class _SmartFutureMixin(Generic[T]):
94
118
  """
95
119
  Callback to clean up waiters when a waiter task is done.
96
120
 
97
- Removes the waiter from _waiters, and _queue._futs if applicable
121
+ Removes the waiter from _waiters, and _queue._futs if applicable.
98
122
 
99
123
  Args:
100
124
  waiter: The waiter task to clean up.
125
+
126
+ Example:
127
+ Automatically called when a waiter task completes.
101
128
  """
102
129
  if not self.done():
103
130
  self._waiters.remove(waiter)
@@ -105,6 +132,8 @@ class _SmartFutureMixin(Generic[T]):
105
132
  def _self_done_cleanup_callback(self: Union["SmartFuture", "SmartTask"]) -> None:
106
133
  """
107
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.
108
137
  """
109
138
  self._waiters.clear()
110
139
  if queue := self._queue:
@@ -125,6 +154,10 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
125
154
  future = SmartFuture()
126
155
  await future
127
156
  ```
157
+
158
+ See Also:
159
+ - :class:`_SmartFutureMixin`
160
+ - :class:`asyncio.Future`
128
161
  """
129
162
 
130
163
  _queue = None
@@ -149,6 +182,9 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
149
182
  ```python
150
183
  future = SmartFuture(queue=my_queue, key=my_key)
151
184
  ```
185
+
186
+ See Also:
187
+ - :class:`SmartProcessingQueue`
152
188
  """
153
189
  super().__init__(loop=loop)
154
190
  if queue:
@@ -175,6 +211,9 @@ class SmartFuture(_SmartFutureMixin[T], asyncio.Future):
175
211
  future2 = SmartFuture()
176
212
  print(future1 < future2)
177
213
  ```
214
+
215
+ See Also:
216
+ - :meth:`num_waiters`
178
217
  """
179
218
  return self.num_waiters > other.num_waiters
180
219
 
@@ -202,6 +241,9 @@ def create_future(
202
241
  ```python
203
242
  future = create_future(queue=my_queue, key=my_key)
204
243
  ```
244
+
245
+ See Also:
246
+ - :class:`SmartFuture`
205
247
  """
206
248
  return SmartFuture(queue=queue, key=key, loop=loop or asyncio.get_event_loop())
207
249
 
@@ -220,6 +262,10 @@ class SmartTask(_SmartFutureMixin[T], asyncio.Task):
220
262
  task = SmartTask(coro=my_coroutine())
221
263
  await task
222
264
  ```
265
+
266
+ See Also:
267
+ - :class:`_SmartFutureMixin`
268
+ - :class:`asyncio.Task`
223
269
  """
224
270
 
225
271
  def __init__(
@@ -241,6 +287,9 @@ class SmartTask(_SmartFutureMixin[T], asyncio.Task):
241
287
  ```python
242
288
  task = SmartTask(coro=my_coroutine(), name="my_task")
243
289
  ```
290
+
291
+ See Also:
292
+ - :func:`asyncio.create_task`
244
293
  """
245
294
  super().__init__(coro, loop=loop, name=name)
246
295
  self._waiters: Set["asyncio.Task[T]"] = set()
@@ -272,6 +321,7 @@ def smart_task_factory(
272
321
 
273
322
  See Also:
274
323
  - :func:`set_smart_task_factory`
324
+ - :class:`SmartTask`
275
325
  """
276
326
  return SmartTask(coro, loop=loop)
277
327
 
@@ -300,7 +350,7 @@ def set_smart_task_factory(loop: asyncio.AbstractEventLoop = None) -> None:
300
350
 
301
351
  def shield(
302
352
  arg: Awaitable[T], *, loop: Optional[asyncio.AbstractEventLoop] = None
303
- ) -> SmartFuture[T]:
353
+ ) -> Union[SmartFuture[T], asyncio.Future]:
304
354
  """
305
355
  Wait for a future, shielding it from cancellation.
306
356
 
@@ -331,6 +381,9 @@ def shield(
331
381
  arg: The awaitable to shield from cancellation.
332
382
  loop: Optional; the event loop. Deprecated since Python 3.8.
333
383
 
384
+ Returns:
385
+ A :class:`SmartFuture` or :class:`asyncio.Future` instance.
386
+
334
387
  Example:
335
388
  Using shield to protect a coroutine from cancellation:
336
389
 
@@ -30,10 +30,14 @@ Examples:
30
30
  asyncio.run(main())
31
31
  ```
32
32
 
33
- Example of defining a coroutine function type:
33
+ Example of defining a coroutine function type using `CoroFn` with `ParamSpec`:
34
34
 
35
35
  ```python
36
36
  from a_sync._typing import CoroFn
37
+ from typing_extensions import ParamSpec
38
+ from typing import Awaitable
39
+
40
+ P = ParamSpec("P")
37
41
 
38
42
  async def async_function(x: int) -> str:
39
43
  return str(x)
@@ -41,10 +45,13 @@ Examples:
41
45
  coro_fn: CoroFn[[int], str] = async_function
42
46
  ```
43
47
 
44
- Example of defining a synchronous function type:
48
+ Example of defining a synchronous function type using `SyncFn` with `ParamSpec`:
45
49
 
46
50
  ```python
47
51
  from a_sync._typing import SyncFn
52
+ from typing_extensions import ParamSpec
53
+
54
+ P = ParamSpec("P")
48
55
 
49
56
  def sync_function(x: int) -> str:
50
57
  return str(x)
@@ -2,13 +2,15 @@
2
2
  This module contains the :class:`ASyncDescriptor` class, which is used to create dual-function sync/async methods
3
3
  and properties.
4
4
 
5
- The :class:`ASyncDescriptor` class provides functionality for mapping operations across multiple instances
6
- and includes utility methods for common operations such as checking if all or any results are truthy,
7
- and finding the minimum, maximum, or sum of results of the method or property mapped across multiple instances.
5
+ The :class:`ASyncDescriptor` class provides a base for creating descriptors that can handle both synchronous and asynchronous
6
+ operations. It includes utility methods for mapping operations across multiple instances and provides access to common
7
+ operations such as checking if all or any results are truthy, and finding the minimum, maximum, or sum of results of the
8
+ method or property mapped across multiple instances through the use of :class:`~a_sync.a_sync.function.ASyncFunction`.
8
9
 
9
10
  See Also:
10
11
  - :class:`~a_sync.a_sync.function.ASyncFunction`
11
12
  - :class:`~a_sync.a_sync.method.ASyncMethodDescriptor`
13
+ - :class:`~a_sync.a_sync.property.ASyncPropertyDescriptor`
12
14
  """
13
15
 
14
16
  import functools
@@ -28,7 +30,7 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
28
30
  This class provides functionality for mapping operations across multiple instances
29
31
  and includes utility methods for common operations such as checking if all or any
30
32
  results are truthy, and finding the minimum, maximum, or sum of results of the method
31
- or property mapped across multiple instances.
33
+ or property mapped across multiple instances through the use of :class:`~a_sync.a_sync.function.ASyncFunction`.
32
34
 
33
35
  Examples:
34
36
  To create a dual-function method or property, subclass :class:`ASyncDescriptor` and implement
@@ -36,12 +38,10 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
36
38
  across multiple instances.
37
39
 
38
40
  ```python
39
- class MyDescriptor(ASyncDescriptor):
40
- def __init__(self, func):
41
- super().__init__(func)
42
-
43
41
  class MyClass:
44
- my_method = MyDescriptor(lambda x: x * 2)
42
+ @ASyncDescriptor
43
+ def my_method(self, x):
44
+ return x * 2
45
45
 
46
46
  instance = MyClass()
47
47
  result = instance.my_method.map([1, 2, 3])
@@ -119,12 +119,10 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
119
119
  A :class:`TaskMapping` object.
120
120
 
121
121
  Examples:
122
- class MyDescriptor(ASyncDescriptor):
123
- def __init__(self, func):
124
- super().__init__(func)
125
-
126
122
  class MyClass:
127
- my_method = MyDescriptor(lambda x: x * 2)
123
+ @ASyncDescriptor
124
+ def my_method(self, x):
125
+ return x * 2
128
126
 
129
127
  instance = MyClass()
130
128
  result = instance.my_method.map([1, 2, 3])
@@ -142,12 +140,10 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
142
140
  An :class:`ASyncFunction` object.
143
141
 
144
142
  Examples:
145
- class MyDescriptor(ASyncDescriptor):
146
- def __init__(self, func):
147
- super().__init__(func)
148
-
149
143
  class MyClass:
150
- my_method = MyDescriptor(lambda x: x > 0)
144
+ @ASyncDescriptor
145
+ def my_method(self, x):
146
+ return x > 0
151
147
 
152
148
  instance = MyClass()
153
149
  result = await instance.my_method.all([1, 2, 3])
@@ -163,12 +159,10 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
163
159
  An :class:`ASyncFunction` object.
164
160
 
165
161
  Examples:
166
- class MyDescriptor(ASyncDescriptor):
167
- def __init__(self, func):
168
- super().__init__(func)
169
-
170
162
  class MyClass:
171
- my_method = MyDescriptor(lambda x: x > 0)
163
+ @ASyncDescriptor
164
+ def my_method(self, x):
165
+ return x > 0
172
166
 
173
167
  instance = MyClass()
174
168
  result = await instance.my_method.any([-1, 0, 1])
@@ -185,12 +179,10 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
185
179
 
186
180
  Examples:
187
181
  ```python
188
- class MyDescriptor(ASyncDescriptor):
189
- def __init__(self, func):
190
- super().__init__(func)
191
-
192
182
  class MyClass:
193
- my_method = MyDescriptor(lambda x: x)
183
+ @ASyncDescriptor
184
+ def my_method(self, x):
185
+ return x
194
186
 
195
187
  instance = MyClass()
196
188
  result = await instance.my_method.min([3, 1, 2])
@@ -207,12 +199,10 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
207
199
  An :class:`ASyncFunction` object.
208
200
 
209
201
  Examples:
210
- class MyDescriptor(ASyncDescriptor):
211
- def __init__(self, func):
212
- super().__init__(func)
213
-
214
202
  class MyClass:
215
- my_method = MyDescriptor(lambda x: x)
203
+ @ASyncDescriptor
204
+ def my_method(self, x):
205
+ return x
216
206
 
217
207
  instance = MyClass()
218
208
  result = await instance.my_method.max([3, 1, 2])
@@ -229,12 +219,10 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
229
219
 
230
220
  Examples:
231
221
  ```python
232
- class MyDescriptor(ASyncDescriptor):
233
- def __init__(self, func):
234
- super().__init__(func)
235
-
236
222
  class MyClass:
237
- my_method = MyDescriptor(lambda x: x)
223
+ @ASyncDescriptor
224
+ def my_method(self, x):
225
+ return x
238
226
 
239
227
  instance = MyClass()
240
228
  result = await instance.my_method.sum([1, 2, 3])
@@ -258,17 +246,12 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
258
246
  name: Optional name for the task.
259
247
  **kwargs: Additional keyword arguments.
260
248
 
261
- Returns:
262
- A boolean indicating if all results are truthy.
263
-
264
249
  Examples:
265
250
  ```python
266
- class MyDescriptor(ASyncDescriptor):
267
- def __init__(self, func):
268
- super().__init__(func)
269
-
270
251
  class MyClass:
271
- my_method = MyDescriptor(lambda x: x > 0)
252
+ @ASyncDescriptor
253
+ def my_method(self, x):
254
+ return x > 0
272
255
 
273
256
  instance = MyClass()
274
257
  result = await instance.my_method._all([1, 2, 3])
@@ -294,17 +277,12 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
294
277
  name: Optional name for the task.
295
278
  **kwargs: Additional keyword arguments.
296
279
 
297
- Returns:
298
- A boolean indicating if any result is truthy.
299
-
300
280
  Examples:
301
281
  ```python
302
- class MyDescriptor(ASyncDescriptor):
303
- def __init__(self, func):
304
- super().__init__(func)
305
-
306
282
  class MyClass:
307
- my_method = MyDescriptor(lambda x: x > 0)
283
+ @ASyncDescriptor
284
+ def my_method(self, x):
285
+ return x > 0
308
286
 
309
287
  instance = MyClass()
310
288
  result = await instance.my_method._any([-1, 0, 1])
@@ -330,17 +308,12 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
330
308
  name: Optional name for the task.
331
309
  **kwargs: Additional keyword arguments.
332
310
 
333
- Returns:
334
- The minimum result.
335
-
336
311
  Examples:
337
312
  ```python
338
- class MyDescriptor(ASyncDescriptor):
339
- def __init__(self, func):
340
- super().__init__(func)
341
-
342
313
  class MyClass:
343
- my_method = MyDescriptor(lambda x: x)
314
+ @ASyncDescriptor
315
+ def my_method(self, x):
316
+ return x
344
317
 
345
318
  instance = MyClass()
346
319
  result = await instance.my_method._min([3, 1, 2])
@@ -366,17 +339,12 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
366
339
  name: Optional name for the task.
367
340
  **kwargs: Additional keyword arguments.
368
341
 
369
- Returns:
370
- The maximum result.
371
-
372
342
  Examples:
373
343
  ```python
374
- class MyDescriptor(ASyncDescriptor):
375
- def __init__(self, func):
376
- super().__init__(func)
377
-
378
344
  class MyClass:
379
- my_method = MyDescriptor(lambda x: x)
345
+ @ASyncDescriptor
346
+ def my_method(self, x):
347
+ return x
380
348
 
381
349
  instance = MyClass()
382
350
  result = await instance.my_method._max([3, 1, 2])
@@ -402,17 +370,12 @@ class ASyncDescriptor(_ModifiedMixin, Generic[I, P, T]):
402
370
  name: Optional name for the task.
403
371
  **kwargs: Additional keyword arguments.
404
372
 
405
- Returns:
406
- The sum of the results.
407
-
408
373
  Examples:
409
374
  ```python
410
- class MyDescriptor(ASyncDescriptor):
411
- def __init__(self, func):
412
- super().__init__(func)
413
-
414
375
  class MyClass:
415
- my_method = MyDescriptor(lambda x: x)
376
+ @ASyncDescriptor
377
+ def my_method(self, x):
378
+ return x
416
379
 
417
380
  instance = MyClass()
418
381
  result = await instance.my_method._sum([1, 2, 3])